diff --git a/graph/iterator.go b/graph/iterator.go index 27a6f02..d28f43e 100644 --- a/graph/iterator.go +++ b/graph/iterator.go @@ -14,8 +14,7 @@ package graph -// Define the general iterator interface, as well as the Base iterator which all -// iterators can "inherit" from to get default iterator functionality. +// Define the general iterator interface. import ( "strings" @@ -24,18 +23,46 @@ import ( "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 { - // Tags are the way we handle results. By adding a tag to an iterator, we can - // "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) + Tagger() *Tagger // Fills a tag-to-result-value map. TagResults(map[string]Value) @@ -58,19 +85,10 @@ type Iterator interface { // All of them should set iterator.Last to be the last returned value, to // make results work. // - // Next() advances the iterator and returns the next valid result. Returns - // (, true) or (nil, false) - Next() (Value, bool) - // NextResult() advances iterators that may have more than one valid result, // from the bottom up. NextResult() bool - // Return whether this iterator is reliably nextable. Most iterators are. - // However, some iterators, like "not" are, by definition, the whole database - // except themselves. Next() on these is unproductive, if impossible. - CanNext() bool - // Check(), given a value, returns whether or not that value is within the set // held by this iterator. Check(Value) bool @@ -114,7 +132,26 @@ type Iterator interface { Close() // UID returns the unique identifier of the iterator. - UID() uintptr + UID() uint64 +} + +type Nexter interface { + // Next() advances the iterator and returns the next valid result. Returns + // (, true) or (nil, false) + Next() (Value, bool) + + Iterator +} + +// Next is a convenience function that conditionally calls the Next method +// of an Iterator if it is a Nexter. If the Iterator is not a Nexter, Next +// return a nil Value and false. +func Next(it Iterator) (Value, bool) { + if n, ok := it.(Nexter); ok { + return n.Next() + } + glog.Errorln("Nexting an un-nextable iterator") + return nil, false } // FixedIterator wraps iterators that are modifiable by addition of fixed value sets. diff --git a/graph/iterator/all_iterator.go b/graph/iterator/all_iterator.go index 22e0d1b..ff1a869 100644 --- a/graph/iterator/all_iterator.go +++ b/graph/iterator/all_iterator.go @@ -31,19 +31,25 @@ import ( // An All iterator across a range of int64 values, from `max` to `min`. type Int64 struct { - Base + uid uint64 + tags graph.Tagger max, min int64 at int64 + result graph.Value } // Creates a new Int64 with the given range. func NewInt64(min, max int64) *Int64 { - var all Int64 - BaseInit(&all.Base) - all.max = max - all.min = min - all.at = min - return &all + return &Int64{ + uid: NextUID(), + min: min, + max: max, + at: min, + } +} + +func (it *Int64) UID() uint64 { + return it.uid } // Start back at the beginning @@ -55,13 +61,28 @@ func (it *Int64) Close() {} func (it *Int64) Clone() graph.Iterator { out := NewInt64(it.min, it.max) - out.CopyTagsFrom(it) + out.tags.CopyFrom(it) 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". 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. @@ -76,10 +97,28 @@ func (it *Int64) Next() (graph.Value, bool) { if it.at > it.max { it.at = -1 } - it.Last = val + it.result = val return graph.NextLogOut(it, val, true) } +// DEPRECATED +func (it *Int64) ResultTree() *graph.ResultTree { + return graph.NewResultTree(it.Result()) +} + +func (it *Int64) Result() graph.Value { + return it.result +} + +func (it *Int64) NextResult() bool { + return false +} + +// No sub-iterators. +func (it *Int64) SubIterators() []graph.Iterator { + return nil +} + // The number of elements in an Int64 is the size of the range. // The size is exact. func (it *Int64) Size() (int64, bool) { @@ -93,7 +132,7 @@ func (it *Int64) Check(tsv graph.Value) bool { graph.CheckLogIn(it, tsv) v := tsv.(int64) if it.min <= v && v <= it.max { - it.Last = v + it.result = v return graph.CheckLogOut(it, v, true) } return graph.CheckLogOut(it, v, false) diff --git a/graph/iterator/and_iterator.go b/graph/iterator/and_iterator.go index 819cb42..902b9a1 100644 --- a/graph/iterator/and_iterator.go +++ b/graph/iterator/and_iterator.go @@ -22,23 +22,28 @@ import ( "github.com/google/cayley/graph" ) -// The And iterator. Consists of a Base and a number of subiterators, the primary of which will +// The And iterator. Consists of a number of subiterators, the primary of which will // be Next()ed if next is called. type And struct { - Base + uid uint64 + tags graph.Tagger internalIterators []graph.Iterator itCount int primaryIt graph.Iterator checkList []graph.Iterator + result graph.Value } // Creates a new And iterator. func NewAnd() *And { - var and And - BaseInit(&and.Base) - and.internalIterators = make([]graph.Iterator, 0, 20) - and.checkList = nil - return &and + return &And{ + uid: NextUID(), + internalIterators: make([]graph.Iterator, 0, 20), + } +} + +func (it *And) UID() uint64 { + return it.uid } // Reset all internal iterators @@ -50,10 +55,33 @@ func (it *And) Reset() { it.checkList = nil } +func (it *And) Tagger() *graph.Tagger { + return &it.tags +} + +// An extended 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 { and := NewAnd() and.AddSubIterator(it.primaryIt.Clone()) - and.CopyTagsFrom(it) + and.tags.CopyFrom(it) for _, sub := range it.internalIterators { and.AddSubIterator(sub.Clone()) } @@ -71,18 +99,6 @@ func (it *And) SubIterators() []graph.Iterator { 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. func (it *And) ResultTree() *graph.ResultTree { tree := graph.NewResultTree(it.Result()) @@ -101,7 +117,7 @@ func (it *And) DebugString(indent int) string { total += fmt.Sprintf("%d:\n%s\n", i, sub.DebugString(indent+4)) } var tags string - for _, k := range it.Tags() { + for _, k := range it.tags.Tags() { tags += fmt.Sprintf("%s;", k) } spaces := strings.Repeat(" ", indent+2) @@ -144,16 +160,20 @@ func (it *And) Next() (graph.Value, bool) { var curr graph.Value var exists bool for { - curr, exists = it.primaryIt.Next() + curr, exists = graph.Next(it.primaryIt) if !exists { return graph.NextLogOut(it, nil, false) } if it.checkSubIts(curr) { - it.Last = curr + it.result = curr return graph.NextLogOut(it, curr, true) } } - panic("Somehow broke out of Next() loop in And") + panic("unreachable") +} + +func (it *And) Result() graph.Value { + return it.result } // Checks a value against the non-primary iterators, in order. @@ -177,7 +197,7 @@ func (it *And) checkCheckList(val graph.Value) bool { } } if ok { - it.Last = val + it.result = val } return graph.CheckLogOut(it, val, ok) } @@ -196,7 +216,7 @@ func (it *And) Check(val graph.Value) bool { if !othersGood { return graph.CheckLogOut(it, val, false) } - it.Last = val + it.result = val return graph.CheckLogOut(it, val, true) } diff --git a/graph/iterator/and_iterator_optimize.go b/graph/iterator/and_iterator_optimize.go index b556094..20a4771 100644 --- a/graph/iterator/and_iterator_optimize.go +++ b/graph/iterator/and_iterator_optimize.go @@ -82,7 +82,7 @@ func (it *And) Optimize() (graph.Iterator, bool) { } // Move the tags hanging on us (like any good replacement). - newAnd.CopyTagsFrom(it) + newAnd.tags.CopyFrom(it) newAnd.optimizeCheck() @@ -145,14 +145,14 @@ func optimizeOrder(its []graph.Iterator) []graph.Iterator { // all of it's contents, and to Check() each of those against everyone // else. for _, it := range its { - if !it.CanNext() { + if _, canNext := it.(graph.Nexter); !canNext { bad = append(bad, it) continue } rootStats := it.Stats() cost := rootStats.NextCost for _, f := range its { - if !f.CanNext() { + if _, canNext := it.(graph.Nexter); !canNext { continue } if f == it { @@ -177,7 +177,7 @@ func optimizeOrder(its []graph.Iterator) []graph.Iterator { // ... push everyone else after... for _, it := range its { - if !it.CanNext() { + if _, canNext := it.(graph.Nexter); !canNext { continue } if it != best { @@ -213,11 +213,11 @@ func (it *And) optimizeCheck() { func (it *And) getSubTags() map[string]struct{} { tags := make(map[string]struct{}) for _, sub := range it.SubIterators() { - for _, tag := range sub.Tags() { + for _, tag := range sub.Tagger().Tags() { tags[tag] = struct{}{} } } - for _, tag := range it.Tags() { + for _, tag := range it.tags.Tags() { tags[tag] = struct{}{} } return tags @@ -227,13 +227,14 @@ func (it *And) getSubTags() map[string]struct{} { // src itself, and moves them to dst. func moveTagsTo(dst graph.Iterator, src *And) { tags := src.getSubTags() - for _, tag := range dst.Tags() { + for _, tag := range dst.Tagger().Tags() { if _, ok := tags[tag]; ok { delete(tags, tag) } } + dt := dst.Tagger() for k := range tags { - dst.AddTag(k) + dt.Add(k) } } diff --git a/graph/iterator/and_iterator_optimize_test.go b/graph/iterator/and_iterator_optimize_test.go index e8d6a80..00b3807 100644 --- a/graph/iterator/and_iterator_optimize_test.go +++ b/graph/iterator/and_iterator_optimize_test.go @@ -32,9 +32,9 @@ func TestIteratorPromotion(t *testing.T) { a := NewAnd() a.AddSubIterator(all) a.AddSubIterator(fixed) - all.AddTag("a") - fixed.AddTag("b") - a.AddTag("c") + all.Tagger().Add("a") + fixed.Tagger().Add("b") + a.Tagger().Add("c") newIt, changed := a.Optimize() if !changed { t.Error("Iterator didn't optimize") @@ -43,7 +43,7 @@ func TestIteratorPromotion(t *testing.T) { t.Error("Expected fixed iterator") } tagsExpected := []string{"a", "b", "c"} - tags := newIt.Tags() + tags := newIt.Tagger().Tags() sort.Strings(tags) if !reflect.DeepEqual(tags, tagsExpected) { t.Fatal("Tags don't match") @@ -67,9 +67,9 @@ func TestNullIteratorAnd(t *testing.T) { func TestReorderWithTag(t *testing.T) { all := NewInt64(100, 300) - all.AddTag("good") + all.Tagger().Add("good") all2 := NewInt64(1, 30000) - all2.AddTag("slow") + all2.Tagger().Add("slow") a := NewAnd() // Make all2 the default iterator a.AddSubIterator(all2) @@ -82,7 +82,7 @@ func TestReorderWithTag(t *testing.T) { expectedTags := []string{"good", "slow"} tagsOut := make([]string, 0) for _, sub := range newIt.SubIterators() { - for _, x := range sub.Tags() { + for _, x := range sub.Tagger().Tags() { tagsOut = append(tagsOut, x) } } @@ -93,9 +93,9 @@ func TestReorderWithTag(t *testing.T) { func TestAndStatistics(t *testing.T) { all := NewInt64(100, 300) - all.AddTag("good") + all.Tagger().Add("good") all2 := NewInt64(1, 30000) - all2.AddTag("slow") + all2.Tagger().Add("slow") a := NewAnd() // Make all2 the default iterator a.AddSubIterator(all2) diff --git a/graph/iterator/and_iterator_test.go b/graph/iterator/and_iterator_test.go index 60633e1..82d290a 100644 --- a/graph/iterator/and_iterator_test.go +++ b/graph/iterator/and_iterator_test.go @@ -24,11 +24,11 @@ import ( func TestTag(t *testing.T) { fix1 := newFixed() fix1.Add(234) - fix1.AddTag("foo") + fix1.Tagger().Add("foo") and := NewAnd() and.AddSubIterator(fix1) - and.AddTag("bar") - out := fix1.Tags() + and.Tagger().Add("bar") + out := fix1.Tagger().Tags() if len(out) != 1 { t.Errorf("Expected length 1, got %d", len(out)) } diff --git a/graph/iterator/fixed_iterator.go b/graph/iterator/fixed_iterator.go index c69869b..6bfebb5 100644 --- a/graph/iterator/fixed_iterator.go +++ b/graph/iterator/fixed_iterator.go @@ -30,10 +30,12 @@ import ( // A Fixed iterator consists of it's values, an index (where it is in the process of Next()ing) and // an equality function. type Fixed struct { - Base + uid uint64 + tags graph.Tagger values []graph.Value lastIndex int cmp Equality + result graph.Value } // Define the signature of an equality function. @@ -54,12 +56,15 @@ func newFixed() *Fixed { // Creates a new Fixed iterator with a custom comparitor. func NewFixedIteratorWithCompare(compareFn Equality) *Fixed { - var it Fixed - BaseInit(&it.Base) - it.values = make([]graph.Value, 0, 20) - it.lastIndex = 0 - it.cmp = compareFn - return &it + return &Fixed{ + uid: NextUID(), + values: make([]graph.Value, 0, 20), + cmp: compareFn, + } +} + +func (it *Fixed) UID() uint64 { + return it.uid } func (it *Fixed) Reset() { @@ -68,12 +73,26 @@ func (it *Fixed) Reset() { 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 { out := NewFixedIteratorWithCompare(it.cmp) for _, val := range it.values { out.Add(val) } - out.CopyTagsFrom(it) + out.tags.CopyFrom(it) return out } @@ -92,7 +111,7 @@ func (it *Fixed) DebugString(indent int) string { return fmt.Sprintf("%s(%s tags: %s Size: %d id0: %d)", strings.Repeat(" ", indent), it.Type(), - it.FixedTags(), + it.tags.Fixed(), len(it.values), value, ) @@ -109,7 +128,7 @@ func (it *Fixed) Check(v graph.Value) bool { graph.CheckLogIn(it, v) for _, x := range it.values { if it.cmp(x, v) { - it.Last = x + it.result = x return graph.CheckLogOut(it, v, true) } } @@ -123,11 +142,29 @@ func (it *Fixed) Next() (graph.Value, bool) { return graph.NextLogOut(it, nil, false) } out := it.values[it.lastIndex] - it.Last = out + it.result = out it.lastIndex++ return graph.NextLogOut(it, out, true) } +// DEPRECATED +func (it *Fixed) ResultTree() *graph.ResultTree { + return graph.NewResultTree(it.Result()) +} + +func (it *Fixed) Result() graph.Value { + return it.result +} + +func (it *Fixed) NextResult() bool { + return false +} + +// No sub-iterators. +func (it *Fixed) SubIterators() []graph.Iterator { + return nil +} + // Optimize() for a Fixed iterator is simple. Returns a Null iterator if it's empty // (so that other iterators upstream can treat this as null) or there is no // optimization. diff --git a/graph/iterator/hasa_iterator.go b/graph/iterator/hasa_iterator.go index 805a066..2a0b46c 100644 --- a/graph/iterator/hasa_iterator.go +++ b/graph/iterator/hasa_iterator.go @@ -47,22 +47,28 @@ import ( // a primary subiterator, a direction in which the triples for that subiterator point, // and a temporary holder for the iterator generated on Check(). type HasA struct { - Base + uid uint64 + tags graph.Tagger ts graph.TripleStore primaryIt graph.Iterator dir quad.Direction resultIt graph.Iterator + result graph.Value } // Construct a new HasA iterator, given the triple subiterator, and the triple // direction for which it stands. func NewHasA(ts graph.TripleStore, subIt graph.Iterator, d quad.Direction) *HasA { - var hasa HasA - BaseInit(&hasa.Base) - hasa.ts = ts - hasa.primaryIt = subIt - hasa.dir = d - return &hasa + return &HasA{ + uid: NextUID(), + ts: ts, + primaryIt: subIt, + dir: d, + } +} + +func (it *HasA) UID() uint64 { + return it.uid } // Return our sole subiterator. @@ -77,9 +83,13 @@ func (it *HasA) Reset() { } } +func (it *HasA) Tagger() *graph.Tagger { + return &it.tags +} + func (it *HasA) Clone() graph.Iterator { out := NewHasA(it.ts, it.primaryIt.Clone(), it.dir) - out.CopyTagsFrom(it) + out.tags.CopyFrom(it) return out } @@ -101,7 +111,14 @@ func (it *HasA) Optimize() (graph.Iterator, bool) { // Pass the TagResults down the chain. 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) } @@ -115,7 +132,7 @@ func (it *HasA) ResultTree() *graph.ResultTree { // Print some information about this iterator. func (it *HasA) DebugString(indent int) string { var tags string - for _, k := range it.Tags() { + for _, k := range it.tags.Tags() { 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)) @@ -142,7 +159,7 @@ func (it *HasA) Check(val graph.Value) bool { // another match is made. func (it *HasA) GetCheckResult() bool { for { - linkVal, ok := it.resultIt.Next() + linkVal, ok := graph.Next(it.resultIt) if !ok { break } @@ -150,7 +167,7 @@ func (it *HasA) GetCheckResult() bool { glog.V(4).Infoln("Quad is", it.ts.Quad(linkVal)) } if it.primaryIt.Check(linkVal) { - it.Last = it.ts.TripleDirection(linkVal, it.dir) + it.result = it.ts.TripleDirection(linkVal, it.dir) return true } } @@ -181,16 +198,20 @@ func (it *HasA) Next() (graph.Value, bool) { } it.resultIt = &Null{} - tID, ok := it.primaryIt.Next() + tID, ok := graph.Next(it.primaryIt) if !ok { return graph.NextLogOut(it, 0, false) } name := it.ts.Quad(tID).Get(it.dir) val := it.ts.ValueOf(name) - it.Last = val + it.result = val return graph.NextLogOut(it, val, true) } +func (it *HasA) Result() graph.Value { + return it.result +} + // GetStats() returns the statistics on the HasA iterator. This is curious. Next // cost is easy, it's an extra call or so on top of the subiterator Next cost. // CheckCost involves going to the graph.TripleStore, iterating out values, and hoping @@ -222,3 +243,7 @@ func (it *HasA) Close() { // Register this iterator as a HasA. func (it *HasA) Type() graph.Type { return graph.HasA } + +func (it *HasA) Size() (int64, bool) { + return 0, true +} diff --git a/graph/iterator/iterator.go b/graph/iterator/iterator.go index e2029d5..e80b56c 100644 --- a/graph/iterator/iterator.go +++ b/graph/iterator/iterator.go @@ -14,161 +14,55 @@ package iterator -// Define the general iterator interface, as well as the Base which all -// iterators can "inherit" from to get default iterator functionality. +// Define the general iterator interface. import ( - "fmt" "strings" "sync/atomic" - "github.com/barakmich/glog" - "github.com/google/cayley/graph" ) -var nextIteratorID uintptr +var nextIteratorID uint64 -func nextID() uintptr { - return atomic.AddUintptr(&nextIteratorID, 1) - 1 +func NextUID() uint64 { + return atomic.AddUint64(&nextIteratorID, 1) - 1 } -// The Base iterator is the iterator other iterators inherit from to get some -// default functionality. -type Base struct { - Last graph.Value - tags []string - fixedTags map[string]graph.Value - canNext bool - uid uintptr -} - -// Called by subclases. -func BaseInit(it *Base) { - // Your basic iterator is nextable - it.canNext = true - if glog.V(2) { - it.uid = nextID() - } -} - -func (it *Base) UID() uintptr { - 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. -func (it *Base) DebugString(indent int) string { - return fmt.Sprintf("%s(base)", strings.Repeat(" ", indent)) -} - -// Nothing in a base iterator. -func (it *Base) Check(v graph.Value) bool { - return false -} - -// Base iterators should never appear in a tree if they are, select against -// them. -func (it *Base) Stats() graph.IteratorStats { - return graph.IteratorStats{100000, 100000, 100000} -} - -// DEPRECATED -func (it *Base) ResultTree() *graph.ResultTree { - tree := graph.NewResultTree(it.Result()) - return tree -} - -// Nothing in a base iterator. -func (it *Base) Next() (graph.Value, bool) { - return nil, false -} - -func (it *Base) NextResult() bool { - return false -} - -// Returns the last result of an iterator. -func (it *Base) Result() graph.Value { - return it.Last -} - -// If you're empty and you know it, clap your hands. -func (it *Base) Size() (int64, bool) { - return 0, true -} - -// No subiterators. Only those with subiterators need to do anything here. -func (it *Base) SubIterators() []graph.Iterator { - return nil -} - -// Accessor -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. -// func (it *Base) Close() {} - -func (it *Null) Close() {} - -func (it *Base) Reset() {} - -// Here we define the simplest base iterator -- the Null iterator. It contains nothing. +// Here we define the simplest iterator -- the Null iterator. It contains nothing. // It is the empty set. Often times, queries that contain one of these match nothing, // so it's important to give it a special iterator. type Null struct { - Base + uid uint64 + tags graph.Tagger } // Fairly useless New function. func NewNull() *Null { - return &Null{} + return &Null{uid: NextUID()} +} + +func (it *Null) UID() uint64 { + return it.uid +} + +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) Check(graph.Value) bool { + return false } func (it *Null) Clone() graph.Iterator { return NewNull() } @@ -185,6 +79,34 @@ func (it *Null) DebugString(indent int) string { return strings.Repeat(" ", indent) + "(null)" } +func (it *Null) Next() (graph.Value, bool) { + return nil, false +} + +func (it *Null) Result() graph.Value { + return nil +} + +func (it *Null) ResultTree() *graph.ResultTree { + return graph.NewResultTree(it.Result()) +} + +func (it *Null) SubIterators() []graph.Iterator { + return nil +} + +func (it *Null) NextResult() bool { + return false +} + +func (it *Null) Size() (int64, bool) { + return 0, true +} + +func (it *Null) Reset() {} + +func (it *Null) Close() {} + // A null iterator costs nothing. Use it! func (it *Null) Stats() graph.IteratorStats { return graph.IteratorStats{} diff --git a/graph/iterator/linksto_iterator.go b/graph/iterator/linksto_iterator.go index ca76d1e..9ad81d6 100644 --- a/graph/iterator/linksto_iterator.go +++ b/graph/iterator/linksto_iterator.go @@ -41,23 +41,29 @@ import ( // for each node) the subiterator, and the direction the iterator comes from. // `next_it` is the tempoarary iterator held per result in `primary_it`. type LinksTo struct { - Base + uid uint64 + tags graph.Tagger ts graph.TripleStore primaryIt graph.Iterator dir quad.Direction nextIt graph.Iterator + result graph.Value } // Construct a new LinksTo iterator around a direction and a subiterator of // nodes. func NewLinksTo(ts graph.TripleStore, it graph.Iterator, d quad.Direction) *LinksTo { - var lto LinksTo - BaseInit(<o.Base) - lto.ts = ts - lto.primaryIt = it - lto.dir = d - lto.nextIt = &Null{} - return <o + return &LinksTo{ + uid: NextUID(), + ts: ts, + primaryIt: it, + dir: d, + nextIt: &Null{}, + } +} + +func (it *LinksTo) UID() uint64 { + return it.uid } func (it *LinksTo) Reset() { @@ -68,9 +74,13 @@ func (it *LinksTo) Reset() { it.nextIt = &Null{} } +func (it *LinksTo) Tagger() *graph.Tagger { + return &it.tags +} + func (it *LinksTo) Clone() graph.Iterator { out := NewLinksTo(it.ts, it.primaryIt.Clone(), it.dir) - out.CopyTagsFrom(it) + out.tags.CopyFrom(it) return out } @@ -79,7 +89,14 @@ func (it *LinksTo) Direction() quad.Direction { return it.dir } // Tag these results, and our subiterator's results. 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) } @@ -103,7 +120,7 @@ func (it *LinksTo) Check(val graph.Value) bool { graph.CheckLogIn(it, val) node := it.ts.TripleDirection(val, it.dir) if it.primaryIt.Check(node) { - it.Last = val + it.result = val return graph.CheckLogOut(it, val, true) } return graph.CheckLogOut(it, val, false) @@ -138,10 +155,10 @@ func (it *LinksTo) Optimize() (graph.Iterator, bool) { // Next()ing a LinksTo operates as described above. func (it *LinksTo) Next() (graph.Value, bool) { graph.NextLogIn(it) - val, ok := it.nextIt.Next() + val, ok := graph.Next(it.nextIt) if !ok { // Subiterator is empty, get another one - candidate, ok := it.primaryIt.Next() + candidate, ok := graph.Next(it.primaryIt) if !ok { // We're out of nodes in our subiterator, so we're done as well. return graph.NextLogOut(it, 0, false) @@ -151,10 +168,14 @@ func (it *LinksTo) Next() (graph.Value, bool) { // Recurse -- return the first in the next set. return it.Next() } - it.Last = val + it.result = val return graph.NextLogOut(it, val, ok) } +func (it *LinksTo) Result() graph.Value { + return it.result +} + // Close our subiterators. func (it *LinksTo) Close() { it.nextIt.Close() @@ -182,3 +203,7 @@ func (it *LinksTo) Stats() graph.IteratorStats { Size: fanoutFactor * subitStats.Size, } } + +func (it *LinksTo) Size() (int64, bool) { + return 0, true +} diff --git a/graph/iterator/optional_iterator.go b/graph/iterator/optional_iterator.go index 46c6dd6..bc6899c 100644 --- a/graph/iterator/optional_iterator.go +++ b/graph/iterator/optional_iterator.go @@ -30,26 +30,31 @@ import ( "fmt" "strings" - "github.com/barakmich/glog" - "github.com/google/cayley/graph" ) -// An optional iterator has the subconstraint iterator we wish to be optional +// An optional iterator has the sub-constraint iterator we wish to be optional // and whether the last check we received was true or false. type Optional struct { - Base + uid uint64 + tags graph.Tagger subIt graph.Iterator lastCheck bool + result graph.Value } // Creates a new optional iterator. func NewOptional(it graph.Iterator) *Optional { - var o Optional - BaseInit(&o.Base) - o.canNext = false - o.subIt = it - return &o + return &Optional{ + uid: NextUID(), + subIt: it, + } +} + +func (it *Optional) CanNext() bool { return false } + +func (it *Optional) UID() uint64 { + return it.uid } func (it *Optional) Reset() { @@ -61,17 +66,23 @@ func (it *Optional) Close() { it.subIt.Close() } +func (it *Optional) Tagger() *graph.Tagger { + return &it.tags +} + func (it *Optional) Clone() graph.Iterator { out := NewOptional(it.subIt.Clone()) - out.CopyTagsFrom(it) + out.tags.CopyFrom(it) return out } -// Nexting the iterator is unsupported -- error and return an empty set. -// (As above, a reasonable alternative would be to Next() an all iterator) -func (it *Optional) Next() (graph.Value, bool) { - glog.Errorln("Nexting an un-nextable iterator") - return nil, false +// DEPRECATED +func (it *Optional) ResultTree() *graph.ResultTree { + return graph.NewResultTree(it.Result()) +} + +func (it *Optional) Result() graph.Value { + return it.result } // An optional iterator only has a next result if, (a) last time we checked @@ -84,13 +95,18 @@ func (it *Optional) NextResult() bool { return false } +// No subiterators. +func (it *Optional) SubIterators() []graph.Iterator { + return nil +} + // Check() is the real hack of this iterator. It always returns true, regardless // of whether the subiterator matched. But we keep track of whether the subiterator // matched for results purposes. func (it *Optional) Check(val graph.Value) bool { checked := it.subIt.Check(val) it.lastCheck = checked - it.Last = val + it.result = val return true } @@ -111,7 +127,7 @@ func (it *Optional) DebugString(indent int) string { return fmt.Sprintf("%s(%s tags:%s\n%s)", strings.Repeat(" ", indent), it.Type(), - it.Tags(), + it.tags.Tags(), it.subIt.DebugString(indent+4)) } @@ -135,3 +151,8 @@ func (it *Optional) Stats() graph.IteratorStats { Size: subStats.Size, } } + +// If you're empty and you know it, clap your hands. +func (it *Optional) Size() (int64, bool) { + return 0, true +} diff --git a/graph/iterator/or_iterator.go b/graph/iterator/or_iterator.go index 31306eb..13f28b8 100644 --- a/graph/iterator/or_iterator.go +++ b/graph/iterator/or_iterator.go @@ -29,29 +29,34 @@ import ( ) type Or struct { - Base + uid uint64 + tags graph.Tagger isShortCircuiting bool internalIterators []graph.Iterator itCount int currentIterator int + result graph.Value } func NewOr() *Or { - var or Or - BaseInit(&or.Base) - or.internalIterators = make([]graph.Iterator, 0, 20) - or.isShortCircuiting = false - or.currentIterator = -1 - return &or + return &Or{ + uid: NextUID(), + internalIterators: make([]graph.Iterator, 0, 20), + currentIterator: -1, + } } func NewShortCircuitOr() *Or { - var or Or - BaseInit(&or.Base) - or.internalIterators = make([]graph.Iterator, 0, 20) - or.isShortCircuiting = true - or.currentIterator = -1 - return &or + return &Or{ + uid: NextUID(), + internalIterators: make([]graph.Iterator, 0, 20), + isShortCircuiting: true, + currentIterator: -1, + } +} + +func (it *Or) UID() uint64 { + return it.uid } // Reset all internal iterators @@ -62,6 +67,10 @@ func (it *Or) Reset() { it.currentIterator = -1 } +func (it *Or) Tagger() *graph.Tagger { + return &it.tags +} + func (it *Or) Clone() graph.Iterator { var or *Or if it.isShortCircuiting { @@ -72,7 +81,7 @@ func (it *Or) Clone() graph.Iterator { for _, sub := range it.internalIterators { or.AddSubIterator(sub.Clone()) } - or.CopyTagsFrom(it) + or.tags.CopyFrom(it) return or } @@ -84,7 +93,14 @@ func (it *Or) SubIterators() []graph.Iterator { // Overrides BaseIterator TagResults, as it needs to add it's own results and // recurse down it's subiterators. 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) } @@ -105,7 +121,7 @@ func (it *Or) DebugString(indent int) string { total += fmt.Sprintf("%d:\n%s\n", i, sub.DebugString(indent+4)) } var tags string - for _, k := range it.Tags() { + for _, k := range it.tags.Tags() { tags += fmt.Sprintf("%s;", k) } spaces := strings.Repeat(" ", indent+2) @@ -139,7 +155,7 @@ func (it *Or) Next() (graph.Value, bool) { firstTime = true } curIt := it.internalIterators[it.currentIterator] - curr, exists = curIt.Next() + curr, exists = graph.Next(curIt) if !exists { if it.isShortCircuiting && !firstTime { return graph.NextLogOut(it, nil, false) @@ -149,11 +165,15 @@ func (it *Or) Next() (graph.Value, bool) { return graph.NextLogOut(it, nil, false) } } else { - it.Last = curr + it.result = curr return graph.NextLogOut(it, curr, true) } } - panic("Somehow broke out of Next() loop in Or") + panic("unreachable") +} + +func (it *Or) Result() graph.Value { + return it.result } // Checks a value against the iterators, in order. @@ -176,7 +196,7 @@ func (it *Or) Check(val graph.Value) bool { if !anyGood { return graph.CheckLogOut(it, val, false) } - it.Last = val + it.result = val return graph.CheckLogOut(it, val, true) } @@ -247,7 +267,7 @@ func (it *Or) Optimize() (graph.Iterator, bool) { } // 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 // the new And (they were unchanged upon calling Optimize() on them, at the diff --git a/graph/iterator/or_iterator_test.go b/graph/iterator/or_iterator_test.go index 3b52ccd..78742eb 100644 --- a/graph/iterator/or_iterator_test.go +++ b/graph/iterator/or_iterator_test.go @@ -24,7 +24,7 @@ import ( func iterated(it graph.Iterator) []int { var res []int for { - val, ok := it.Next() + val, ok := graph.Next(it) if !ok { break } diff --git a/graph/iterator/query_shape.go b/graph/iterator/query_shape.go index d49aa09..973f6db 100644 --- a/graph/iterator/query_shape.go +++ b/graph/iterator/query_shape.go @@ -108,10 +108,10 @@ func (qs *queryShape) StealNode(left *Node, right *Node) { func (qs *queryShape) MakeNode(it graph.Iterator) *Node { n := Node{Id: qs.nodeId} - for _, tag := range it.Tags() { + for _, tag := range it.Tagger().Tags() { n.Tags = append(n.Tags, tag) } - for k, _ := range it.FixedTags() { + for k, _ := range it.Tagger().Fixed() { n.Tags = append(n.Tags, k) } @@ -130,7 +130,7 @@ func (qs *queryShape) MakeNode(it graph.Iterator) *Node { case graph.Fixed: n.IsFixed = true for { - val, more := it.Next() + val, more := graph.Next(it) if !more { break } diff --git a/graph/iterator/query_shape_test.go b/graph/iterator/query_shape_test.go index 4e701ab..570223a 100644 --- a/graph/iterator/query_shape_test.go +++ b/graph/iterator/query_shape_test.go @@ -27,7 +27,7 @@ func hasaWithTag(ts graph.TripleStore, tag string, target string) *HasA { obj := ts.FixedIterator() obj.Add(ts.ValueOf(target)) - obj.AddTag(tag) + obj.Tagger().Add(tag) and.AddSubIterator(NewLinksTo(ts, obj, quad.Object)) pred := ts.FixedIterator() @@ -49,7 +49,7 @@ func TestQueryShape(t *testing.T) { // Given a single linkage iterator's shape. hasa := hasaWithTag(ts, "tag", "cool") - hasa.AddTag("top") + hasa.Tagger().Add("top") shape := make(map[string]interface{}) OutputQueryShapeForIterator(hasa, ts, shape) @@ -94,11 +94,11 @@ func TestQueryShape(t *testing.T) { andInternal := NewAnd() hasa1 := hasaWithTag(ts, "tag1", "cool") - hasa1.AddTag("hasa1") + hasa1.Tagger().Add("hasa1") andInternal.AddSubIterator(hasa1) hasa2 := hasaWithTag(ts, "tag2", "fun") - hasa2.AddTag("hasa2") + hasa2.Tagger().Add("hasa2") andInternal.AddSubIterator(hasa2) pred := ts.FixedIterator() diff --git a/graph/iterator/value_comparison_iterator.go b/graph/iterator/value_comparison_iterator.go index fd6a1a8..7d687bd 100644 --- a/graph/iterator/value_comparison_iterator.go +++ b/graph/iterator/value_comparison_iterator.go @@ -46,21 +46,27 @@ const ( ) type Comparison struct { - Base - subIt graph.Iterator - op Operator - val interface{} - ts graph.TripleStore + uid uint64 + tags graph.Tagger + subIt graph.Iterator + op Operator + val interface{} + ts graph.TripleStore + result graph.Value } func NewComparison(sub graph.Iterator, op Operator, val interface{}, ts graph.TripleStore) *Comparison { - var vc Comparison - BaseInit(&vc.Base) - vc.subIt = sub - vc.op = op - vc.val = val - vc.ts = ts - return &vc + return &Comparison{ + uid: NextUID(), + subIt: sub, + op: op, + val: val, + ts: ts, + } +} + +func (it *Comparison) UID() uint64 { + return it.uid } // Here's the non-boilerplate part of the ValueComparison iterator. Given a value @@ -111,9 +117,13 @@ func (it *Comparison) Reset() { it.subIt.Reset() } +func (it *Comparison) Tagger() *graph.Tagger { + return &it.tags +} + func (it *Comparison) Clone() graph.Iterator { out := NewComparison(it.subIt.Clone(), it.op, it.val, it.ts) - out.CopyTagsFrom(it) + out.tags.CopyFrom(it) return out } @@ -121,7 +131,7 @@ func (it *Comparison) Next() (graph.Value, bool) { var val graph.Value var ok bool for { - val, ok = it.subIt.Next() + val, ok = graph.Next(it.subIt) if !ok { return nil, false } @@ -129,10 +139,19 @@ func (it *Comparison) Next() (graph.Value, bool) { break } } - it.Last = val + it.result = val return val, ok } +// DEPRECATED +func (it *Comparison) ResultTree() *graph.ResultTree { + return graph.NewResultTree(it.Result()) +} + +func (it *Comparison) Result() graph.Value { + return it.result +} + func (it *Comparison) NextResult() bool { for { hasNext := it.subIt.NextResult() @@ -143,10 +162,15 @@ func (it *Comparison) NextResult() bool { return true } } - it.Last = it.subIt.Result() + it.result = it.subIt.Result() return true } +// No subiterators. +func (it *Comparison) SubIterators() []graph.Iterator { + return nil +} + func (it *Comparison) Check(val graph.Value) bool { if !it.doComparison(val) { return false @@ -157,7 +181,14 @@ func (it *Comparison) Check(val graph.Value) bool { // If we failed the check, then the subiterator should not contribute to the result // set. Otherwise, go ahead and tag it. 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) } @@ -188,3 +219,7 @@ func (it *Comparison) Optimize() (graph.Iterator, bool) { func (it *Comparison) Stats() graph.IteratorStats { return it.subIt.Stats() } + +func (it *Comparison) Size() (int64, bool) { + return 0, true +} diff --git a/graph/leveldb/all_iterator.go b/graph/leveldb/all_iterator.go index 056b270..b45fc0d 100644 --- a/graph/leveldb/all_iterator.go +++ b/graph/leveldb/all_iterator.go @@ -28,33 +28,47 @@ import ( ) type AllIterator struct { - iterator.Base + uid uint64 + tags graph.Tagger prefix []byte dir quad.Direction open bool iter ldbit.Iterator ts *TripleStore ro *opt.ReadOptions + result graph.Value } func NewAllIterator(prefix string, d quad.Direction, ts *TripleStore) *AllIterator { - var it AllIterator - iterator.BaseInit(&it.Base) - it.ro = &opt.ReadOptions{} - it.ro.DontFillCache = true - it.iter = ts.db.NewIterator(nil, it.ro) - it.prefix = []byte(prefix) - it.dir = d - it.open = true - it.ts = ts + opts := &opt.ReadOptions{ + DontFillCache: true, + } + + it := AllIterator{ + uid: iterator.NextUID(), + ro: opts, + iter: ts.db.NewIterator(nil, opts), + prefix: []byte(prefix), + dir: d, + open: true, + ts: ts, + } + it.iter.Seek(it.prefix) if !it.iter.Valid() { + // FIXME(kortschak) What are the semantics here? Is this iterator usable? + // If not, we should return nil *Iterator and an error. it.open = false it.iter.Release() } + return &it } +func (it *AllIterator) UID() uint64 { + return it.uid +} + func (it *AllIterator) Reset() { if !it.open { it.iter = it.ts.db.NewIterator(nil, it.ro) @@ -67,15 +81,29 @@ 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 { out := NewAllIterator(string(it.prefix), it.dir, it.ts) - out.CopyTagsFrom(it) + out.tags.CopyFrom(it) return out } func (it *AllIterator) Next() (graph.Value, bool) { if !it.open { - it.Last = nil + it.result = nil return nil, false } var out []byte @@ -89,12 +117,29 @@ func (it *AllIterator) Next() (graph.Value, bool) { it.Close() return nil, false } - it.Last = out + it.result = out return out, true } +func (it *AllIterator) ResultTree() *graph.ResultTree { + return graph.NewResultTree(it.Result()) +} + +func (it *AllIterator) Result() graph.Value { + return it.result +} + +func (it *AllIterator) NextResult() bool { + return false +} + +// No subiterators. +func (it *AllIterator) SubIterators() []graph.Iterator { + return nil +} + func (it *AllIterator) Check(v graph.Value) bool { - it.Last = v + it.result = v return true } @@ -116,7 +161,7 @@ func (it *AllIterator) Size() (int64, bool) { func (it *AllIterator) DebugString(indent int) string { 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 } diff --git a/graph/leveldb/iterator.go b/graph/leveldb/iterator.go index dda7edf..51bce4c 100644 --- a/graph/leveldb/iterator.go +++ b/graph/leveldb/iterator.go @@ -28,7 +28,8 @@ import ( ) type Iterator struct { - iterator.Base + uid uint64 + tags graph.Tagger nextPrefix []byte checkId []byte dir quad.Direction @@ -37,30 +38,46 @@ type Iterator struct { qs *TripleStore ro *opt.ReadOptions originalPrefix string + result graph.Value } func NewIterator(prefix string, d quad.Direction, value graph.Value, qs *TripleStore) *Iterator { - var it Iterator - iterator.BaseInit(&it.Base) - it.checkId = value.([]byte) - it.dir = d - it.originalPrefix = prefix - it.nextPrefix = make([]byte, 0, 2+qs.hasher.Size()) - it.nextPrefix = append(it.nextPrefix, []byte(prefix)...) - it.nextPrefix = append(it.nextPrefix, []byte(it.checkId[1:])...) - it.ro = &opt.ReadOptions{} - it.ro.DontFillCache = true - it.iter = qs.db.NewIterator(nil, it.ro) - it.open = true - it.qs = qs + vb := value.([]byte) + p := make([]byte, 0, 2+qs.hasher.Size()) + p = append(p, []byte(prefix)...) + p = append(p, []byte(vb[1:])...) + + opts := &opt.ReadOptions{ + DontFillCache: true, + } + + it := Iterator{ + uid: iterator.NextUID(), + nextPrefix: p, + checkId: vb, + dir: d, + originalPrefix: prefix, + ro: opts, + iter: qs.db.NewIterator(nil, opts), + open: true, + qs: qs, + } + ok := it.iter.Seek(it.nextPrefix) if !ok { + // FIXME(kortschak) What are the semantics here? Is this iterator usable? + // If not, we should return nil *Iterator and an error. it.open = false it.iter.Release() } + return &it } +func (it *Iterator) UID() uint64 { + return it.uid +} + func (it *Iterator) Reset() { if !it.open { it.iter = it.qs.db.NewIterator(nil, it.ro) @@ -73,9 +90,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 { out := NewIterator(it.originalPrefix, it.dir, it.checkId, it.qs) - out.CopyTagsFrom(it) + out.tags.CopyFrom(it) return out } @@ -88,22 +119,22 @@ func (it *Iterator) Close() { func (it *Iterator) Next() (graph.Value, bool) { if it.iter == nil { - it.Last = nil + it.result = nil return nil, false } if !it.open { - it.Last = nil + it.result = nil return nil, false } if !it.iter.Valid() { - it.Last = nil + it.result = nil it.Close() return nil, false } if bytes.HasPrefix(it.iter.Key(), it.nextPrefix) { out := make([]byte, len(it.iter.Key())) copy(out, it.iter.Key()) - it.Last = out + it.result = out ok := it.iter.Next() if !ok { it.Close() @@ -111,10 +142,27 @@ func (it *Iterator) Next() (graph.Value, bool) { return out, true } it.Close() - it.Last = nil + it.result = nil return nil, false } +func (it *Iterator) ResultTree() *graph.ResultTree { + return graph.NewResultTree(it.Result()) +} + +func (it *Iterator) Result() graph.Value { + return it.result +} + +func (it *Iterator) NextResult() bool { + return false +} + +// No subiterators. +func (it *Iterator) SubIterators() []graph.Iterator { + return nil +} + func PositionOf(prefix []byte, d quad.Direction, qs *TripleStore) int { if bytes.Equal(prefix, []byte("sp")) { switch d { @@ -193,7 +241,7 @@ func (it *Iterator) Size() (int64, bool) { func (it *Iterator) DebugString(indent int) string { 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.qs.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.qs.NameOf(it.checkId)) } var levelDBType graph.Type diff --git a/graph/leveldb/leveldb_test.go b/graph/leveldb/leveldb_test.go index 2501e14..bba1eb8 100644 --- a/graph/leveldb/leveldb_test.go +++ b/graph/leveldb/leveldb_test.go @@ -46,7 +46,7 @@ func makeTripleSet() []*quad.Quad { func iteratedTriples(qs graph.TripleStore, it graph.Iterator) []*quad.Quad { var res ordered for { - val, ok := it.Next() + val, ok := graph.Next(it) if !ok { break } @@ -86,7 +86,7 @@ func (o ordered) Swap(i, j int) { o[i], o[j] = o[j], o[i] } func iteratedNames(qs graph.TripleStore, it graph.Iterator) []string { var res []string for { - val, ok := it.Next() + val, ok := graph.Next(it) if !ok { break } @@ -266,7 +266,7 @@ func TestIterator(t *testing.T) { it.Reset() it = qs.TriplesAllIterator() - edge, _ := it.Next() + edge, _ := graph.Next(it) triple := qs.Quad(edge) set := makeTripleSet() var ok bool @@ -416,7 +416,7 @@ func TestOptimize(t *testing.T) { // With an linksto-fixed pair fixed := qs.FixedIterator() fixed.Add(qs.ValueOf("F")) - fixed.AddTag("internal") + fixed.Tagger().Add("internal") lto := iterator.NewLinksTo(qs, fixed, quad.Object) oldIt := lto.Clone() @@ -434,10 +434,10 @@ func TestOptimize(t *testing.T) { t.Errorf("Optimized iteration does not match original") } - oldIt.Next() + graph.Next(oldIt) oldResults := make(map[string]graph.Value) oldIt.TagResults(oldResults) - newIt.Next() + graph.Next(newIt) newResults := make(map[string]graph.Value) newIt.TagResults(newResults) if !reflect.DeepEqual(newResults, oldResults) { diff --git a/graph/leveldb/triplestore_iterator_optimize.go b/graph/leveldb/triplestore_iterator_optimize.go index 2234060..9aab0f2 100644 --- a/graph/leveldb/triplestore_iterator_optimize.go +++ b/graph/leveldb/triplestore_iterator_optimize.go @@ -37,14 +37,15 @@ func (ts *TripleStore) optimizeLinksTo(it *iterator.LinksTo) (graph.Iterator, bo if primary.Type() == graph.Fixed { size, _ := primary.Size() if size == 1 { - val, ok := primary.Next() + val, ok := graph.Next(primary) if !ok { panic("Sizes lie") } newIt := ts.TripleIterator(it.Direction(), val) - newIt.CopyTagsFrom(it) - for _, tag := range primary.Tags() { - newIt.AddFixedTag(tag, val) + nt := newIt.Tagger() + nt.CopyFrom(it) + for _, tag := range primary.Tagger().Tags() { + nt.AddFixed(tag, val) } it.Close() return newIt, true diff --git a/graph/memstore/all_iterator.go b/graph/memstore/all_iterator.go index 371a958..658a4a1 100644 --- a/graph/memstore/all_iterator.go +++ b/graph/memstore/all_iterator.go @@ -31,6 +31,11 @@ func NewMemstoreAllIterator(ts *TripleStore) *AllIterator { return &out } +// No subiterators. +func (it *AllIterator) SubIterators() []graph.Iterator { + return nil +} + func (it *AllIterator) Next() (graph.Value, bool) { next, out := it.Int64.Next() if !out { @@ -41,6 +46,5 @@ func (it *AllIterator) Next() (graph.Value, bool) { if !ok { return it.Next() } - it.Last = next return next, out } diff --git a/graph/memstore/iterator.go b/graph/memstore/iterator.go index 3b7bfa8..7ec913a 100644 --- a/graph/memstore/iterator.go +++ b/graph/memstore/iterator.go @@ -26,11 +26,13 @@ import ( ) type Iterator struct { - iterator.Base + uid uint64 + tags graph.Tagger tree *llrb.LLRB data string isRunning bool iterLast Int64 + result graph.Value } type Int64 int64 @@ -53,34 +55,69 @@ func IterateOne(tree *llrb.LLRB, last Int64) Int64 { } func NewLlrbIterator(tree *llrb.LLRB, data string) *Iterator { - var it Iterator - iterator.BaseInit(&it.Base) - it.tree = tree - it.iterLast = Int64(-1) - it.data = data - return &it + return &Iterator{ + uid: iterator.NextUID(), + tree: tree, + iterLast: Int64(-1), + data: data, + } +} + +func (it *Iterator) UID() uint64 { + return it.uid } func (it *Iterator) Reset() { 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 { - var new_it = NewLlrbIterator(it.tree, it.data) - new_it.CopyTagsFrom(it) - return new_it + m := NewLlrbIterator(it.tree, it.data) + m.tags.CopyFrom(it) + return m } func (it *Iterator) Close() {} func (it *Iterator) Next() (graph.Value, bool) { graph.NextLogIn(it) - if it.tree.Max() == nil || it.Last == int64(it.tree.Max().(Int64)) { + if it.tree.Max() == nil || it.result == int64(it.tree.Max().(Int64)) { return graph.NextLogOut(it, nil, false) } it.iterLast = IterateOne(it.tree, it.iterLast) - it.Last = int64(it.iterLast) - return graph.NextLogOut(it, it.Last, true) + it.result = int64(it.iterLast) + return graph.NextLogOut(it, it.result, true) +} + +func (it *Iterator) ResultTree() *graph.ResultTree { + return graph.NewResultTree(it.Result()) +} + +func (it *Iterator) Result() graph.Value { + return it.result +} + +func (it *Iterator) NextResult() bool { + return false +} + +// No subiterators. +func (it *Iterator) SubIterators() []graph.Iterator { + return nil } func (it *Iterator) Size() (int64, bool) { @@ -90,7 +127,7 @@ func (it *Iterator) Size() (int64, bool) { func (it *Iterator) Check(v graph.Value) bool { graph.CheckLogIn(it, v) if it.tree.Has(Int64(v.(int64))) { - it.Last = v + it.result = v return graph.CheckLogOut(it, v, true) } return graph.CheckLogOut(it, v, false) @@ -98,7 +135,7 @@ func (it *Iterator) Check(v graph.Value) bool { func (it *Iterator) DebugString(indent int) string { 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 diff --git a/graph/memstore/triplestore_iterator_optimize.go b/graph/memstore/triplestore_iterator_optimize.go index 1a89a16..3dc2c2c 100644 --- a/graph/memstore/triplestore_iterator_optimize.go +++ b/graph/memstore/triplestore_iterator_optimize.go @@ -37,14 +37,15 @@ func (ts *TripleStore) optimizeLinksTo(it *iterator.LinksTo) (graph.Iterator, bo if primary.Type() == graph.Fixed { size, _ := primary.Size() if size == 1 { - val, ok := primary.Next() + val, ok := graph.Next(primary) if !ok { panic("Sizes lie") } newIt := ts.TripleIterator(it.Direction(), val) - newIt.CopyTagsFrom(it) - for _, tag := range primary.Tags() { - newIt.AddFixedTag(tag, val) + nt := newIt.Tagger() + nt.CopyFrom(it) + for _, tag := range primary.Tagger().Tags() { + nt.AddFixed(tag, val) } return newIt, true } diff --git a/graph/memstore/triplestore_test.go b/graph/memstore/triplestore_test.go index 61ae371..44c43b4 100644 --- a/graph/memstore/triplestore_test.go +++ b/graph/memstore/triplestore_test.go @@ -19,6 +19,7 @@ import ( "sort" "testing" + "github.com/google/cayley/graph" "github.com/google/cayley/graph/iterator" "github.com/google/cayley/quad" ) @@ -150,7 +151,7 @@ func TestLinksToOptimization(t *testing.T) { fixed.Add(ts.ValueOf("cool")) lto := iterator.NewLinksTo(ts, fixed, quad.Object) - lto.AddTag("foo") + lto.Tagger().Add("foo") newIt, changed := lto.Optimize() if !changed { @@ -165,7 +166,8 @@ func TestLinksToOptimization(t *testing.T) { if v_clone.DebugString(0) != v.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") } } @@ -188,7 +190,7 @@ func TestRemoveTriple(t *testing.T) { hasa := iterator.NewHasA(ts, innerAnd, quad.Object) newIt, _ := hasa.Optimize() - _, ok := newIt.Next() + _, ok := graph.Next(newIt) if ok { t.Error("E should not have any followers.") } diff --git a/graph/mongo/iterator.go b/graph/mongo/iterator.go index 77dcd75..d04c8fa 100644 --- a/graph/mongo/iterator.go +++ b/graph/mongo/iterator.go @@ -28,7 +28,8 @@ import ( ) type Iterator struct { - iterator.Base + uid uint64 + tags graph.Tagger qs *TripleStore dir quad.Direction iter *mgo.Iter @@ -38,55 +39,68 @@ type Iterator struct { isAll bool constraint bson.M collection string + result graph.Value } func NewIterator(qs *TripleStore, collection string, d quad.Direction, val graph.Value) *Iterator { - var m Iterator - iterator.BaseInit(&m.Base) + name := qs.NameOf(val) - m.name = qs.NameOf(val) - m.collection = collection + var constraint bson.M switch d { case quad.Subject: - m.constraint = bson.M{"Subject": m.name} + constraint = bson.M{"Subject": name} case quad.Predicate: - m.constraint = bson.M{"Predicate": m.name} + constraint = bson.M{"Predicate": name} case quad.Object: - m.constraint = bson.M{"Object": m.name} + constraint = bson.M{"Object": name} case quad.Label: - m.constraint = bson.M{"Label": m.name} + constraint = bson.M{"Label": name} } - m.qs = qs - m.dir = d - m.iter = qs.db.C(collection).Find(m.constraint).Iter() - size, err := qs.db.C(collection).Find(m.constraint).Count() + size, err := qs.db.C(collection).Find(constraint).Count() if err != nil { + // FIXME(kortschak) This should be passed back rather than just logging. glog.Errorln("Trouble getting size for iterator! ", err) return nil } - m.size = int64(size) - m.hash = val.(string) - m.isAll = false - return &m + + return &Iterator{ + uid: iterator.NextUID(), + name: name, + constraint: constraint, + collection: collection, + qs: qs, + dir: d, + iter: qs.db.C(collection).Find(constraint).Iter(), + size: int64(size), + hash: val.(string), + isAll: false, + } } func NewAllIterator(qs *TripleStore, collection string) *Iterator { - var m Iterator - m.qs = qs - m.dir = quad.Any - m.constraint = nil - m.collection = collection - m.iter = qs.db.C(collection).Find(nil).Iter() size, err := qs.db.C(collection).Count() if err != nil { + // FIXME(kortschak) This should be passed back rather than just logging. glog.Errorln("Trouble getting size for iterator! ", err) return nil } - m.size = int64(size) - m.hash = "" - m.isAll = true - return &m + + return &Iterator{ + uid: iterator.NextUID(), + qs: qs, + dir: quad.Any, + constraint: nil, + collection: collection, + iter: qs.db.C(collection).Find(nil).Iter(), + size: int64(size), + hash: "", + isAll: true, + } +} + +func (it *Iterator) UID() uint64 { + return it.uid } func (it *Iterator) Reset() { @@ -99,15 +113,29 @@ func (it *Iterator) Close() { it.iter.Close() } -func (it *Iterator) Clone() graph.Iterator { - var newM graph.Iterator - if it.isAll { - newM = NewAllIterator(it.qs, it.collection) - } else { - newM = NewIterator(it.qs, it.collection, it.dir, it.hash) +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() } - 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.qs, it.collection) + } else { + m = NewIterator(it.qs, it.collection, it.dir, it.hash) + } + m.tags.CopyFrom(it) + return m } func (it *Iterator) Next() (graph.Value, bool) { @@ -125,14 +153,31 @@ func (it *Iterator) Next() (graph.Value, bool) { } return nil, false } - it.Last = result.Id + it.result = result.Id return result.Id, true } +func (it *Iterator) ResultTree() *graph.ResultTree { + return graph.NewResultTree(it.Result()) +} + +func (it *Iterator) Result() graph.Value { + return it.result +} + +func (it *Iterator) NextResult() bool { + return false +} + +// No subiterators. +func (it *Iterator) SubIterators() []graph.Iterator { + return nil +} + func (it *Iterator) Check(v graph.Value) bool { graph.CheckLogIn(it, v) if it.isAll { - it.Last = v + it.result = v return graph.CheckLogOut(it, v, true) } var offset int @@ -148,7 +193,7 @@ func (it *Iterator) Check(v graph.Value) bool { } val := v.(string)[offset : it.qs.hasher.Size()*2+offset] if val == it.hash { - it.Last = v + it.result = v return graph.CheckLogOut(it, v, true) } return graph.CheckLogOut(it, v, false) diff --git a/graph/mongo/triplestore_iterator_optimize.go b/graph/mongo/triplestore_iterator_optimize.go index 766e84c..d2d1a05 100644 --- a/graph/mongo/triplestore_iterator_optimize.go +++ b/graph/mongo/triplestore_iterator_optimize.go @@ -37,14 +37,15 @@ func (ts *TripleStore) optimizeLinksTo(it *iterator.LinksTo) (graph.Iterator, bo if primary.Type() == graph.Fixed { size, _ := primary.Size() if size == 1 { - val, ok := primary.Next() + val, ok := graph.Next(primary) if !ok { panic("Sizes lie") } newIt := ts.TripleIterator(it.Direction(), val) - newIt.CopyTagsFrom(it) - for _, tag := range primary.Tags() { - newIt.AddFixedTag(tag, val) + nt := newIt.Tagger() + nt.CopyFrom(it) + for _, tag := range primary.Tagger().Tags() { + nt.AddFixed(tag, val) } it.Close() return newIt, true diff --git a/graph/result_tree_evaluator.go b/graph/result_tree_evaluator.go index e1588d2..e2feb33 100644 --- a/graph/result_tree_evaluator.go +++ b/graph/result_tree_evaluator.go @@ -40,7 +40,7 @@ func (t *ResultTree) AddSubtree(sub *ResultTree) { t.subtrees = append(t.subtrees, sub) } -func StringResultTreeEvaluator(it Iterator) string { +func StringResultTreeEvaluator(it Nexter) string { ok := true out := "" for { @@ -59,6 +59,6 @@ func StringResultTreeEvaluator(it Iterator) string { return out } -func PrintResultTreeEvaluator(it Iterator) { +func PrintResultTreeEvaluator(it Nexter) { fmt.Print(StringResultTreeEvaluator(it)) } diff --git a/graph/sexp/parser.go b/graph/sexp/parser.go index de530f7..fa25b5d 100644 --- a/graph/sexp/parser.go +++ b/graph/sexp/parser.go @@ -190,7 +190,7 @@ func buildIteratorTree(tree *peg.ExpressionTree, ts graph.TripleStore) graph.Ite nodeID := getIdentString(tree) if tree.Children[0].Name == "Variable" { allIt := ts.NodesAllIterator() - allIt.AddTag(nodeID) + allIt.Tagger().Add(nodeID) out = allIt } else { n := nodeID diff --git a/graph/sexp/parser_test.go b/graph/sexp/parser_test.go index 29536d3..e7e66bf 100644 --- a/graph/sexp/parser_test.go +++ b/graph/sexp/parser_test.go @@ -67,7 +67,7 @@ func TestMemstoreBackedSexp(t *testing.T) { if it.Type() != test.typ { t.Errorf("Incorrect type for %s, got:%q expect %q", test.message, it.Type(), test.expect) } - got, ok := it.Next() + got, ok := graph.Next(it) if !ok { t.Errorf("Failed to %s", test.message) } @@ -88,7 +88,7 @@ func TestTreeConstraintParse(t *testing.T) { if it.Type() != graph.And { t.Error("Odd iterator tree. Got: %s", it.DebugString(0)) } - out, ok := it.Next() + out, ok := graph.Next(it) if !ok { t.Error("Got no results") } @@ -105,7 +105,7 @@ func TestTreeConstraintTagParse(t *testing.T) { "(:like\n" + "($a (:is :good))))" it := BuildIteratorTreeForQuery(ts, query) - _, ok := it.Next() + _, ok := graph.Next(it) if !ok { t.Error("Got no results") } @@ -135,14 +135,14 @@ func TestMultipleConstraintParse(t *testing.T) { if it.Type() != graph.And { t.Error("Odd iterator tree. Got: %s", it.DebugString(0)) } - out, ok := it.Next() + out, ok := graph.Next(it) if !ok { t.Error("Got no results") } if out != ts.ValueOf("i") { t.Errorf("Got %d, expected %d", out, ts.ValueOf("i")) } - _, ok = it.Next() + _, ok = graph.Next(it) if ok { t.Error("Too many results") } diff --git a/graph/sexp/session.go b/graph/sexp/session.go index 8d243f0..0fb4810 100644 --- a/graph/sexp/session.go +++ b/graph/sexp/session.go @@ -77,7 +77,7 @@ func (s *Session) ExecInput(input string, out chan interface{}, limit int) { } nResults := 0 for { - _, ok := it.Next() + _, ok := graph.Next(it) if !ok { break } diff --git a/query/gremlin/build_iterator.go b/query/gremlin/build_iterator.go index d3d9325..2a0b800 100644 --- a/query/gremlin/build_iterator.go +++ b/query/gremlin/build_iterator.go @@ -136,7 +136,7 @@ func buildInOutIterator(obj *otto.Object, ts graph.TripleStore, base graph.Itera tags = makeListOfStringsFromArrayValue(one.Object()) } for _, tag := range tags { - predicateNodeIterator.AddTag(tag) + predicateNodeIterator.Tagger().Add(tag) } } @@ -180,7 +180,7 @@ func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph. case "tag": it = subIt for _, tag := range stringArgs { - it.AddTag(tag) + it.Tagger().Add(tag) } case "save": all := ts.NodesAllIterator() @@ -188,9 +188,9 @@ func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph. return iterator.NewNull() } if len(stringArgs) == 2 { - all.AddTag(stringArgs[1]) + all.Tagger().Add(stringArgs[1]) } else { - all.AddTag(stringArgs[0]) + all.Tagger().Add(stringArgs[0]) } predFixed := ts.FixedIterator() predFixed.Add(ts.ValueOf(stringArgs[0])) @@ -208,9 +208,9 @@ func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph. return iterator.NewNull() } if len(stringArgs) == 2 { - all.AddTag(stringArgs[1]) + all.Tagger().Add(stringArgs[1]) } else { - all.AddTag(stringArgs[0]) + all.Tagger().Add(stringArgs[0]) } predFixed := ts.FixedIterator() predFixed.Add(ts.ValueOf(stringArgs[0])) diff --git a/query/gremlin/finals.go b/query/gremlin/finals.go index 7ad0886..022a394 100644 --- a/query/gremlin/finals.go +++ b/query/gremlin/finals.go @@ -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 { return func(call otto.FunctionCall) otto.Value { it := buildIteratorTree(obj, ses.ts) - it.AddTag(TopResultTag) + it.Tagger().Add(TopResultTag) ses.limit = -1 ses.count = 0 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 { limitVal, _ := call.Argument(0).ToInteger() it := buildIteratorTree(obj, ses.ts) - it.AddTag(TopResultTag) + it.Tagger().Add(TopResultTag) ses.limit = int(limitVal) ses.count = 0 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 { return func(call otto.FunctionCall) otto.Value { it := buildIteratorTree(obj, ses.ts) - it.AddTag(TopResultTag) + it.Tagger().Add(TopResultTag) limit := -1 if len(call.ArgumentList) > 0 { 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 { return func(call otto.FunctionCall) otto.Value { it := buildIteratorTree(obj, ses.ts) - it.AddTag(TopResultTag) + it.Tagger().Add(TopResultTag) limit := 1 var val otto.Value 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 { return func(call otto.FunctionCall) otto.Value { it := buildIteratorTree(obj, ses.ts) - it.AddTag(TopResultTag) + it.Tagger().Add(TopResultTag) limit := -1 if len(call.ArgumentList) == 0 { return otto.NullValue() @@ -151,7 +151,7 @@ func runIteratorToArray(it graph.Iterator, ses *Session, limit int) []map[string if ses.doHalt { return nil } - _, ok := it.Next() + _, ok := graph.Next(it) if !ok { break } @@ -187,7 +187,7 @@ func runIteratorToArrayNoTags(it graph.Iterator, ses *Session, limit int) []stri if ses.doHalt { return nil } - val, ok := it.Next() + val, ok := graph.Next(it) if !ok { break } @@ -208,7 +208,7 @@ func runIteratorWithCallback(it graph.Iterator, ses *Session, callback otto.Valu if ses.doHalt { return } - _, ok := it.Next() + _, ok := graph.Next(it) if !ok { break } @@ -249,7 +249,7 @@ func runIteratorOnSession(it graph.Iterator, ses *Session) { if ses.doHalt { return } - _, ok := it.Next() + _, ok := graph.Next(it) if !ok { break } diff --git a/query/mql/build_iterator.go b/query/mql/build_iterator.go index b7ff9a4..f6c54e9 100644 --- a/query/mql/build_iterator.go +++ b/query/mql/build_iterator.go @@ -34,7 +34,7 @@ func (q *Query) buildFixed(s string) graph.Iterator { func (q *Query) buildResultIterator(path Path) graph.Iterator { all := q.ses.ts.NodesAllIterator() - all.AddTag(string(path)) + all.Tagger().Add(string(path)) return all } @@ -98,7 +98,7 @@ func (q *Query) buildIteratorTreeInternal(query interface{}, path Path) (it grap if err != nil { return nil, false, err } - it.AddTag(string(path)) + it.Tagger().Add(string(path)) return it, optional, nil } diff --git a/query/mql/session.go b/query/mql/session.go index e5944d4..882c856 100644 --- a/query/mql/session.go +++ b/query/mql/session.go @@ -88,7 +88,7 @@ func (s *Session) ExecInput(input string, c chan interface{}, limit int) { glog.V(2).Infoln(it.DebugString(0)) } for { - _, ok := it.Next() + _, ok := graph.Next(it) if !ok { break }