github.com/cayleygraph/cayley@v0.7.7/graph/shape/path.go (about)

     1  package shape
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/cayleygraph/cayley/graph"
     7  	"github.com/cayleygraph/cayley/graph/iterator"
     8  	"github.com/cayleygraph/quad"
     9  )
    10  
    11  func IntersectShapes(s1, s2 Shape) Shape {
    12  	switch s1 := s1.(type) {
    13  	case AllNodes:
    14  		return s2
    15  	case Intersect:
    16  		if s2, ok := s2.(Intersect); ok {
    17  			return append(s1, s2...)
    18  		}
    19  		return append(s1, s2)
    20  	}
    21  	return Intersect{s1, s2}
    22  }
    23  
    24  func IntersectOptional(s, opt Shape) Shape {
    25  	var optional []Shape
    26  	switch opt := opt.(type) {
    27  	case Intersect:
    28  		optional = []Shape(opt)
    29  	case IntersectOpt:
    30  		optional = make([]Shape, 0, len(opt.Sub)+len(opt.Opt))
    31  		optional = append(optional, opt.Sub...)
    32  		optional = append(optional, opt.Opt...)
    33  	default:
    34  		optional = []Shape{opt}
    35  	}
    36  	if len(optional) == 0 {
    37  		return s
    38  	}
    39  	switch s := s.(type) {
    40  	case Intersect:
    41  		return IntersectOpt{Sub: s, Opt: optional}
    42  	case IntersectOpt:
    43  		s.Opt = append(s.Opt, optional...)
    44  		return s
    45  	}
    46  	return IntersectOpt{Sub: Intersect{s}, Opt: optional}
    47  }
    48  
    49  func UnionShapes(s1, s2 Shape) Union {
    50  	if s1, ok := s1.(Union); ok {
    51  		if s2, ok := s2.(Union); ok {
    52  			return append(s1, s2...)
    53  		}
    54  		return append(s1, s2)
    55  	}
    56  	return Union{s1, s2}
    57  }
    58  
    59  func buildOut(from, via, labels Shape, tags []string, in bool) Shape {
    60  	start, goal := quad.Subject, quad.Object
    61  	if in {
    62  		start, goal = goal, start
    63  	}
    64  	if len(tags) != 0 {
    65  		via = Save{From: via, Tags: tags}
    66  	}
    67  
    68  	quads := make(Quads, 0, 3)
    69  	if _, ok := from.(AllNodes); !ok {
    70  		quads = append(quads, QuadFilter{
    71  			Dir: start, Values: from,
    72  		})
    73  	}
    74  	if _, ok := via.(AllNodes); !ok {
    75  		quads = append(quads, QuadFilter{
    76  			Dir: quad.Predicate, Values: via,
    77  		})
    78  	}
    79  	if labels != nil {
    80  		if _, ok := labels.(AllNodes); !ok {
    81  			quads = append(quads, QuadFilter{
    82  				Dir: quad.Label, Values: labels,
    83  			})
    84  		}
    85  	}
    86  	return NodesFrom{Quads: quads, Dir: goal}
    87  }
    88  
    89  func Out(from, via, labels Shape, tags ...string) Shape {
    90  	return buildOut(from, via, labels, tags, false)
    91  }
    92  
    93  func In(from, via, labels Shape, tags ...string) Shape {
    94  	return buildOut(from, via, labels, tags, true)
    95  }
    96  
    97  // InWithTags, OutWithTags, Both, BothWithTags
    98  
    99  func Predicates(from Shape, in bool) Shape {
   100  	dir := quad.Subject
   101  	if in {
   102  		dir = quad.Object
   103  	}
   104  	return Unique{NodesFrom{
   105  		Quads: Quads{
   106  			{Dir: dir, Values: from},
   107  		},
   108  		Dir: quad.Predicate,
   109  	}}
   110  }
   111  
   112  func SavePredicates(from Shape, in bool, tag string) Shape {
   113  	preds := Save{
   114  		From: AllNodes{},
   115  		Tags: []string{tag},
   116  	}
   117  	start := quad.Subject
   118  	if in {
   119  		start = quad.Object
   120  	}
   121  
   122  	var save Shape = NodesFrom{
   123  		Quads: Quads{
   124  			{Dir: quad.Predicate, Values: preds},
   125  		},
   126  		Dir: start,
   127  	}
   128  	return IntersectShapes(from, save)
   129  }
   130  
   131  func Labels(from Shape) Shape {
   132  	return Unique{NodesFrom{
   133  		Quads: Union{
   134  			Quads{
   135  				{Dir: quad.Subject, Values: from},
   136  			},
   137  			Quads{
   138  				{Dir: quad.Object, Values: from},
   139  			},
   140  		},
   141  		Dir: quad.Label,
   142  	}}
   143  }
   144  
   145  func SaveVia(from, via Shape, tag string, rev, opt bool) Shape {
   146  	return SaveViaLabels(from, via, AllNodes{}, tag, rev, opt)
   147  }
   148  
   149  func SaveViaLabels(from, via, labels Shape, tag string, rev, opt bool) Shape {
   150  	nodes := Save{
   151  		From: AllNodes{},
   152  		Tags: []string{tag},
   153  	}
   154  	start, goal := quad.Subject, quad.Object
   155  	if rev {
   156  		start, goal = goal, start
   157  	}
   158  
   159  	quads := Quads{
   160  		{Dir: goal, Values: nodes},
   161  		{Dir: quad.Predicate, Values: via},
   162  	}
   163  	if labels != nil {
   164  		if _, ok := labels.(AllNodes); !ok {
   165  			quads = append(quads, QuadFilter{
   166  				Dir: quad.Label, Values: labels,
   167  			})
   168  		}
   169  	}
   170  
   171  	var save Shape = NodesFrom{
   172  		Quads: quads,
   173  		Dir:   start,
   174  	}
   175  	if opt {
   176  		return IntersectOptional(from, save)
   177  	}
   178  	return IntersectShapes(from, save)
   179  }
   180  
   181  func Has(from, via, nodes Shape, rev bool) Shape {
   182  	return HasLabels(from, via, AllNodes{}, nodes, rev)
   183  }
   184  
   185  func HasLabels(from, via, nodes, labels Shape, rev bool) Shape {
   186  	start, goal := quad.Subject, quad.Object
   187  	if rev {
   188  		start, goal = goal, start
   189  	}
   190  
   191  	quads := make(Quads, 0, 3)
   192  	if _, ok := nodes.(AllNodes); !ok {
   193  		quads = append(quads, QuadFilter{
   194  			Dir: goal, Values: nodes,
   195  		})
   196  	}
   197  	if _, ok := via.(AllNodes); !ok {
   198  		quads = append(quads, QuadFilter{
   199  			Dir: quad.Predicate, Values: via,
   200  		})
   201  	}
   202  	if labels != nil {
   203  		if _, ok := labels.(AllNodes); !ok {
   204  			quads = append(quads, QuadFilter{
   205  				Dir: quad.Label, Values: labels,
   206  			})
   207  		}
   208  	}
   209  	if len(quads) == 0 {
   210  		panic("empty has")
   211  	}
   212  	return IntersectShapes(from, NodesFrom{
   213  		Quads: quads, Dir: start,
   214  	})
   215  }
   216  
   217  func AddFilters(nodes Shape, filters ...ValueFilter) Shape {
   218  	if len(filters) == 0 {
   219  		return nodes
   220  	}
   221  	if s, ok := nodes.(Filter); ok {
   222  		arr := make([]ValueFilter, 0, len(s.Filters)+len(filters))
   223  		arr = append(arr, s.Filters...)
   224  		arr = append(arr, filters...)
   225  		return Filter{From: s.From, Filters: arr}
   226  	}
   227  	if nodes == nil {
   228  		nodes = AllNodes{}
   229  	}
   230  	return Filter{
   231  		From:    nodes,
   232  		Filters: filters,
   233  	}
   234  }
   235  
   236  func Compare(nodes Shape, op iterator.Operator, v quad.Value) Shape {
   237  	return AddFilters(nodes, Comparison{Op: op, Val: v})
   238  }
   239  
   240  func Iterate(ctx context.Context, qs graph.QuadStore, s Shape) *graph.IterateChain {
   241  	it := BuildIterator(qs, s)
   242  	return graph.Iterate(ctx, it).On(qs)
   243  }