Move tag handling out into graph.Tagger

This commit is contained in:
kortschak 2014-07-30 10:15:22 +09:30
parent 0238332ca3
commit 1604dca737
28 changed files with 315 additions and 159 deletions

View file

@ -24,18 +24,46 @@ import (
"github.com/barakmich/glog" "github.com/barakmich/glog"
) )
type Tagger struct {
tags []string
fixedTags map[string]Value
}
// Adds a tag to the iterator.
func (t *Tagger) Add(tag string) {
t.tags = append(t.tags, tag)
}
func (t *Tagger) AddFixed(tag string, value Value) {
if t.fixedTags == nil {
t.fixedTags = make(map[string]Value)
}
t.fixedTags[tag] = value
}
// Returns the tags. The returned value must not be mutated.
func (t *Tagger) Tags() []string {
return t.tags
}
// Returns the fixed tags. The returned value must not be mutated.
func (t *Tagger) Fixed() map[string]Value {
return t.fixedTags
}
func (t *Tagger) CopyFrom(src Iterator) {
for _, tag := range src.Tagger().Tags() {
t.Add(tag)
}
for k, v := range src.Tagger().Fixed() {
t.AddFixed(k, v)
}
}
type Iterator interface { type Iterator interface {
// Tags are the way we handle results. By adding a tag to an iterator, we can Tagger() *Tagger
// "name" it, in a sense, and at each step of iteration, get a named result.
// TagResults() is therefore the handy way of walking an iterator tree and
// getting the named results.
//
// Tag Accessors.
AddTag(string)
Tags() []string
AddFixedTag(string, Value)
FixedTags() map[string]Value
CopyTagsFrom(Iterator)
// Fills a tag-to-result-value map. // Fills a tag-to-result-value map.
TagResults(map[string]Value) TagResults(map[string]Value)

View file

@ -32,6 +32,7 @@ import (
// An All iterator across a range of int64 values, from `max` to `min`. // An All iterator across a range of int64 values, from `max` to `min`.
type Int64 struct { type Int64 struct {
Base Base
tags graph.Tagger
max, min int64 max, min int64
at int64 at int64
} }
@ -55,13 +56,28 @@ func (it *Int64) Close() {}
func (it *Int64) Clone() graph.Iterator { func (it *Int64) Clone() graph.Iterator {
out := NewInt64(it.min, it.max) out := NewInt64(it.min, it.max)
out.CopyTagsFrom(it) out.tags.CopyFrom(it)
return out return out
} }
func (it *Int64) Tagger() *graph.Tagger {
return &it.tags
}
// Fill the map based on the tags assigned to this iterator.
func (it *Int64) TagResults(dst map[string]graph.Value) {
for _, tag := range it.tags.Tags() {
dst[tag] = it.Result()
}
for tag, value := range it.tags.Fixed() {
dst[tag] = value
}
}
// Prints the All iterator as just an "all". // Prints the All iterator as just an "all".
func (it *Int64) DebugString(indent int) string { func (it *Int64) DebugString(indent int) string {
return fmt.Sprintf("%s(%s tags: %v)", strings.Repeat(" ", indent), it.Type(), it.Tags()) return fmt.Sprintf("%s(%s tags: %v)", strings.Repeat(" ", indent), it.Type(), it.tags.Tags())
} }
// Next() on an Int64 all iterator is a simple incrementing counter. // Next() on an Int64 all iterator is a simple incrementing counter.

View file

@ -26,6 +26,7 @@ import (
// be Next()ed if next is called. // be Next()ed if next is called.
type And struct { type And struct {
Base Base
tags graph.Tagger
internalIterators []graph.Iterator internalIterators []graph.Iterator
itCount int itCount int
primaryIt graph.Iterator primaryIt graph.Iterator
@ -50,10 +51,33 @@ func (it *And) Reset() {
it.checkList = nil it.checkList = nil
} }
func (it *And) Tagger() *graph.Tagger {
return &it.tags
}
// Overrides Base TagResults, as it needs to add it's own results and
// recurse down it's subiterators.
func (it *And) TagResults(dst map[string]graph.Value) {
for _, tag := range it.tags.Tags() {
dst[tag] = it.Result()
}
for tag, value := range it.tags.Fixed() {
dst[tag] = value
}
if it.primaryIt != nil {
it.primaryIt.TagResults(dst)
}
for _, sub := range it.internalIterators {
sub.TagResults(dst)
}
}
func (it *And) Clone() graph.Iterator { func (it *And) Clone() graph.Iterator {
and := NewAnd() and := NewAnd()
and.AddSubIterator(it.primaryIt.Clone()) and.AddSubIterator(it.primaryIt.Clone())
and.CopyTagsFrom(it) and.tags.CopyFrom(it)
for _, sub := range it.internalIterators { for _, sub := range it.internalIterators {
and.AddSubIterator(sub.Clone()) and.AddSubIterator(sub.Clone())
} }
@ -71,18 +95,6 @@ func (it *And) SubIterators() []graph.Iterator {
return iters return iters
} }
// Overrides Base TagResults, as it needs to add it's own results and
// recurse down it's subiterators.
func (it *And) TagResults(dst map[string]graph.Value) {
it.Base.TagResults(dst)
if it.primaryIt != nil {
it.primaryIt.TagResults(dst)
}
for _, sub := range it.internalIterators {
sub.TagResults(dst)
}
}
// DEPRECATED Returns the ResultTree for this iterator, recurses to it's subiterators. // DEPRECATED Returns the ResultTree for this iterator, recurses to it's subiterators.
func (it *And) ResultTree() *graph.ResultTree { func (it *And) ResultTree() *graph.ResultTree {
tree := graph.NewResultTree(it.Result()) tree := graph.NewResultTree(it.Result())
@ -101,7 +113,7 @@ func (it *And) DebugString(indent int) string {
total += fmt.Sprintf("%d:\n%s\n", i, sub.DebugString(indent+4)) total += fmt.Sprintf("%d:\n%s\n", i, sub.DebugString(indent+4))
} }
var tags string var tags string
for _, k := range it.Tags() { for _, k := range it.tags.Tags() {
tags += fmt.Sprintf("%s;", k) tags += fmt.Sprintf("%s;", k)
} }
spaces := strings.Repeat(" ", indent+2) spaces := strings.Repeat(" ", indent+2)

View file

@ -82,7 +82,7 @@ func (it *And) Optimize() (graph.Iterator, bool) {
} }
// Move the tags hanging on us (like any good replacement). // Move the tags hanging on us (like any good replacement).
newAnd.CopyTagsFrom(it) newAnd.tags.CopyFrom(it)
newAnd.optimizeCheck() newAnd.optimizeCheck()
@ -213,11 +213,11 @@ func (it *And) optimizeCheck() {
func (it *And) getSubTags() map[string]struct{} { func (it *And) getSubTags() map[string]struct{} {
tags := make(map[string]struct{}) tags := make(map[string]struct{})
for _, sub := range it.SubIterators() { for _, sub := range it.SubIterators() {
for _, tag := range sub.Tags() { for _, tag := range sub.Tagger().Tags() {
tags[tag] = struct{}{} tags[tag] = struct{}{}
} }
} }
for _, tag := range it.Tags() { for _, tag := range it.tags.Tags() {
tags[tag] = struct{}{} tags[tag] = struct{}{}
} }
return tags return tags
@ -227,13 +227,14 @@ func (it *And) getSubTags() map[string]struct{} {
// src itself, and moves them to dst. // src itself, and moves them to dst.
func moveTagsTo(dst graph.Iterator, src *And) { func moveTagsTo(dst graph.Iterator, src *And) {
tags := src.getSubTags() tags := src.getSubTags()
for _, tag := range dst.Tags() { for _, tag := range dst.Tagger().Tags() {
if _, ok := tags[tag]; ok { if _, ok := tags[tag]; ok {
delete(tags, tag) delete(tags, tag)
} }
} }
dt := dst.Tagger()
for k := range tags { for k := range tags {
dst.AddTag(k) dt.Add(k)
} }
} }

View file

@ -32,9 +32,9 @@ func TestIteratorPromotion(t *testing.T) {
a := NewAnd() a := NewAnd()
a.AddSubIterator(all) a.AddSubIterator(all)
a.AddSubIterator(fixed) a.AddSubIterator(fixed)
all.AddTag("a") all.Tagger().Add("a")
fixed.AddTag("b") fixed.Tagger().Add("b")
a.AddTag("c") a.Tagger().Add("c")
newIt, changed := a.Optimize() newIt, changed := a.Optimize()
if !changed { if !changed {
t.Error("Iterator didn't optimize") t.Error("Iterator didn't optimize")
@ -43,7 +43,7 @@ func TestIteratorPromotion(t *testing.T) {
t.Error("Expected fixed iterator") t.Error("Expected fixed iterator")
} }
tagsExpected := []string{"a", "b", "c"} tagsExpected := []string{"a", "b", "c"}
tags := newIt.Tags() tags := newIt.Tagger().Tags()
sort.Strings(tags) sort.Strings(tags)
if !reflect.DeepEqual(tags, tagsExpected) { if !reflect.DeepEqual(tags, tagsExpected) {
t.Fatal("Tags don't match") t.Fatal("Tags don't match")
@ -67,9 +67,9 @@ func TestNullIteratorAnd(t *testing.T) {
func TestReorderWithTag(t *testing.T) { func TestReorderWithTag(t *testing.T) {
all := NewInt64(100, 300) all := NewInt64(100, 300)
all.AddTag("good") all.Tagger().Add("good")
all2 := NewInt64(1, 30000) all2 := NewInt64(1, 30000)
all2.AddTag("slow") all2.Tagger().Add("slow")
a := NewAnd() a := NewAnd()
// Make all2 the default iterator // Make all2 the default iterator
a.AddSubIterator(all2) a.AddSubIterator(all2)
@ -82,7 +82,7 @@ func TestReorderWithTag(t *testing.T) {
expectedTags := []string{"good", "slow"} expectedTags := []string{"good", "slow"}
tagsOut := make([]string, 0) tagsOut := make([]string, 0)
for _, sub := range newIt.SubIterators() { for _, sub := range newIt.SubIterators() {
for _, x := range sub.Tags() { for _, x := range sub.Tagger().Tags() {
tagsOut = append(tagsOut, x) tagsOut = append(tagsOut, x)
} }
} }
@ -93,9 +93,9 @@ func TestReorderWithTag(t *testing.T) {
func TestAndStatistics(t *testing.T) { func TestAndStatistics(t *testing.T) {
all := NewInt64(100, 300) all := NewInt64(100, 300)
all.AddTag("good") all.Tagger().Add("good")
all2 := NewInt64(1, 30000) all2 := NewInt64(1, 30000)
all2.AddTag("slow") all2.Tagger().Add("slow")
a := NewAnd() a := NewAnd()
// Make all2 the default iterator // Make all2 the default iterator
a.AddSubIterator(all2) a.AddSubIterator(all2)

View file

@ -24,11 +24,11 @@ import (
func TestTag(t *testing.T) { func TestTag(t *testing.T) {
fix1 := newFixed() fix1 := newFixed()
fix1.Add(234) fix1.Add(234)
fix1.AddTag("foo") fix1.Tagger().Add("foo")
and := NewAnd() and := NewAnd()
and.AddSubIterator(fix1) and.AddSubIterator(fix1)
and.AddTag("bar") and.Tagger().Add("bar")
out := fix1.Tags() out := fix1.Tagger().Tags()
if len(out) != 1 { if len(out) != 1 {
t.Errorf("Expected length 1, got %d", len(out)) t.Errorf("Expected length 1, got %d", len(out))
} }

View file

@ -31,6 +31,7 @@ import (
// an equality function. // an equality function.
type Fixed struct { type Fixed struct {
Base Base
tags graph.Tagger
values []graph.Value values []graph.Value
lastIndex int lastIndex int
cmp Equality cmp Equality
@ -68,12 +69,26 @@ func (it *Fixed) Reset() {
func (it *Fixed) Close() {} func (it *Fixed) Close() {}
func (it *Fixed) Tagger() *graph.Tagger {
return &it.tags
}
func (it *Fixed) TagResults(dst map[string]graph.Value) {
for _, tag := range it.tags.Tags() {
dst[tag] = it.Result()
}
for tag, value := range it.tags.Fixed() {
dst[tag] = value
}
}
func (it *Fixed) Clone() graph.Iterator { func (it *Fixed) Clone() graph.Iterator {
out := NewFixedIteratorWithCompare(it.cmp) out := NewFixedIteratorWithCompare(it.cmp)
for _, val := range it.values { for _, val := range it.values {
out.Add(val) out.Add(val)
} }
out.CopyTagsFrom(it) out.tags.CopyFrom(it)
return out return out
} }
@ -92,7 +107,7 @@ func (it *Fixed) DebugString(indent int) string {
return fmt.Sprintf("%s(%s tags: %s Size: %d id0: %d)", return fmt.Sprintf("%s(%s tags: %s Size: %d id0: %d)",
strings.Repeat(" ", indent), strings.Repeat(" ", indent),
it.Type(), it.Type(),
it.FixedTags(), it.tags.Fixed(),
len(it.values), len(it.values),
value, value,
) )

View file

@ -47,6 +47,7 @@ import (
// and a temporary holder for the iterator generated on Check(). // and a temporary holder for the iterator generated on Check().
type HasA struct { type HasA struct {
Base Base
tags graph.Tagger
ts graph.TripleStore ts graph.TripleStore
primaryIt graph.Iterator primaryIt graph.Iterator
dir graph.Direction dir graph.Direction
@ -76,9 +77,13 @@ func (it *HasA) Reset() {
} }
} }
func (it *HasA) Tagger() *graph.Tagger {
return &it.tags
}
func (it *HasA) Clone() graph.Iterator { func (it *HasA) Clone() graph.Iterator {
out := NewHasA(it.ts, it.primaryIt.Clone(), it.dir) out := NewHasA(it.ts, it.primaryIt.Clone(), it.dir)
out.CopyTagsFrom(it) out.tags.CopyFrom(it)
return out return out
} }
@ -100,7 +105,14 @@ func (it *HasA) Optimize() (graph.Iterator, bool) {
// Pass the TagResults down the chain. // Pass the TagResults down the chain.
func (it *HasA) TagResults(dst map[string]graph.Value) { func (it *HasA) TagResults(dst map[string]graph.Value) {
it.Base.TagResults(dst) for _, tag := range it.tags.Tags() {
dst[tag] = it.Result()
}
for tag, value := range it.tags.Fixed() {
dst[tag] = value
}
it.primaryIt.TagResults(dst) it.primaryIt.TagResults(dst)
} }
@ -114,7 +126,7 @@ func (it *HasA) ResultTree() *graph.ResultTree {
// Print some information about this iterator. // Print some information about this iterator.
func (it *HasA) DebugString(indent int) string { func (it *HasA) DebugString(indent int) string {
var tags string var tags string
for _, k := range it.Tags() { for _, k := range it.tags.Tags() {
tags += fmt.Sprintf("%s;", k) tags += fmt.Sprintf("%s;", k)
} }
return fmt.Sprintf("%s(%s %d tags:%s direction:%s\n%s)", strings.Repeat(" ", indent), it.Type(), it.UID(), tags, it.dir, it.primaryIt.DebugString(indent+4)) return fmt.Sprintf("%s(%s %d tags:%s direction:%s\n%s)", strings.Repeat(" ", indent), it.Type(), it.UID(), tags, it.dir, it.primaryIt.DebugString(indent+4))

View file

@ -36,11 +36,9 @@ func NextUID() uint64 {
// The Base iterator is the iterator other iterators inherit from to get some // The Base iterator is the iterator other iterators inherit from to get some
// default functionality. // default functionality.
type Base struct { type Base struct {
Last graph.Value Last graph.Value
tags []string canNext bool
fixedTags map[string]graph.Value uid uint64
canNext bool
uid uint64
} }
// Called by subclases. // Called by subclases.
@ -56,41 +54,6 @@ func (it *Base) UID() uint64 {
return it.uid return it.uid
} }
// Adds a tag to the iterator. Most iterators don't need to override.
func (it *Base) AddTag(tag string) {
if it.tags == nil {
it.tags = make([]string, 0)
}
it.tags = append(it.tags, tag)
}
func (it *Base) AddFixedTag(tag string, value graph.Value) {
if it.fixedTags == nil {
it.fixedTags = make(map[string]graph.Value)
}
it.fixedTags[tag] = value
}
// Returns the tags.
func (it *Base) Tags() []string {
return it.tags
}
func (it *Base) FixedTags() map[string]graph.Value {
return it.fixedTags
}
func (it *Base) CopyTagsFrom(other_it graph.Iterator) {
for _, tag := range other_it.Tags() {
it.AddTag(tag)
}
for k, v := range other_it.FixedTags() {
it.AddFixedTag(k, v)
}
}
// Prints a silly debug string. Most classes override. // Prints a silly debug string. Most classes override.
func (it *Base) DebugString(indent int) string { func (it *Base) DebugString(indent int) string {
return fmt.Sprintf("%s(base)", strings.Repeat(" ", indent)) return fmt.Sprintf("%s(base)", strings.Repeat(" ", indent))
@ -140,18 +103,6 @@ func (it *Base) SubIterators() []graph.Iterator {
// Accessor // Accessor
func (it *Base) CanNext() bool { return it.canNext } func (it *Base) CanNext() bool { return it.canNext }
// Fill the map based on the tags assigned to this iterator. Default
// functionality works well for most iterators.
func (it *Base) TagResults(dst map[string]graph.Value) {
for _, tag := range it.Tags() {
dst[tag] = it.Result()
}
for tag, value := range it.FixedTags() {
dst[tag] = value
}
}
// Nothing to clean up. // Nothing to clean up.
// func (it *Base) Close() {} // func (it *Base) Close() {}
@ -164,6 +115,7 @@ func (it *Base) Reset() {}
// so it's important to give it a special iterator. // so it's important to give it a special iterator.
type Null struct { type Null struct {
Base Base
tags graph.Tagger
} }
// Fairly useless New function. // Fairly useless New function.
@ -171,6 +123,21 @@ func NewNull() *Null {
return &Null{} return &Null{}
} }
func (it *Null) Tagger() *graph.Tagger {
return &it.tags
}
// Fill the map based on the tags assigned to this iterator.
func (it *Null) TagResults(dst map[string]graph.Value) {
for _, tag := range it.tags.Tags() {
dst[tag] = it.Result()
}
for tag, value := range it.tags.Fixed() {
dst[tag] = value
}
}
func (it *Null) Clone() graph.Iterator { return NewNull() } func (it *Null) Clone() graph.Iterator { return NewNull() }
// Name the null iterator. // Name the null iterator.

View file

@ -41,6 +41,7 @@ import (
// `next_it` is the tempoarary iterator held per result in `primary_it`. // `next_it` is the tempoarary iterator held per result in `primary_it`.
type LinksTo struct { type LinksTo struct {
Base Base
tags graph.Tagger
ts graph.TripleStore ts graph.TripleStore
primaryIt graph.Iterator primaryIt graph.Iterator
dir graph.Direction dir graph.Direction
@ -67,9 +68,13 @@ func (it *LinksTo) Reset() {
it.nextIt = &Null{} it.nextIt = &Null{}
} }
func (it *LinksTo) Tagger() *graph.Tagger {
return &it.tags
}
func (it *LinksTo) Clone() graph.Iterator { func (it *LinksTo) Clone() graph.Iterator {
out := NewLinksTo(it.ts, it.primaryIt.Clone(), it.dir) out := NewLinksTo(it.ts, it.primaryIt.Clone(), it.dir)
out.CopyTagsFrom(it) out.tags.CopyFrom(it)
return out return out
} }
@ -78,7 +83,14 @@ func (it *LinksTo) Direction() graph.Direction { return it.dir }
// Tag these results, and our subiterator's results. // Tag these results, and our subiterator's results.
func (it *LinksTo) TagResults(dst map[string]graph.Value) { func (it *LinksTo) TagResults(dst map[string]graph.Value) {
it.Base.TagResults(dst) for _, tag := range it.tags.Tags() {
dst[tag] = it.Result()
}
for tag, value := range it.tags.Fixed() {
dst[tag] = value
}
it.primaryIt.TagResults(dst) it.primaryIt.TagResults(dst)
} }

View file

@ -39,6 +39,7 @@ import (
// and whether the last check we received was true or false. // and whether the last check we received was true or false.
type Optional struct { type Optional struct {
Base Base
tags graph.Tagger
subIt graph.Iterator subIt graph.Iterator
lastCheck bool lastCheck bool
} }
@ -61,9 +62,13 @@ func (it *Optional) Close() {
it.subIt.Close() it.subIt.Close()
} }
func (it *Optional) Tagger() *graph.Tagger {
return &it.tags
}
func (it *Optional) Clone() graph.Iterator { func (it *Optional) Clone() graph.Iterator {
out := NewOptional(it.subIt.Clone()) out := NewOptional(it.subIt.Clone())
out.CopyTagsFrom(it) out.tags.CopyFrom(it)
return out return out
} }
@ -111,7 +116,7 @@ func (it *Optional) DebugString(indent int) string {
return fmt.Sprintf("%s(%s tags:%s\n%s)", return fmt.Sprintf("%s(%s tags:%s\n%s)",
strings.Repeat(" ", indent), strings.Repeat(" ", indent),
it.Type(), it.Type(),
it.Tags(), it.tags.Tags(),
it.subIt.DebugString(indent+4)) it.subIt.DebugString(indent+4))
} }

View file

@ -30,6 +30,7 @@ import (
type Or struct { type Or struct {
Base Base
tags graph.Tagger
isShortCircuiting bool isShortCircuiting bool
internalIterators []graph.Iterator internalIterators []graph.Iterator
itCount int itCount int
@ -62,6 +63,10 @@ func (it *Or) Reset() {
it.currentIterator = -1 it.currentIterator = -1
} }
func (it *Or) Tagger() *graph.Tagger {
return &it.tags
}
func (it *Or) Clone() graph.Iterator { func (it *Or) Clone() graph.Iterator {
var or *Or var or *Or
if it.isShortCircuiting { if it.isShortCircuiting {
@ -72,7 +77,7 @@ func (it *Or) Clone() graph.Iterator {
for _, sub := range it.internalIterators { for _, sub := range it.internalIterators {
or.AddSubIterator(sub.Clone()) or.AddSubIterator(sub.Clone())
} }
or.CopyTagsFrom(it) or.tags.CopyFrom(it)
return or return or
} }
@ -84,7 +89,14 @@ func (it *Or) SubIterators() []graph.Iterator {
// Overrides BaseIterator TagResults, as it needs to add it's own results and // Overrides BaseIterator TagResults, as it needs to add it's own results and
// recurse down it's subiterators. // recurse down it's subiterators.
func (it *Or) TagResults(dst map[string]graph.Value) { func (it *Or) TagResults(dst map[string]graph.Value) {
it.Base.TagResults(dst) for _, tag := range it.tags.Tags() {
dst[tag] = it.Result()
}
for tag, value := range it.tags.Fixed() {
dst[tag] = value
}
it.internalIterators[it.currentIterator].TagResults(dst) it.internalIterators[it.currentIterator].TagResults(dst)
} }
@ -105,7 +117,7 @@ func (it *Or) DebugString(indent int) string {
total += fmt.Sprintf("%d:\n%s\n", i, sub.DebugString(indent+4)) total += fmt.Sprintf("%d:\n%s\n", i, sub.DebugString(indent+4))
} }
var tags string var tags string
for _, k := range it.Tags() { for _, k := range it.tags.Tags() {
tags += fmt.Sprintf("%s;", k) tags += fmt.Sprintf("%s;", k)
} }
spaces := strings.Repeat(" ", indent+2) spaces := strings.Repeat(" ", indent+2)
@ -247,7 +259,7 @@ func (it *Or) Optimize() (graph.Iterator, bool) {
} }
// Move the tags hanging on us (like any good replacement). // Move the tags hanging on us (like any good replacement).
newOr.CopyTagsFrom(it) newOr.tags.CopyFrom(it)
// And close ourselves but not our subiterators -- some may still be alive in // And close ourselves but not our subiterators -- some may still be alive in
// the new And (they were unchanged upon calling Optimize() on them, at the // the new And (they were unchanged upon calling Optimize() on them, at the

View file

@ -107,10 +107,10 @@ func (qs *queryShape) StealNode(left *Node, right *Node) {
func (qs *queryShape) MakeNode(it graph.Iterator) *Node { func (qs *queryShape) MakeNode(it graph.Iterator) *Node {
n := Node{Id: qs.nodeId} n := Node{Id: qs.nodeId}
for _, tag := range it.Tags() { for _, tag := range it.Tagger().Tags() {
n.Tags = append(n.Tags, tag) n.Tags = append(n.Tags, tag)
} }
for k, _ := range it.FixedTags() { for k, _ := range it.Tagger().Fixed() {
n.Tags = append(n.Tags, k) n.Tags = append(n.Tags, k)
} }

View file

@ -26,7 +26,7 @@ func hasaWithTag(ts graph.TripleStore, tag string, target string) *HasA {
obj := ts.FixedIterator() obj := ts.FixedIterator()
obj.Add(ts.ValueOf(target)) obj.Add(ts.ValueOf(target))
obj.AddTag(tag) obj.Tagger().Add(tag)
and.AddSubIterator(NewLinksTo(ts, obj, graph.Object)) and.AddSubIterator(NewLinksTo(ts, obj, graph.Object))
pred := ts.FixedIterator() pred := ts.FixedIterator()
@ -48,7 +48,7 @@ func TestQueryShape(t *testing.T) {
// Given a single linkage iterator's shape. // Given a single linkage iterator's shape.
hasa := hasaWithTag(ts, "tag", "cool") hasa := hasaWithTag(ts, "tag", "cool")
hasa.AddTag("top") hasa.Tagger().Add("top")
shape := make(map[string]interface{}) shape := make(map[string]interface{})
OutputQueryShapeForIterator(hasa, ts, shape) OutputQueryShapeForIterator(hasa, ts, shape)
@ -93,11 +93,11 @@ func TestQueryShape(t *testing.T) {
andInternal := NewAnd() andInternal := NewAnd()
hasa1 := hasaWithTag(ts, "tag1", "cool") hasa1 := hasaWithTag(ts, "tag1", "cool")
hasa1.AddTag("hasa1") hasa1.Tagger().Add("hasa1")
andInternal.AddSubIterator(hasa1) andInternal.AddSubIterator(hasa1)
hasa2 := hasaWithTag(ts, "tag2", "fun") hasa2 := hasaWithTag(ts, "tag2", "fun")
hasa2.AddTag("hasa2") hasa2.Tagger().Add("hasa2")
andInternal.AddSubIterator(hasa2) andInternal.AddSubIterator(hasa2)
pred := ts.FixedIterator() pred := ts.FixedIterator()

View file

@ -47,6 +47,7 @@ const (
type Comparison struct { type Comparison struct {
Base Base
tags graph.Tagger
subIt graph.Iterator subIt graph.Iterator
op Operator op Operator
val interface{} val interface{}
@ -111,9 +112,13 @@ func (it *Comparison) Reset() {
it.subIt.Reset() it.subIt.Reset()
} }
func (it *Comparison) Tagger() *graph.Tagger {
return &it.tags
}
func (it *Comparison) Clone() graph.Iterator { func (it *Comparison) Clone() graph.Iterator {
out := NewComparison(it.subIt.Clone(), it.op, it.val, it.ts) out := NewComparison(it.subIt.Clone(), it.op, it.val, it.ts)
out.CopyTagsFrom(it) out.tags.CopyFrom(it)
return out return out
} }
@ -157,7 +162,14 @@ func (it *Comparison) Check(val graph.Value) bool {
// If we failed the check, then the subiterator should not contribute to the result // If we failed the check, then the subiterator should not contribute to the result
// set. Otherwise, go ahead and tag it. // set. Otherwise, go ahead and tag it.
func (it *Comparison) TagResults(dst map[string]graph.Value) { func (it *Comparison) TagResults(dst map[string]graph.Value) {
it.Base.TagResults(dst) for _, tag := range it.tags.Tags() {
dst[tag] = it.Result()
}
for tag, value := range it.tags.Fixed() {
dst[tag] = value
}
it.subIt.TagResults(dst) it.subIt.TagResults(dst)
} }

View file

@ -28,6 +28,7 @@ import (
type AllIterator struct { type AllIterator struct {
iterator.Base iterator.Base
tags graph.Tagger
prefix []byte prefix []byte
dir graph.Direction dir graph.Direction
open bool open bool
@ -66,9 +67,23 @@ func (it *AllIterator) Reset() {
} }
} }
func (it *AllIterator) Tagger() *graph.Tagger {
return &it.tags
}
func (it *AllIterator) TagResults(dst map[string]graph.Value) {
for _, tag := range it.tags.Tags() {
dst[tag] = it.Result()
}
for tag, value := range it.tags.Fixed() {
dst[tag] = value
}
}
func (it *AllIterator) Clone() graph.Iterator { func (it *AllIterator) Clone() graph.Iterator {
out := NewAllIterator(string(it.prefix), it.dir, it.ts) out := NewAllIterator(string(it.prefix), it.dir, it.ts)
out.CopyTagsFrom(it) out.tags.CopyFrom(it)
return out return out
} }
@ -115,7 +130,7 @@ func (it *AllIterator) Size() (int64, bool) {
func (it *AllIterator) DebugString(indent int) string { func (it *AllIterator) DebugString(indent int) string {
size, _ := it.Size() size, _ := it.Size()
return fmt.Sprintf("%s(%s tags: %v leveldb size:%d %s %p)", strings.Repeat(" ", indent), it.Type(), it.Tags(), size, it.dir, it) return fmt.Sprintf("%s(%s tags: %v leveldb size:%d %s %p)", strings.Repeat(" ", indent), it.Type(), it.tags.Tags(), size, it.dir, it)
} }
func (it *AllIterator) Type() graph.Type { return graph.All } func (it *AllIterator) Type() graph.Type { return graph.All }

View file

@ -28,6 +28,7 @@ import (
type Iterator struct { type Iterator struct {
iterator.Base iterator.Base
tags graph.Tagger
nextPrefix []byte nextPrefix []byte
checkId []byte checkId []byte
dir graph.Direction dir graph.Direction
@ -72,9 +73,23 @@ func (it *Iterator) Reset() {
} }
} }
func (it *Iterator) Tagger() *graph.Tagger {
return &it.tags
}
func (it *Iterator) TagResults(dst map[string]graph.Value) {
for _, tag := range it.tags.Tags() {
dst[tag] = it.Result()
}
for tag, value := range it.tags.Fixed() {
dst[tag] = value
}
}
func (it *Iterator) Clone() graph.Iterator { func (it *Iterator) Clone() graph.Iterator {
out := NewIterator(it.originalPrefix, it.dir, it.checkId, it.ts) out := NewIterator(it.originalPrefix, it.dir, it.checkId, it.ts)
out.CopyTagsFrom(it) out.tags.CopyFrom(it)
return out return out
} }
@ -192,7 +207,7 @@ func (it *Iterator) Size() (int64, bool) {
func (it *Iterator) DebugString(indent int) string { func (it *Iterator) DebugString(indent int) string {
size, _ := it.Size() size, _ := it.Size()
return fmt.Sprintf("%s(%s %d tags: %v dir: %s size:%d %s)", strings.Repeat(" ", indent), it.Type(), it.UID(), it.Tags(), it.dir, size, it.ts.NameOf(it.checkId)) return fmt.Sprintf("%s(%s %d tags: %v dir: %s size:%d %s)", strings.Repeat(" ", indent), it.Type(), it.UID(), it.tags.Tags(), it.dir, size, it.ts.NameOf(it.checkId))
} }
var levelDBType graph.Type var levelDBType graph.Type

View file

@ -415,7 +415,7 @@ func TestOptimize(t *testing.T) {
// With an linksto-fixed pair // With an linksto-fixed pair
fixed := ts.FixedIterator() fixed := ts.FixedIterator()
fixed.Add(ts.ValueOf("F")) fixed.Add(ts.ValueOf("F"))
fixed.AddTag("internal") fixed.Tagger().Add("internal")
lto := iterator.NewLinksTo(ts, fixed, graph.Object) lto := iterator.NewLinksTo(ts, fixed, graph.Object)
oldIt := lto.Clone() oldIt := lto.Clone()

View file

@ -42,9 +42,10 @@ func (ts *TripleStore) optimizeLinksTo(it *iterator.LinksTo) (graph.Iterator, bo
panic("Sizes lie") panic("Sizes lie")
} }
newIt := ts.TripleIterator(it.Direction(), val) newIt := ts.TripleIterator(it.Direction(), val)
newIt.CopyTagsFrom(it) nt := newIt.Tagger()
for _, tag := range primary.Tags() { nt.CopyFrom(it)
newIt.AddFixedTag(tag, val) for _, tag := range primary.Tagger().Tags() {
nt.AddFixed(tag, val)
} }
it.Close() it.Close()
return newIt, true return newIt, true

View file

@ -27,6 +27,7 @@ import (
type Iterator struct { type Iterator struct {
iterator.Base iterator.Base
tags graph.Tagger
tree *llrb.LLRB tree *llrb.LLRB
data string data string
isRunning bool isRunning bool
@ -65,10 +66,24 @@ func (it *Iterator) Reset() {
it.iterLast = Int64(-1) it.iterLast = Int64(-1)
} }
func (it *Iterator) Tagger() *graph.Tagger {
return &it.tags
}
func (it *Iterator) TagResults(dst map[string]graph.Value) {
for _, tag := range it.tags.Tags() {
dst[tag] = it.Result()
}
for tag, value := range it.tags.Fixed() {
dst[tag] = value
}
}
func (it *Iterator) Clone() graph.Iterator { func (it *Iterator) Clone() graph.Iterator {
var new_it = NewLlrbIterator(it.tree, it.data) m := NewLlrbIterator(it.tree, it.data)
new_it.CopyTagsFrom(it) m.tags.CopyFrom(it)
return new_it return m
} }
func (it *Iterator) Close() {} func (it *Iterator) Close() {}
@ -98,7 +113,7 @@ func (it *Iterator) Check(v graph.Value) bool {
func (it *Iterator) DebugString(indent int) string { func (it *Iterator) DebugString(indent int) string {
size, _ := it.Size() size, _ := it.Size()
return fmt.Sprintf("%s(%s tags:%s size:%d %s)", strings.Repeat(" ", indent), it.Type(), it.Tags(), size, it.data) return fmt.Sprintf("%s(%s tags:%s size:%d %s)", strings.Repeat(" ", indent), it.Type(), it.tags.Tags(), size, it.data)
} }
var memType graph.Type var memType graph.Type

View file

@ -42,9 +42,10 @@ func (ts *TripleStore) optimizeLinksTo(it *iterator.LinksTo) (graph.Iterator, bo
panic("Sizes lie") panic("Sizes lie")
} }
newIt := ts.TripleIterator(it.Direction(), val) newIt := ts.TripleIterator(it.Direction(), val)
newIt.CopyTagsFrom(it) nt := newIt.Tagger()
for _, tag := range primary.Tags() { nt.CopyFrom(it)
newIt.AddFixedTag(tag, val) for _, tag := range primary.Tagger().Tags() {
nt.AddFixed(tag, val)
} }
return newIt, true return newIt, true
} }

View file

@ -150,7 +150,7 @@ func TestLinksToOptimization(t *testing.T) {
fixed.Add(ts.ValueOf("cool")) fixed.Add(ts.ValueOf("cool"))
lto := iterator.NewLinksTo(ts, fixed, graph.Object) lto := iterator.NewLinksTo(ts, fixed, graph.Object)
lto.AddTag("foo") lto.Tagger().Add("foo")
newIt, changed := lto.Optimize() newIt, changed := lto.Optimize()
if !changed { if !changed {
@ -165,7 +165,8 @@ func TestLinksToOptimization(t *testing.T) {
if v_clone.DebugString(0) != v.DebugString(0) { if v_clone.DebugString(0) != v.DebugString(0) {
t.Fatal("Wrong iterator. Got ", v_clone.DebugString(0)) t.Fatal("Wrong iterator. Got ", v_clone.DebugString(0))
} }
if len(v_clone.Tags()) < 1 || v_clone.Tags()[0] != "foo" { vt := v_clone.Tagger()
if len(vt.Tags()) < 1 || vt.Tags()[0] != "foo" {
t.Fatal("Tag on LinksTo did not persist") t.Fatal("Tag on LinksTo did not persist")
} }
} }

View file

@ -28,6 +28,7 @@ import (
type Iterator struct { type Iterator struct {
iterator.Base iterator.Base
tags graph.Tagger
ts *TripleStore ts *TripleStore
dir graph.Direction dir graph.Direction
iter *mgo.Iter iter *mgo.Iter
@ -98,15 +99,29 @@ func (it *Iterator) Close() {
it.iter.Close() it.iter.Close()
} }
func (it *Iterator) Clone() graph.Iterator { func (it *Iterator) Tagger() *graph.Tagger {
var newM graph.Iterator return &it.tags
if it.isAll { }
newM = NewAllIterator(it.ts, it.collection)
} else { func (it *Iterator) TagResults(dst map[string]graph.Value) {
newM = NewIterator(it.ts, it.collection, it.dir, it.hash) for _, tag := range it.tags.Tags() {
dst[tag] = it.Result()
} }
newM.CopyTagsFrom(it)
return newM for tag, value := range it.tags.Fixed() {
dst[tag] = value
}
}
func (it *Iterator) Clone() graph.Iterator {
var m *Iterator
if it.isAll {
m = NewAllIterator(it.ts, it.collection)
} else {
m = NewIterator(it.ts, it.collection, it.dir, it.hash)
}
m.tags.CopyFrom(it)
return m
} }
func (it *Iterator) Next() (graph.Value, bool) { func (it *Iterator) Next() (graph.Value, bool) {

View file

@ -42,9 +42,10 @@ func (ts *TripleStore) optimizeLinksTo(it *iterator.LinksTo) (graph.Iterator, bo
panic("Sizes lie") panic("Sizes lie")
} }
newIt := ts.TripleIterator(it.Direction(), val) newIt := ts.TripleIterator(it.Direction(), val)
newIt.CopyTagsFrom(it) nt := newIt.Tagger()
for _, tag := range primary.Tags() { nt.CopyFrom(it)
newIt.AddFixedTag(tag, val) for _, tag := range primary.Tagger().Tags() {
nt.AddFixed(tag, val)
} }
it.Close() it.Close()
return newIt, true return newIt, true

View file

@ -189,7 +189,7 @@ func buildIteratorTree(tree *peg.ExpressionTree, ts graph.TripleStore) graph.Ite
nodeID := getIdentString(tree) nodeID := getIdentString(tree)
if tree.Children[0].Name == "Variable" { if tree.Children[0].Name == "Variable" {
allIt := ts.NodesAllIterator() allIt := ts.NodesAllIterator()
allIt.AddTag(nodeID) allIt.Tagger().Add(nodeID)
out = allIt out = allIt
} else { } else {
n := nodeID n := nodeID

View file

@ -135,7 +135,7 @@ func buildInOutIterator(obj *otto.Object, ts graph.TripleStore, base graph.Itera
tags = makeListOfStringsFromArrayValue(one.Object()) tags = makeListOfStringsFromArrayValue(one.Object())
} }
for _, tag := range tags { for _, tag := range tags {
predicateNodeIterator.AddTag(tag) predicateNodeIterator.Tagger().Add(tag)
} }
} }
@ -179,7 +179,7 @@ func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph.
case "tag": case "tag":
it = subIt it = subIt
for _, tag := range stringArgs { for _, tag := range stringArgs {
it.AddTag(tag) it.Tagger().Add(tag)
} }
case "save": case "save":
all := ts.NodesAllIterator() all := ts.NodesAllIterator()
@ -187,9 +187,9 @@ func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph.
return iterator.NewNull() return iterator.NewNull()
} }
if len(stringArgs) == 2 { if len(stringArgs) == 2 {
all.AddTag(stringArgs[1]) all.Tagger().Add(stringArgs[1])
} else { } else {
all.AddTag(stringArgs[0]) all.Tagger().Add(stringArgs[0])
} }
predFixed := ts.FixedIterator() predFixed := ts.FixedIterator()
predFixed.Add(ts.ValueOf(stringArgs[0])) predFixed.Add(ts.ValueOf(stringArgs[0]))
@ -207,9 +207,9 @@ func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph.
return iterator.NewNull() return iterator.NewNull()
} }
if len(stringArgs) == 2 { if len(stringArgs) == 2 {
all.AddTag(stringArgs[1]) all.Tagger().Add(stringArgs[1])
} else { } else {
all.AddTag(stringArgs[0]) all.Tagger().Add(stringArgs[0])
} }
predFixed := ts.FixedIterator() predFixed := ts.FixedIterator()
predFixed.Add(ts.ValueOf(stringArgs[0])) predFixed.Add(ts.ValueOf(stringArgs[0]))

View file

@ -38,7 +38,7 @@ func embedFinals(env *otto.Otto, ses *Session, obj *otto.Object) {
func allFunc(env *otto.Otto, ses *Session, obj *otto.Object) func(otto.FunctionCall) otto.Value { func allFunc(env *otto.Otto, ses *Session, obj *otto.Object) func(otto.FunctionCall) otto.Value {
return func(call otto.FunctionCall) otto.Value { return func(call otto.FunctionCall) otto.Value {
it := buildIteratorTree(obj, ses.ts) it := buildIteratorTree(obj, ses.ts)
it.AddTag(TopResultTag) it.Tagger().Add(TopResultTag)
ses.limit = -1 ses.limit = -1
ses.count = 0 ses.count = 0
runIteratorOnSession(it, ses) runIteratorOnSession(it, ses)
@ -51,7 +51,7 @@ func limitFunc(env *otto.Otto, ses *Session, obj *otto.Object) func(otto.Functio
if len(call.ArgumentList) > 0 { if len(call.ArgumentList) > 0 {
limitVal, _ := call.Argument(0).ToInteger() limitVal, _ := call.Argument(0).ToInteger()
it := buildIteratorTree(obj, ses.ts) it := buildIteratorTree(obj, ses.ts)
it.AddTag(TopResultTag) it.Tagger().Add(TopResultTag)
ses.limit = int(limitVal) ses.limit = int(limitVal)
ses.count = 0 ses.count = 0
runIteratorOnSession(it, ses) runIteratorOnSession(it, ses)
@ -63,7 +63,7 @@ func limitFunc(env *otto.Otto, ses *Session, obj *otto.Object) func(otto.Functio
func toArrayFunc(env *otto.Otto, ses *Session, obj *otto.Object, withTags bool) func(otto.FunctionCall) otto.Value { func toArrayFunc(env *otto.Otto, ses *Session, obj *otto.Object, withTags bool) func(otto.FunctionCall) otto.Value {
return func(call otto.FunctionCall) otto.Value { return func(call otto.FunctionCall) otto.Value {
it := buildIteratorTree(obj, ses.ts) it := buildIteratorTree(obj, ses.ts)
it.AddTag(TopResultTag) it.Tagger().Add(TopResultTag)
limit := -1 limit := -1
if len(call.ArgumentList) > 0 { if len(call.ArgumentList) > 0 {
limitParsed, _ := call.Argument(0).ToInteger() limitParsed, _ := call.Argument(0).ToInteger()
@ -90,7 +90,7 @@ func toArrayFunc(env *otto.Otto, ses *Session, obj *otto.Object, withTags bool)
func toValueFunc(env *otto.Otto, ses *Session, obj *otto.Object, withTags bool) func(otto.FunctionCall) otto.Value { func toValueFunc(env *otto.Otto, ses *Session, obj *otto.Object, withTags bool) func(otto.FunctionCall) otto.Value {
return func(call otto.FunctionCall) otto.Value { return func(call otto.FunctionCall) otto.Value {
it := buildIteratorTree(obj, ses.ts) it := buildIteratorTree(obj, ses.ts)
it.AddTag(TopResultTag) it.Tagger().Add(TopResultTag)
limit := 1 limit := 1
var val otto.Value var val otto.Value
var err error var err error
@ -120,7 +120,7 @@ func toValueFunc(env *otto.Otto, ses *Session, obj *otto.Object, withTags bool)
func mapFunc(env *otto.Otto, ses *Session, obj *otto.Object) func(otto.FunctionCall) otto.Value { func mapFunc(env *otto.Otto, ses *Session, obj *otto.Object) func(otto.FunctionCall) otto.Value {
return func(call otto.FunctionCall) otto.Value { return func(call otto.FunctionCall) otto.Value {
it := buildIteratorTree(obj, ses.ts) it := buildIteratorTree(obj, ses.ts)
it.AddTag(TopResultTag) it.Tagger().Add(TopResultTag)
limit := -1 limit := -1
if len(call.ArgumentList) == 0 { if len(call.ArgumentList) == 0 {
return otto.NullValue() return otto.NullValue()

View file

@ -33,7 +33,7 @@ func (q *Query) buildFixed(s string) graph.Iterator {
func (q *Query) buildResultIterator(path Path) graph.Iterator { func (q *Query) buildResultIterator(path Path) graph.Iterator {
all := q.ses.ts.NodesAllIterator() all := q.ses.ts.NodesAllIterator()
all.AddTag(string(path)) all.Tagger().Add(string(path))
return all return all
} }
@ -97,7 +97,7 @@ func (q *Query) buildIteratorTreeInternal(query interface{}, path Path) (it grap
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
it.AddTag(string(path)) it.Tagger().Add(string(path))
return it, optional, nil return it, optional, nil
} }