github.com/ipld/go-ipld-prime@v0.21.0/traversal/selector/exploreFields.go (about)

     1  package selector
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/ipld/go-ipld-prime/datamodel"
     7  )
     8  
     9  // ExploreFields traverses named fields in a map (or equivalently, struct, if
    10  // traversing on typed/schema nodes) and applies a next selector to the
    11  // reached nodes.
    12  //
    13  // Note that a concept of "ExplorePath" (e.g. "foo/bar/baz") can be represented
    14  // as a set of three nexted ExploreFields selectors, each specifying one field.
    15  // (For this reason, we don't have a special "ExplorePath" feature; use this.)
    16  //
    17  // ExploreFields also works for selecting specific elements out of a list;
    18  // if a "field" is a base-10 int, it will be coerced and do the right thing.
    19  // ExploreIndex or ExploreRange is more appropriate, however, and should be preferred.
    20  type ExploreFields struct {
    21  	selections map[string]Selector
    22  	interests  []datamodel.PathSegment // keys of above; already boxed as that's the only way we consume them
    23  }
    24  
    25  // Interests for ExploreFields are the fields listed in the selector node
    26  func (s ExploreFields) Interests() []datamodel.PathSegment {
    27  	return s.interests
    28  }
    29  
    30  // Explore returns the selector for the given path if it is a field in
    31  // the selector node or nil if not
    32  func (s ExploreFields) Explore(n datamodel.Node, p datamodel.PathSegment) (Selector, error) {
    33  	return s.selections[p.String()], nil
    34  }
    35  
    36  // Decide always returns false because this is not a matcher
    37  func (s ExploreFields) Decide(n datamodel.Node) bool {
    38  	return false
    39  }
    40  
    41  // Match always returns false because this is not a matcher
    42  func (s ExploreFields) Match(node datamodel.Node) (datamodel.Node, error) {
    43  	return nil, nil
    44  }
    45  
    46  // ParseExploreFields assembles a Selector
    47  // from a ExploreFields selector node
    48  func (pc ParseContext) ParseExploreFields(n datamodel.Node) (Selector, error) {
    49  	if n.Kind() != datamodel.Kind_Map {
    50  		return nil, fmt.Errorf("selector spec parse rejected: selector body must be a map")
    51  	}
    52  	fields, err := n.LookupByString(SelectorKey_Fields)
    53  	if err != nil {
    54  		return nil, fmt.Errorf("selector spec parse rejected: fields in ExploreFields selector must be present")
    55  	}
    56  	if fields.Kind() != datamodel.Kind_Map {
    57  		return nil, fmt.Errorf("selector spec parse rejected: fields in ExploreFields selector must be a map")
    58  	}
    59  	x := ExploreFields{
    60  		make(map[string]Selector, fields.Length()),
    61  		make([]datamodel.PathSegment, 0, fields.Length()),
    62  	}
    63  	for itr := fields.MapIterator(); !itr.Done(); {
    64  		kn, v, err := itr.Next()
    65  		if err != nil {
    66  			return nil, fmt.Errorf("error during selector spec parse: %w", err)
    67  		}
    68  
    69  		kstr, _ := kn.AsString()
    70  		x.interests = append(x.interests, datamodel.PathSegmentOfString(kstr))
    71  		x.selections[kstr], err = pc.ParseSelector(v)
    72  		if err != nil {
    73  			return nil, err
    74  		}
    75  	}
    76  	return x, nil
    77  }