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

     1  /*
     2  selectorparse package contains some helpful functions for parsing the serial form of Selectors.
     3  
     4  Some common selectors are also exported as pre-compiled variables,
     5  both for convenience of use and to be readable as examples.
     6  */
     7  package selectorparse
     8  
     9  import (
    10  	"strings"
    11  
    12  	"github.com/ipld/go-ipld-prime/codec/dagjson"
    13  	"github.com/ipld/go-ipld-prime/datamodel"
    14  	"github.com/ipld/go-ipld-prime/node/basicnode"
    15  	"github.com/ipld/go-ipld-prime/traversal/selector"
    16  )
    17  
    18  // ParseJSONSelector accepts a string of json which will be parsed as a selector,
    19  // and returns a datamodel.Node of the parsed Data Model.
    20  // The returned datamodel.Node is suitable to hand to `selector.CompileSelector`,
    21  // or, could be composed programmatically with other Data Model selector clauses
    22  // and then compiled later.
    23  //
    24  // The selector will be checked for compileability, and an error returned if it is not.
    25  func ParseJSONSelector(jsonStr string) (datamodel.Node, error) {
    26  	nb := basicnode.Prototype.Any.NewBuilder()
    27  	if err := dagjson.Decode(nb, strings.NewReader(jsonStr)); err != nil {
    28  		return nil, err
    29  	}
    30  	// Compile it, because that's where all of our error checking is right now.
    31  	// ... but throw that result away, because the point of this method is to return nodes that you can compose further.
    32  	// Ideally, we'd have just used Schemas for this check,
    33  	// which would be cheaper than running the full compile,
    34  	// and also more correct (because it would let us parse incomplete phrases that won't compile alone),
    35  	// but that's not currently how the Selectors code is implemented.  Future work!
    36  	n := nb.Build()
    37  	if _, err := selector.CompileSelector(n); err != nil {
    38  		return nil, err
    39  	}
    40  	return n, nil
    41  }
    42  
    43  // ParseJSONSelector accepts a string of json which will be parsed as a selector,
    44  // and returns a compiled and ready-to-run Selector.
    45  //
    46  // ParseJSONSelector is functionally equivalent to combining ParseJSONSelector and CompileSelector into one step.
    47  func ParseAndCompileJSONSelector(jsonStr string) (selector.Selector, error) {
    48  	nb := basicnode.Prototype.Any.NewBuilder()
    49  	if err := dagjson.Decode(nb, strings.NewReader(jsonStr)); err != nil {
    50  		return nil, err
    51  	}
    52  	if s, err := selector.CompileSelector(nb.Build()); err != nil {
    53  		return nil, err
    54  	} else {
    55  		return s, nil
    56  	}
    57  }
    58  
    59  func must(s datamodel.Node, e error) datamodel.Node {
    60  	if e != nil {
    61  		panic(e)
    62  	}
    63  	return s
    64  }
    65  
    66  // CommonSelector_MatchPoint is a selector that matches exactly one thing: the first node it touches.
    67  // It doesn't walk anywhere at all.
    68  //
    69  // This is not a very useful selector, but is an example of how selectors can be written.
    70  var CommonSelector_MatchPoint = must(ParseJSONSelector(`{".":{}}`))
    71  
    72  // CommonSelector_MatchChildren will examine the node it is applied to,
    73  // walk to each of its children, and match the children.
    74  // It does not recurse.
    75  // Note that the root node itself is visited (necessarily!) but it is not "matched".
    76  var CommonSelector_MatchChildren = must(ParseJSONSelector(`{"a":{">":{".":{}}}}`))
    77  
    78  // CommonSelector_ExploreAllRecursively is a selector that walks over a graph of data,
    79  // recursively, without limit (!) until it reaches every part of the graph.
    80  // (This is safe to assume will halt eventually, because in IPLD, we work with DAGs --
    81  // although it still may be a bad idea to do this in practice,
    82  // because you could accidentally do this on terabytes of linked data, and that would still take a while!)
    83  //
    84  // It does not actually _match_ anything at all.
    85  // That means if you're intercepting block loads (e.g. you're looking at calls to LinkSystem.StorageReadOpener), you'll see them;
    86  // and if you're using `traversal.AdvVisitFn`, you'll still hear about nodes visited during the exploration;
    87  // however, if you're using just `traversal.VisitFn`, nothing is considered "matched", so that callback will never be called.
    88  var CommonSelector_ExploreAllRecursively = must(ParseJSONSelector(`{"R":{"l":{"none":{}},":>":{"a":{">":{"@":{}}}}}}`))
    89  
    90  // CommonSelector_MatchAllRecursively is like CommonSelector_ExploreAllRecursively, but also matching everything it touches.
    91  // The first thing inside the recursion is an ExploreUnion clause (which means the selection continues with multiple logical paths);
    92  // the first thing inside that union clause is a Matcher clause;
    93  // the second thing inside that union is the ExploreAll clause, which gets us deeper, and then that contains the ExploreRecursiveEdge.
    94  var CommonSelector_MatchAllRecursively = must(ParseJSONSelector(`{"R":{"l":{"none":{}},":>":{"|":[{".":{}},{"a":{">":{"@":{}}}}]}}}`))