Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
ld
go-ld-prime
Commits
5dfad59f
Commit
5dfad59f
authored
Aug 20, 2020
by
Eric Myhre
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add traversal.Get function.
parent
d3ccd3c3
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
71 additions
and
10 deletions
+71
-10
traversal/focus.go
traversal/focus.go
+51
-10
traversal/focus_test.go
traversal/focus_test.go
+20
-0
No files found.
traversal/focus.go
View file @
5dfad59f
...
...
@@ -17,6 +17,17 @@ func Focus(n ipld.Node, p ipld.Path, fn VisitFn) error {
return
Progress
{}
.
Focus
(
n
,
p
,
fn
)
}
// Get is the equivalent of Focus, but returns the reached node (rather than invoking a callback at the target),
// and does not yield Progress information.
//
// This function is a helper function which starts a new traversal with default configuration.
// It cannot cross links automatically (since this requires configuration).
// Use the equivalent Get function on the Progress structure
// for more advanced and configurable walks.
func
Get
(
n
ipld
.
Node
,
p
ipld
.
Path
)
(
ipld
.
Node
,
error
)
{
return
Progress
{}
.
Get
(
n
,
p
)
}
// FocusedTransform traverses an ipld.Node graph, reaches a single Node,
// and calls the given TransformFn to decide what new node to replace the visited node with.
// A new Node tree will be returned (the original is unchanged).
...
...
@@ -45,6 +56,32 @@ func FocusedTransform(n ipld.Node, p ipld.Path, fn TransformFn) (ipld.Node, erro
// the Path recorded of the traversal so far will continue to be extended,
// and thus continued nested uses of Walk and Focus will see the fully contextualized Path.
func
(
prog
Progress
)
Focus
(
n
ipld
.
Node
,
p
ipld
.
Path
,
fn
VisitFn
)
error
{
n
,
err
:=
prog
.
get
(
n
,
p
,
true
)
if
err
!=
nil
{
return
err
}
return
fn
(
prog
,
n
)
}
// Get is the equivalent of Focus, but returns the reached node (rather than invoking a callback at the target),
// and does not yield Progress information.
//
// Provide configuration to this process using the Config field in the Progress object.
//
// This walk will automatically cross links, but requires some configuration
// with link loading functions to do so.
//
// If doing several traversals which are nested, consider using the Focus funcion in preference to Get;
// the Focus functions provide updated Progress objects which can be used to do nested traversals while keeping consistent track of progress,
// such that continued nested uses of Walk or Focus or Get will see the fully contextualized Path.
func
(
prog
Progress
)
Get
(
n
ipld
.
Node
,
p
ipld
.
Path
)
(
ipld
.
Node
,
error
)
{
return
prog
.
get
(
n
,
p
,
false
)
}
// get is the internal implementation for Focus and Get.
// It *mutates* the Progress object it's called on, and returns reached nodes.
// For Get calls, trackProgress=false, which avoids some allocations for state tracking that's not needed by that call.
func
(
prog
*
Progress
)
get
(
n
ipld
.
Node
,
p
ipld
.
Path
,
trackProgress
bool
)
(
ipld
.
Node
,
error
)
{
prog
.
init
()
segments
:=
p
.
Segments
()
var
prev
ipld
.
Node
// for LinkContext
...
...
@@ -56,21 +93,21 @@ func (prog Progress) Focus(n ipld.Node, p ipld.Path, fn VisitFn) error {
case
ipld
.
ReprKind_Map
:
next
,
err
:=
n
.
LookupByString
(
seg
.
String
())
if
err
!=
nil
{
return
fmt
.
Errorf
(
"error traversing segment %q on node at %q: %s"
,
seg
,
p
.
Truncate
(
i
),
err
)
return
nil
,
fmt
.
Errorf
(
"error traversing segment %q on node at %q: %s"
,
seg
,
p
.
Truncate
(
i
),
err
)
}
prev
,
n
=
n
,
next
case
ipld
.
ReprKind_List
:
intSeg
,
err
:=
seg
.
Index
()
if
err
!=
nil
{
return
fmt
.
Errorf
(
"error traversing segment %q on node at %q: the segment cannot be parsed as a number and the node is a list"
,
seg
,
p
.
Truncate
(
i
))
return
nil
,
fmt
.
Errorf
(
"error traversing segment %q on node at %q: the segment cannot be parsed as a number and the node is a list"
,
seg
,
p
.
Truncate
(
i
))
}
next
,
err
:=
n
.
LookupByIndex
(
intSeg
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"error traversing segment %q on node at %q: %s"
,
seg
,
p
.
Truncate
(
i
),
err
)
return
nil
,
fmt
.
Errorf
(
"error traversing segment %q on node at %q: %s"
,
seg
,
p
.
Truncate
(
i
),
err
)
}
prev
,
n
=
n
,
next
default
:
return
fmt
.
Errorf
(
"cannot traverse node at %q: %s"
,
p
.
Truncate
(
i
),
fmt
.
Errorf
(
"cannot traverse terminals"
))
return
nil
,
fmt
.
Errorf
(
"cannot traverse node at %q: %s"
,
p
.
Truncate
(
i
),
fmt
.
Errorf
(
"cannot traverse terminals"
))
}
// Dereference any links.
for
n
.
ReprKind
()
==
ipld
.
ReprKind_Link
{
...
...
@@ -84,7 +121,7 @@ func (prog Progress) Focus(n ipld.Node, p ipld.Path, fn VisitFn) error {
// Pick what in-memory format we will build.
np
,
err
:=
prog
.
Cfg
.
LinkTargetNodePrototypeChooser
(
lnk
,
lnkCtx
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"error traversing node at %q: could not load link %q: %s"
,
p
.
Truncate
(
i
+
1
),
lnk
,
err
)
return
nil
,
fmt
.
Errorf
(
"error traversing node at %q: could not load link %q: %s"
,
p
.
Truncate
(
i
+
1
),
lnk
,
err
)
}
nb
:=
np
.
NewBuilder
()
// Load link!
...
...
@@ -95,15 +132,19 @@ func (prog Progress) Focus(n ipld.Node, p ipld.Path, fn VisitFn) error {
prog
.
Cfg
.
LinkLoader
,
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"error traversing node at %q: could not load link %q: %s"
,
p
.
Truncate
(
i
+
1
),
lnk
,
err
)
return
nil
,
fmt
.
Errorf
(
"error traversing node at %q: could not load link %q: %s"
,
p
.
Truncate
(
i
+
1
),
lnk
,
err
)
}
if
trackProgress
{
prog
.
LastBlock
.
Path
=
p
.
Truncate
(
i
+
1
)
prog
.
LastBlock
.
Link
=
lnk
}
prog
.
LastBlock
.
Path
=
p
.
Truncate
(
i
+
1
)
prog
.
LastBlock
.
Link
=
lnk
prev
,
n
=
n
,
nb
.
Build
()
}
}
prog
.
Path
=
prog
.
Path
.
Join
(
p
)
return
fn
(
prog
,
n
)
if
trackProgress
{
prog
.
Path
=
prog
.
Path
.
Join
(
p
)
}
return
n
,
nil
}
// FocusedTransform traverses an ipld.Node graph, reaches a single Node,
...
...
traversal/focus_test.go
View file @
5dfad59f
...
...
@@ -123,6 +123,26 @@ func TestFocusSingleTree(t *testing.T) {
})
}
// covers Get used on one already-loaded Node; no link-loading exercised.
// same fixtures as the test for Focus; just has fewer assertions, since Get does no progress tracking.
func
TestGetSingleTree
(
t
*
testing
.
T
)
{
t
.
Run
(
"empty path on scalar node returns start node"
,
func
(
t
*
testing
.
T
)
{
n
,
err
:=
traversal
.
Get
(
basicnode
.
NewString
(
"x"
),
ipld
.
Path
{})
Wish
(
t
,
err
,
ShouldEqual
,
nil
)
Wish
(
t
,
n
,
ShouldEqual
,
basicnode
.
NewString
(
"x"
))
})
t
.
Run
(
"one step path on map node works"
,
func
(
t
*
testing
.
T
)
{
n
,
err
:=
traversal
.
Get
(
middleMapNode
,
ipld
.
ParsePath
(
"foo"
))
Wish
(
t
,
err
,
ShouldEqual
,
nil
)
Wish
(
t
,
n
,
ShouldEqual
,
basicnode
.
NewBool
(
true
))
})
t
.
Run
(
"two step path on map node works"
,
func
(
t
*
testing
.
T
)
{
n
,
err
:=
traversal
.
Get
(
middleMapNode
,
ipld
.
ParsePath
(
"nested/nonlink"
))
Wish
(
t
,
err
,
ShouldEqual
,
nil
)
Wish
(
t
,
n
,
ShouldEqual
,
basicnode
.
NewString
(
"zoo"
))
})
}
func
TestFocusWithLinkLoading
(
t
*
testing
.
T
)
{
t
.
Run
(
"link traversal with no configured loader should fail"
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
"terminal link should fail"
,
func
(
t
*
testing
.
T
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment