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  }