github.com/ipld/go-ipld-prime@v0.21.0/traversal/selector/condition.go (about) 1 package selector 2 3 import ( 4 "fmt" 5 6 "github.com/ipld/go-ipld-prime/datamodel" 7 cidlink "github.com/ipld/go-ipld-prime/linking/cid" 8 ) 9 10 // Condition provides a mechanism for matching and limiting matching and 11 // exploration of selectors. 12 // Not all types of conditions which are imagined in the selector specification 13 // are encoded at present, instead we currently only implement a subset that 14 // is sufficient for initial pressing use cases. 15 type Condition struct { 16 mode ConditionMode 17 match datamodel.Node 18 } 19 20 // A ConditionMode is the keyed representation for the union that is the condition 21 type ConditionMode string 22 23 const ( 24 ConditionMode_Link ConditionMode = "/" 25 ) 26 27 // Match decides if a given datamodel.Node matches the condition. 28 func (c *Condition) Match(n datamodel.Node) bool { 29 switch c.mode { 30 case ConditionMode_Link: 31 if n.Kind() != datamodel.Kind_Link { 32 return false 33 } 34 lnk, err := n.AsLink() 35 if err != nil { 36 return false 37 } 38 match, err := c.match.AsLink() 39 if err != nil { 40 return false 41 } 42 cidlnk, ok := lnk.(cidlink.Link) 43 cidmatch, ok2 := match.(cidlink.Link) 44 if ok && ok2 { 45 return cidmatch.Equals(cidlnk.Cid) 46 } 47 return match.String() == lnk.String() 48 default: 49 return false 50 } 51 } 52 53 // ParseCondition assembles a Condition from a condition selector node 54 func (pc ParseContext) ParseCondition(n datamodel.Node) (Condition, error) { 55 if n.Kind() != datamodel.Kind_Map { 56 return Condition{}, fmt.Errorf("selector spec parse rejected: condition body must be a map") 57 } 58 if n.Length() != 1 { 59 return Condition{}, fmt.Errorf("selector spec parse rejected: condition is a keyed union and thus must be single-entry map") 60 } 61 kn, v, _ := n.MapIterator().Next() 62 kstr, _ := kn.AsString() 63 // Switch over the single key to determine which condition body comes next. 64 // (This switch is where the keyed union discriminators concretely happen.) 65 switch ConditionMode(kstr) { 66 case ConditionMode_Link: 67 if _, err := v.AsLink(); err != nil { 68 return Condition{}, fmt.Errorf("selector spec parse rejected: condition_link must be a link") 69 } 70 return Condition{mode: ConditionMode_Link, match: v}, nil 71 default: 72 return Condition{}, fmt.Errorf("selector spec parse rejected: %q is not a known member of the condition union", kstr) 73 } 74 }