9
9
"github.com/ipld/go-ipld-prime/traversal/selector"
10
10
)
11
11
12
+ type loadLinkFn func (prog Progress , ps datamodel.PathSegment , v datamodel.Node , parent datamodel.Node ) (datamodel.Node , error )
13
+
12
14
// WalkLocal walks a tree of Nodes, visiting each of them,
13
15
// and calling the given VisitFn on all of them;
14
16
// it does not traverse any links.
@@ -79,7 +81,7 @@ func WalkTransforming(n datamodel.Node, s selector.Selector, fn TransformFn) (da
79
81
// and thus continued nested uses of Walk and Focus will see the fully contextualized Path.
80
82
func (prog Progress ) WalkMatching (n datamodel.Node , s selector.Selector , fn VisitFn ) error {
81
83
prog .init ()
82
- return prog .walkAdv (n , s , func (prog Progress , n datamodel.Node , tr VisitReason ) error {
84
+ return prog .walkAdv (nil , n , s , func (prog Progress , n datamodel.Node , tr VisitReason ) error {
83
85
if tr != VisitReason_SelectionMatch {
84
86
return nil
85
87
}
@@ -143,10 +145,10 @@ func (prog Progress) WalkLocal(n datamodel.Node, fn VisitFn) error {
143
145
// An AdvVisitFn is used instead of a VisitFn, so that the reason can be provided.
144
146
func (prog Progress ) WalkAdv (n datamodel.Node , s selector.Selector , fn AdvVisitFn ) error {
145
147
prog .init ()
146
- return prog .walkAdv (n , s , fn )
148
+ return prog .walkAdv (nil , n , s , fn )
147
149
}
148
150
149
- func (prog Progress ) walkAdv (n datamodel.Node , s selector.Selector , fn AdvVisitFn ) error {
151
+ func (prog Progress ) walkAdv (loadLink loadLinkFn , n datamodel.Node , s selector.Selector , fn AdvVisitFn ) error {
150
152
// Check the budget!
151
153
if prog .Budget != nil {
152
154
if prog .Budget .NodeBudget <= 0 {
@@ -195,25 +197,67 @@ func (prog Progress) walkAdv(n datamodel.Node, s selector.Selector, fn AdvVisitF
195
197
}
196
198
}
197
199
}
200
+
198
201
// If we're handling scalars (e.g. not maps and lists) we can return now.
199
- nk := n .Kind ()
200
- switch nk {
201
- case datamodel .Kind_Map , datamodel .Kind_List : // continue
202
- default :
202
+ if n .Kind () != datamodel .Kind_Map && n .Kind () != datamodel .Kind_List {
203
203
return nil
204
204
}
205
+
205
206
// For maps and lists: recurse (in one of two ways, depending on if the selector also states specific interests).
206
207
attn := s .Interests ()
207
- if attn == nil {
208
- return prog .walkAdv_iterateAll (n , s , fn )
209
- }
210
- if len (attn ) == 0 {
208
+ if attn != nil && len (attn ) == 0 {
211
209
return nil
212
210
}
213
- return prog .walkAdv_iterateSelective (n , attn , s , fn )
211
+
212
+ if loadLink == nil {
213
+ loadLink = loadLinkActual
214
+ if prog .Cfg .Preloader != nil {
215
+ preProg := prog
216
+ // TODO: handle preProg.Budget .. somehow
217
+ // TODO: handle preProg.SeenLinks .. somehow
218
+ preloadLinks := make ([]preload.Link , 0 )
219
+ preProg .SeenLinks = make (map [datamodel.Link ]struct {})
220
+ loadLinkCollect := func (prog Progress , ps datamodel.PathSegment , v datamodel.Node , parent datamodel.Node ) (datamodel.Node , error ) {
221
+ lnk , err := v .AsLink ()
222
+ if err != nil {
223
+ return nil , err
224
+ }
225
+ preloadLinks = append (preloadLinks , preload.Link {
226
+ Segment : ps ,
227
+ LinkNode : v ,
228
+ Link : lnk ,
229
+ })
230
+ return nil , SkipMe {}
231
+ }
232
+
233
+ // traversal preload
234
+ noopVisitor := func (prog Progress , n datamodel.Node , reason VisitReason ) error { return nil }
235
+ if attn != nil {
236
+ if err := preProg .walkAdv_iterateSelective (loadLinkCollect , n , attn , s , noopVisitor ); err != nil {
237
+ return err
238
+ }
239
+ } else {
240
+ if err := preProg .walkAdv_iterateAll (loadLinkCollect , n , s , noopVisitor ); err != nil {
241
+ return err
242
+ }
243
+ }
244
+
245
+ prog .Cfg .Preloader (preload.PreloadContext {
246
+ Ctx : prog .Cfg .Ctx ,
247
+ BasePath : prog .Path ,
248
+ ParentNode : n ,
249
+ }, preloadLinks )
250
+ }
251
+ }
252
+
253
+ // traversal actual
254
+ if attn != nil {
255
+ return prog .walkAdv_iterateSelective (loadLink , n , attn , s , fn )
256
+ }
257
+ return prog .walkAdv_iterateAll (loadLink , n , s , fn )
214
258
}
215
259
216
- func (prog Progress ) iterateAll ( n datamodel.Node , visit func (datamodel. PathSegment , datamodel. Node , bool ) error ) error {
260
+ func (prog Progress ) walkAdv_iterateAll ( loadLink loadLinkFn , n datamodel.Node , s selector. Selector , fn AdvVisitFn ) error {
217
261
var reachedStartAtPath bool
218
262
for itr := selector .NewSegmentIterator (n ); ! itr .Done (); {
219
263
if reachedStartAtPath {
@@ -231,81 +275,46 @@ func (prog Progress) iterateAll(n datamodel.Node, visit func(datamodel.PathSegme
231
275
continue
232
276
}
233
277
}
234
- err = visit (ps , v , prog .PastStartAtPath )
235
- if err != nil {
236
- return err
237
- }
238
- }
239
- return nil
240
- }
241
-
242
- func (prog Progress ) walkAdv_iterateAll (n datamodel.Node , s selector.Selector , fn AdvVisitFn ) error {
243
- nextSelectors := make ([]selector.Selector , 0 , n .Length ())
244
- preloadLinks := make ([]preload.Link , 0 , n .Length ())
245
- err := prog .iterateAll (n , func (ps datamodel.PathSegment , v datamodel.Node , pastStartAtPath bool ) error {
246
278
sNext , err := s .Explore (n , ps )
247
279
if err != nil {
248
280
return err
249
281
}
250
- nextSelectors = append (nextSelectors , sNext )
251
- if sNext != nil && v .Kind () == datamodel .Kind_Link {
252
- lnk , _ := v .AsLink ()
253
- preloadLinks = append (preloadLinks , preload.Link {
254
- Segment : ps ,
255
- LinkNode : v ,
256
- Link : lnk ,
257
- })
258
- }
259
- return nil
260
- })
261
- if err != nil {
262
- return err
263
- }
264
- if prog .Cfg .Preloader != nil && len (preloadLinks ) > 0 {
265
- prog .Cfg .Preloader (preload.PreloadContext {
266
- Ctx : prog .Cfg .Ctx ,
267
- BasePath : prog .Path ,
268
- ParentNode : n ,
269
- }, preloadLinks )
270
- }
271
-
272
- index := 0
273
- return prog .iterateAll (n , func (ps datamodel.PathSegment , v datamodel.Node , pastStartAtPath bool ) error {
274
- var err error
275
- sNext := nextSelectors [index ]
276
- index ++
277
- if sNext == nil {
278
- return nil
279
- }
280
- progNext := prog
281
- if pastStartAtPath {
282
- progNext .PastStartAtPath = true
283
- }
284
- progNext .Path = prog .Path .AppendSegment (ps )
285
- if v .Kind () == datamodel .Kind_Link {
286
- lnk , _ := v .AsLink ()
287
- if prog .Cfg .LinkVisitOnlyOnce {
288
- if _ , seen := prog .SeenLinks [lnk ]; seen {
289
- return nil
282
+ if sNext != nil {
283
+ progNext := prog
284
+ progNext .Path = prog .Path .AppendSegment (ps )
285
+ if v .Kind () == datamodel .Kind_Link {
286
+ lnk , _ := v .AsLink ()
287
+ if prog .Cfg .LinkVisitOnlyOnce {
288
+ if _ , seen := prog .SeenLinks [lnk ]; seen {
289
+ continue
290
+ }
291
+ prog .SeenLinks [lnk ] = struct {}{}
290
292
}
291
- prog .SeenLinks [lnk ] = struct {}{}
292
- }
293
- progNext .LastBlock .Path = progNext .Path
294
- progNext .LastBlock .Link = lnk
295
- v , err = progNext .loadLink (v , n )
296
- if err != nil {
297
- if _ , ok := err .(SkipMe ); ok {
298
- return nil
293
+ progNext .LastBlock .Path = progNext .Path
294
+ progNext .LastBlock .Link = lnk
295
+ v , err = loadLink (progNext , ps , v , n )
296
+ if err != nil {
297
+ if _ , ok := err .(SkipMe ); ok {
298
+ continue
299
+ }
300
+ return err
301
+ }
302
+ err = progNext .walkAdv (nil , v , sNext , fn )
303
+ if err != nil {
304
+ return err
305
+ }
306
+ } else {
307
+ err = progNext .walkAdv (loadLink , v , sNext , fn )
308
+ if err != nil {
309
+ return err
299
310
}
300
- return err
301
311
}
302
312
}
303
-
304
- return progNext .walkAdv (v , sNext , fn )
305
- })
313
+ }
314
+ return nil
306
315
}
307
316
308
- func (prog Progress ) iterateSelective ( n datamodel.Node , attn []datamodel.PathSegment , visit func ( ps datamodel. PathSegment , v datamodel. Node ) error ) error {
317
+ func (prog Progress ) walkAdv_iterateSelective ( loadLink loadLinkFn , n datamodel.Node , attn []datamodel.PathSegment , s selector. Selector , fn AdvVisitFn ) error {
309
318
var reachedStartAtPath bool
310
319
for _ , ps := range attn {
311
320
if prog .Path .Len () < prog .Cfg .StartAtPath .Len () {
@@ -320,78 +329,46 @@ func (prog Progress) iterateSelective(n datamodel.Node, attn []datamodel.PathSeg
320
329
if err != nil {
321
330
continue
322
331
}
323
- err = visit (ps , v )
324
- if err != nil {
325
- return err
326
- }
327
- }
328
- return nil
329
- }
330
-
331
- func (prog Progress ) walkAdv_iterateSelective (n datamodel.Node , attn []datamodel.PathSegment , s selector.Selector , fn AdvVisitFn ) error {
332
- nextSelectors := make ([]selector.Selector , 0 , len (attn ))
333
- preloadLinks := make ([]preload.Link , 0 , len (attn ))
334
- err := prog .iterateSelective (n , attn , func (ps datamodel.PathSegment , v datamodel.Node ) error {
335
332
sNext , err := s .Explore (n , ps )
336
333
if err != nil {
337
334
return err
338
335
}
339
- nextSelectors = append (nextSelectors , sNext )
340
- if sNext != nil && v .Kind () == datamodel .Kind_Link {
341
- lnk , _ := v .AsLink ()
342
- preloadLinks = append (preloadLinks , preload.Link {
343
- Segment : ps ,
344
- LinkNode : v ,
345
- Link : lnk ,
346
- })
347
- }
348
- return nil
349
- })
350
- if err != nil {
351
- return err
352
- }
353
- if prog .Cfg .Preloader != nil && len (preloadLinks ) > 0 {
354
- prog .Cfg .Preloader (preload.PreloadContext {
355
- Ctx : prog .Cfg .Ctx ,
356
- BasePath : prog .Path ,
357
- ParentNode : n ,
358
- }, preloadLinks )
359
- }
360
-
361
- index := 0
362
- return prog .iterateSelective (n , attn , func (ps datamodel.PathSegment , v datamodel.Node ) error {
363
- var err error
364
- sNext := nextSelectors [index ]
365
- index ++
366
- if sNext == nil {
367
- return nil
368
- }
369
- progNext := prog
370
- progNext .Path = prog .Path .AppendSegment (ps )
371
- if v .Kind () == datamodel .Kind_Link {
372
- lnk , _ := v .AsLink ()
373
- if prog .Cfg .LinkVisitOnlyOnce {
374
- if _ , seen := prog .SeenLinks [lnk ]; seen {
375
- return nil
336
+ if sNext != nil {
337
+ progNext := prog
338
+ progNext .Path = prog .Path .AppendSegment (ps )
339
+ if v .Kind () == datamodel .Kind_Link {
340
+ lnk , _ := v .AsLink ()
341
+ if prog .Cfg .LinkVisitOnlyOnce {
342
+ if _ , seen := prog .SeenLinks [lnk ]; seen {
343
+ continue
344
+ }
345
+ prog .SeenLinks [lnk ] = struct {}{}
376
346
}
377
- prog .SeenLinks [lnk ] = struct {}{}
378
- }
379
- progNext .LastBlock .Path = progNext .Path
380
- progNext .LastBlock .Link = lnk
381
- v , err = progNext .loadLink (v , n )
382
- if err != nil {
383
- if _ , ok := err .(SkipMe ); ok {
384
- return nil
347
+ progNext .LastBlock .Path = progNext .Path
348
+ progNext .LastBlock .Link = lnk
349
+ v , err = loadLink (progNext , ps , v , n )
350
+ if err != nil {
351
+ if _ , ok := err .(SkipMe ); ok {
352
+ continue
353
+ }
354
+ return err
355
+ }
356
+ err = progNext .walkAdv (nil , v , sNext , fn )
357
+ if err != nil {
358
+ return err
359
+ }
360
+ } else {
361
+ err = progNext .walkAdv (loadLink , v , sNext , fn )
362
+ if err != nil {
363
+ return err
385
364
}
386
- return err
387
365
}
388
366
}
389
-
390
- return progNext .walkAdv (v , sNext , fn )
391
- })
367
+ }
368
+ return nil
392
369
}
393
370
394
- func (prog Progress ) loadLink ( v datamodel.Node , parent datamodel.Node ) (datamodel.Node , error ) {
371
+ func loadLinkActual (prog Progress , ps datamodel. PathSegment , v datamodel.Node , parent datamodel.Node ) (datamodel.Node , error ) {
395
372
lnk , err := v .AsLink ()
396
373
if err != nil {
397
374
return nil , err
@@ -496,9 +473,9 @@ func (prog Progress) walkTransforming(n datamodel.Node, s selector.Selector, fn
496
473
nk := n .Kind ()
497
474
switch nk {
498
475
case datamodel .Kind_List :
499
- return prog .walk_transform_iterateList (n , s , fn , s .Interests ())
476
+ return prog .walk_transform_iterateList (loadLinkActual , n , s , fn , s .Interests ())
500
477
case datamodel .Kind_Map :
501
- return prog .walk_transform_iterateMap (n , s , fn , s .Interests ())
478
+ return prog .walk_transform_iterateMap (loadLinkActual , n , s , fn , s .Interests ())
502
479
default :
503
480
return n , nil
504
481
}
@@ -513,7 +490,7 @@ func contains(interest []datamodel.PathSegment, candidate datamodel.PathSegment)
513
490
return false
514
491
}
515
492
516
- func (prog Progress ) walk_transform_iterateList (n datamodel.Node , s selector.Selector , fn TransformFn , attn []datamodel.PathSegment ) (datamodel.Node , error ) {
493
+ func (prog Progress ) walk_transform_iterateList (loadLink loadLinkFn , n datamodel.Node , s selector.Selector , fn TransformFn , attn []datamodel.PathSegment ) (datamodel.Node , error ) {
517
494
bldr := n .Prototype ().NewBuilder ()
518
495
lstBldr , err := bldr .BeginList (n .Length ())
519
496
if err != nil {
@@ -542,7 +519,7 @@ func (prog Progress) walk_transform_iterateList(n datamodel.Node, s selector.Sel
542
519
}
543
520
progNext .LastBlock .Path = progNext .Path
544
521
progNext .LastBlock .Link = lnk
545
- v , err = progNext . loadLink (v , n )
522
+ v , err = loadLink (progNext , ps , v , n )
546
523
if err != nil {
547
524
if _ , ok := err .(SkipMe ); ok {
548
525
continue
@@ -575,7 +552,7 @@ func (prog Progress) walk_transform_iterateList(n datamodel.Node, s selector.Sel
575
552
return bldr .Build (), nil
576
553
}
577
554
578
- func (prog Progress ) walk_transform_iterateMap (n datamodel.Node , s selector.Selector , fn TransformFn , attn []datamodel.PathSegment ) (datamodel.Node , error ) {
555
+ func (prog Progress ) walk_transform_iterateMap (loadLink loadLinkFn , n datamodel.Node , s selector.Selector , fn TransformFn , attn []datamodel.PathSegment ) (datamodel.Node , error ) {
579
556
bldr := n .Prototype ().NewBuilder ()
580
557
mapBldr , err := bldr .BeginMap (n .Length ())
581
558
if err != nil {
@@ -609,7 +586,7 @@ func (prog Progress) walk_transform_iterateMap(n datamodel.Node, s selector.Sele
609
586
}
610
587
progNext .LastBlock .Path = progNext .Path
611
588
progNext .LastBlock .Link = lnk
612
- v , err = progNext . loadLink (v , n )
589
+ v , err = loadLink (progNext , ps , v , n )
613
590
if err != nil {
614
591
if _ , ok := err .(SkipMe ); ok {
615
592
continue
0 commit comments