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":{">":{"@":{}}}}]}}}`))