Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ExploreRecursive stopAt condition and add tests #229

Merged
merged 5 commits into from
Aug 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions traversal/selector/exploreAll.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ func (s ExploreAll) Interests() []ipld.PathSegment {
}

// Explore returns the node's selector for all fields
func (s ExploreAll) Explore(n ipld.Node, p ipld.PathSegment) Selector {
return s.next
func (s ExploreAll) Explore(n ipld.Node, p ipld.PathSegment) (Selector, error) {
return s.next, nil
}

// Decide always returns false because this is not a matcher
Expand Down
4 changes: 2 additions & 2 deletions traversal/selector/exploreFields.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ func (s ExploreFields) Interests() []ipld.PathSegment {

// Explore returns the selector for the given path if it is a field in
// the selector node or nil if not
func (s ExploreFields) Explore(n ipld.Node, p ipld.PathSegment) Selector {
return s.selections[p.String()]
func (s ExploreFields) Explore(n ipld.Node, p ipld.PathSegment) (Selector, error) {
return s.selections[p.String()], nil
}

// Decide always returns false because this is not a matcher
Expand Down
8 changes: 4 additions & 4 deletions traversal/selector/exploreIndex.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ func (s ExploreIndex) Interests() []ipld.PathSegment {

// Explore returns the node's selector if
// the path matches the index for this selector or nil if not
func (s ExploreIndex) Explore(n ipld.Node, p ipld.PathSegment) Selector {
func (s ExploreIndex) Explore(n ipld.Node, p ipld.PathSegment) (Selector, error) {
if n.Kind() != ipld.Kind_List {
return nil
return nil, nil
}
expectedIndex, expectedErr := p.Index()
actualIndex, actualErr := s.interest[0].Index()
if expectedErr != nil || actualErr != nil || expectedIndex != actualIndex {
return nil
return nil, nil
}
return s.next
return s.next, nil
}

// Decide always returns false because this is not a matcher
Expand Down
8 changes: 4 additions & 4 deletions traversal/selector/exploreIndex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func TestExploreIndexExplore(t *testing.T) {
s := ExploreIndex{Matcher{}, [1]ipld.PathSegment{ipld.PathSegmentOfInt(3)}}
t.Run("exploring should return nil unless node is a list", func(t *testing.T) {
n := fluent.MustBuildMap(basicnode.Prototype__Map{}, 0, func(na fluent.MapAssembler) {})
returnedSelector := s.Explore(n, ipld.PathSegmentOfInt(3))
returnedSelector, _ := s.Explore(n, ipld.PathSegmentOfInt(3))
Wish(t, returnedSelector, ShouldEqual, nil)
})
n := fluent.MustBuildList(basicnode.Prototype__List{}, 4, func(na fluent.ListAssembler) {
Expand All @@ -78,15 +78,15 @@ func TestExploreIndexExplore(t *testing.T) {
na.AssembleValue().AssignInt(3)
})
t.Run("exploring should return nil when given a path segment with a different index", func(t *testing.T) {
returnedSelector := s.Explore(n, ipld.PathSegmentOfInt(2))
returnedSelector, _ := s.Explore(n, ipld.PathSegmentOfInt(2))
Wish(t, returnedSelector, ShouldEqual, nil)
})
t.Run("exploring should return nil when given a path segment that isn't an index", func(t *testing.T) {
returnedSelector := s.Explore(n, ipld.PathSegmentOfString("cheese"))
returnedSelector, _ := s.Explore(n, ipld.PathSegmentOfString("cheese"))
Wish(t, returnedSelector, ShouldEqual, nil)
})
t.Run("exploring should return the next selector when given a path segment with the right index", func(t *testing.T) {
returnedSelector := s.Explore(n, ipld.PathSegmentOfInt(3))
returnedSelector, _ := s.Explore(n, ipld.PathSegmentOfInt(3))
Wish(t, returnedSelector, ShouldEqual, Matcher{})
})
}
10 changes: 5 additions & 5 deletions traversal/selector/exploreRange.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,18 @@ func (s ExploreRange) Interests() []ipld.PathSegment {

// Explore returns the node's selector if
// the path matches an index in the range of this selector
func (s ExploreRange) Explore(n ipld.Node, p ipld.PathSegment) Selector {
func (s ExploreRange) Explore(n ipld.Node, p ipld.PathSegment) (Selector, error) {
if n.Kind() != ipld.Kind_List {
return nil
return nil, nil
}
index, err := p.Index()
if err != nil {
return nil
return nil, nil
}
if index < s.start || index >= s.end {
return nil
return nil, nil
}
return s.next
return s.next, nil
}

// Decide always returns false because this is not a matcher
Expand Down
8 changes: 4 additions & 4 deletions traversal/selector/exploreRange_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func TestExploreRangeExplore(t *testing.T) {
s := ExploreRange{Matcher{}, 3, 4, []ipld.PathSegment{ipld.PathSegmentOfInt(3)}}
t.Run("exploring should return nil unless node is a list", func(t *testing.T) {
n := fluent.MustBuildMap(basicnode.Prototype__Map{}, 0, func(na fluent.MapAssembler) {})
returnedSelector := s.Explore(n, ipld.PathSegmentOfInt(3))
returnedSelector, _ := s.Explore(n, ipld.PathSegmentOfInt(3))
Wish(t, returnedSelector, ShouldEqual, nil)
})
n := fluent.MustBuildList(basicnode.Prototype__List{}, 4, func(na fluent.ListAssembler) {
Expand All @@ -116,15 +116,15 @@ func TestExploreRangeExplore(t *testing.T) {
na.AssembleValue().AssignInt(3)
})
t.Run("exploring should return nil when given a path segment out of range", func(t *testing.T) {
returnedSelector := s.Explore(n, ipld.PathSegmentOfInt(2))
returnedSelector, _ := s.Explore(n, ipld.PathSegmentOfInt(2))
Wish(t, returnedSelector, ShouldEqual, nil)
})
t.Run("exploring should return nil when given a path segment that isn't an index", func(t *testing.T) {
returnedSelector := s.Explore(n, ipld.PathSegmentOfString("cheese"))
returnedSelector, _ := s.Explore(n, ipld.PathSegmentOfString("cheese"))
Wish(t, returnedSelector, ShouldEqual, nil)
})
t.Run("exploring should return the next selector when given a path segment with index in range", func(t *testing.T) {
returnedSelector := s.Explore(n, ipld.PathSegmentOfInt(3))
returnedSelector, _ := s.Explore(n, ipld.PathSegmentOfInt(3))
Wish(t, returnedSelector, ShouldEqual, Matcher{})
})
}
24 changes: 15 additions & 9 deletions traversal/selector/exploreRecursive.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,28 +86,34 @@ func (s ExploreRecursive) Interests() []ipld.PathSegment {
}

// Explore returns the node's selector for all fields
func (s ExploreRecursive) Explore(n ipld.Node, p ipld.PathSegment) Selector {
if s.stopAt != nil && s.stopAt.Match(n) {
return nil
func (s ExploreRecursive) Explore(n ipld.Node, p ipld.PathSegment) (Selector, error) {
if s.stopAt != nil {
target, err := n.LookupBySegment(p)
if err != nil {
return nil, err
}
if s.stopAt.Match(target) {
return nil, nil
}
}

nextSelector := s.current.Explore(n, p)
nextSelector, _ := s.current.Explore(n, p)
limit := s.limit

if nextSelector == nil {
return nil
return nil, nil
}
if !s.hasRecursiveEdge(nextSelector) {
return ExploreRecursive{s.sequence, nextSelector, limit, s.stopAt}
return ExploreRecursive{s.sequence, nextSelector, limit, s.stopAt}, nil
}
switch limit.mode {
case RecursionLimit_Depth:
if limit.depth < 2 {
return s.replaceRecursiveEdge(nextSelector, nil)
return s.replaceRecursiveEdge(nextSelector, nil), nil
}
return ExploreRecursive{s.sequence, s.replaceRecursiveEdge(nextSelector, s.sequence), RecursionLimit{RecursionLimit_Depth, limit.depth - 1}, s.stopAt}
return ExploreRecursive{s.sequence, s.replaceRecursiveEdge(nextSelector, s.sequence), RecursionLimit{RecursionLimit_Depth, limit.depth - 1}, s.stopAt}, nil
case RecursionLimit_None:
return ExploreRecursive{s.sequence, s.replaceRecursiveEdge(nextSelector, s.sequence), limit, s.stopAt}
return ExploreRecursive{s.sequence, s.replaceRecursiveEdge(nextSelector, s.sequence), limit, s.stopAt}, nil
default:
panic("Unsupported recursion limit type")
}
Expand Down
2 changes: 1 addition & 1 deletion traversal/selector/exploreRecursiveEdge.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func (s ExploreRecursiveEdge) Interests() []ipld.PathSegment {
}

// Explore should ultimately never get called for an ExploreRecursiveEdge selector
func (s ExploreRecursiveEdge) Explore(n ipld.Node, p ipld.PathSegment) Selector {
func (s ExploreRecursiveEdge) Explore(n ipld.Node, p ipld.PathSegment) (Selector, error) {
panic("Traversed Explore Recursive Edge Node With No Parent")
}

Expand Down
62 changes: 31 additions & 31 deletions traversal/selector/exploreRecursive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,28 +202,28 @@ func TestExploreRecursiveExplore(t *testing.T) {
err := dagjson.Decode(nb, strings.NewReader(nodeString))
Wish(t, err, ShouldEqual, nil)
rn := nb.Build()
rs = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rn, err = rn.LookupByString("Parents")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rn, err = rn.LookupByIndex(0)
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))

rn, err = rn.LookupByString("Parents")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rn, err = rn.LookupByIndex(0)
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_Depth, maxDepth - 2}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rn, err = rn.LookupByString("Parents")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth - 2}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rn, err = rn.LookupByIndex(0)
Wish(t, rs, ShouldEqual, nil)
Wish(t, err, ShouldEqual, nil)
Expand Down Expand Up @@ -253,31 +253,31 @@ func TestExploreRecursiveExplore(t *testing.T) {
err := dagjson.Decode(nb, strings.NewReader(nodeString))
Wish(t, err, ShouldEqual, nil)
rn := nb.Build()
rs = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rn, err = rn.LookupByString("Parents")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_None, 0}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rn, err = rn.LookupByIndex(0)
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_None, 0}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rn, err = rn.LookupByString("Parents")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_None, 0}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rn, err = rn.LookupByIndex(0)
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_None, 0}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rn, err = rn.LookupByString("Parents")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_None, 0}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rn, err = rn.LookupByIndex(0)
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_None, 0}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rn, err = rn.LookupByString("Parents")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_None, 0}, nil})
Wish(t, err, ShouldEqual, nil)
Expand All @@ -296,11 +296,11 @@ func TestExploreRecursiveExplore(t *testing.T) {
err := dagjson.Decode(nb, strings.NewReader(nodeString))
Wish(t, err, ShouldEqual, nil)
rn := nb.Build()
rs = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rn, err = rn.LookupByString("Parents")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfInt(0))
Wish(t, rs, ShouldEqual, nil)
})
t.Run("exploring should work when there is nested recursion", func(t *testing.T) {
Expand Down Expand Up @@ -345,59 +345,59 @@ func TestExploreRecursiveExplore(t *testing.T) {
// traverse down Parent nodes
rn := n
rs = s
rs = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rn, err = rn.LookupByString("Parents")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rn, err = rn.LookupByIndex(0)
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rn, err = rn.LookupByString("Parents")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})
Wish(t, err, ShouldEqual, nil)

// traverse down top level Side tree (nested recursion)
rn = n
rs = s
rs = rs.Explore(rn, ipld.PathSegmentOfString("Side"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("Side"))
rn, err = rn.LookupByString("Side")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, ExploreRecursive{sideSelector, sideSelector, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil}, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfString("real"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("real"))
rn, err = rn.LookupByString("real")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, ExploreRecursive{sideSelector, sideSelector, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil}, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfString("apple"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("apple"))
rn, err = rn.LookupByString("apple")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, ExploreRecursive{sideSelector, sideSelector, RecursionLimit{RecursionLimit_Depth, maxDepth - 2}, nil}, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfString("sauce"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("sauce"))
rn, err = rn.LookupByString("sauce")
Wish(t, rs, ShouldEqual, nil)
Wish(t, err, ShouldEqual, nil)

// traverse once down Parent (top level recursion) then down Side tree (nested recursion)
rn = n
rs = s
rs = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rn, err = rn.LookupByString("Parents")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rn, err = rn.LookupByIndex(0)
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, subTree, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfString("Side"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("Side"))
rn, err = rn.LookupByString("Side")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, ExploreRecursive{sideSelector, sideSelector, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil}, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfString("cheese"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("cheese"))
rn, err = rn.LookupByString("cheese")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, ExploreRecursive{sideSelector, sideSelector, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil}, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfString("whiz"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("whiz"))
rn, err = rn.LookupByString("whiz")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, ExploreRecursive{sideSelector, sideSelector, RecursionLimit{RecursionLimit_Depth, maxDepth - 2}, nil}, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})
Wish(t, err, ShouldEqual, nil)
Expand Down Expand Up @@ -426,20 +426,20 @@ func TestExploreRecursiveExplore(t *testing.T) {
err := dagjson.Decode(nb, strings.NewReader(nodeString))
Wish(t, err, ShouldEqual, nil)
rn := nb.Build()
rs = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rn, err = rn.LookupByString("Parents")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rn, err = rn.LookupByIndex(0)
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, ExploreUnion{[]Selector{Matcher{}, subTree}}, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfString("Parents"))

rn, err = rn.LookupByString("Parents")
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, parentsSelector, RecursionLimit{RecursionLimit_Depth, maxDepth - 1}, nil})
Wish(t, err, ShouldEqual, nil)
rs = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rs, _ = rs.Explore(rn, ipld.PathSegmentOfInt(0))
rn, err = rn.LookupByIndex(0)
Wish(t, rs, ShouldEqual, ExploreRecursive{subTree, ExploreUnion{[]Selector{Matcher{}, subTree}}, RecursionLimit{RecursionLimit_Depth, maxDepth - 2}, nil})
Wish(t, err, ShouldEqual, nil)
Expand Down
13 changes: 8 additions & 5 deletions traversal/selector/exploreUnion.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,25 @@ func (s ExploreUnion) Interests() []ipld.PathSegment {
// - a new union selector if more than one member returns a selector
// - if exactly one member returns a selector, that selector
// - nil if no members return a selector
func (s ExploreUnion) Explore(n ipld.Node, p ipld.PathSegment) Selector {
func (s ExploreUnion) Explore(n ipld.Node, p ipld.PathSegment) (Selector, error) {
// TODO: memory efficient?
nonNilResults := make([]Selector, 0, len(s.Members))
for _, member := range s.Members {
resultSelector := member.Explore(n, p)
resultSelector, err := member.Explore(n, p)
if err != nil {
return nil, err
}
if resultSelector != nil {
nonNilResults = append(nonNilResults, resultSelector)
}
}
if len(nonNilResults) == 0 {
return nil
return nil, nil
}
if len(nonNilResults) == 1 {
return nonNilResults[0]
return nonNilResults[0], nil
}
return ExploreUnion{nonNilResults}
return ExploreUnion{nonNilResults}, nil
}

// Decide returns true for a Union selector if any of the member selectors
Expand Down
Loading