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

traversal.SkipMe feature #51

Merged
merged 1 commit into from
Mar 31, 2020
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
13 changes: 13 additions & 0 deletions traversal/fns.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,16 @@ type Config struct {
// could decide what kind of native type is expected, and return a
// `bind.NodeBuilder` for that specific concrete native type.
type LinkTargetNodeStyleChooser func(ipld.Link, ipld.LinkContext) (ipld.NodeStyle, error)

// SkipMe is a signalling "error" which can be used to tell traverse to skip some data.
//
// SkipMe can be returned by the Config.LinkLoader to skip entire blocks without aborting the walk.
// (This can be useful if you know you don't have data on hand,
// but want to continue the walk in other areas anyway;
// or, if you're doing a way where you know that it's valid to memoize seen
// areas based on Link alone.)
type SkipMe struct{}

func (SkipMe) Error() string {
return "skip"
}
11 changes: 11 additions & 0 deletions traversal/walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ func WalkTransforming(n ipld.Node, s selector.Selector, fn TransformFn) (ipld.No
// This is important to note because when walking DAGs with Links,
// it means you may visit the same node multiple times
// due to having reached it via a different path.
// (You can prevent this by using a LinkLoader function which memoizes a set of
// already-visited Links, and returns a SkipMe when encountering them again.)
//
// WalkMatching (and the other traversal functions) can be used again again inside the VisitFn!
// By using the traversal.Progress handed to the VisitFn,
Expand Down Expand Up @@ -122,6 +124,9 @@ func (prog Progress) walkAdv_iterateAll(n ipld.Node, s selector.Selector, fn Adv
progNext.LastBlock.Link = lnk
v, err = progNext.loadLink(v, n)
if err != nil {
if _, ok := err.(SkipMe); ok {
return nil
}
return err
}
}
Expand Down Expand Up @@ -151,6 +156,9 @@ func (prog Progress) walkAdv_iterateSelective(n ipld.Node, attn []ipld.PathSegme
progNext.LastBlock.Link = lnk
v, err = progNext.loadLink(v, n)
if err != nil {
if _, ok := err.(SkipMe); ok {
return nil
}
return err
}
}
Expand Down Expand Up @@ -189,6 +197,9 @@ func (prog Progress) loadLink(v ipld.Node, parent ipld.Node) (ipld.Node, error)
prog.Cfg.LinkLoader,
)
if err != nil {
if _, ok := err.(SkipMe); ok {
return nil, err
}
return nil, fmt.Errorf("error traversing node at %q: could not load link %q: %s", prog.Path, lnk, err)
}
return nb.Build(), nil
Expand Down