add Is, Follow, and All to the path API
This commit is contained in:
parent
3dc74329c0
commit
4128133675
2 changed files with 98 additions and 5 deletions
|
|
@ -32,6 +32,9 @@ type Path struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartPath(qs graph.QuadStore, nodes ...string) *Path {
|
func StartPath(qs graph.QuadStore, nodes ...string) *Path {
|
||||||
|
if len(nodes) == 0 {
|
||||||
|
return PathFromIterator(qs, qs.NodesAllIterator())
|
||||||
|
}
|
||||||
return &Path{
|
return &Path{
|
||||||
stack: []morphism{
|
stack: []morphism{
|
||||||
isMorphism(qs, nodes...),
|
isMorphism(qs, nodes...),
|
||||||
|
|
@ -43,7 +46,7 @@ func StartPath(qs graph.QuadStore, nodes ...string) *Path {
|
||||||
func PathFromIterator(qs graph.QuadStore, it graph.Iterator) *Path {
|
func PathFromIterator(qs graph.QuadStore, it graph.Iterator) *Path {
|
||||||
return &Path{
|
return &Path{
|
||||||
stack: []morphism{
|
stack: []morphism{
|
||||||
intersectIteratorMorphism(it),
|
iteratorMorphism(it),
|
||||||
},
|
},
|
||||||
qs: qs,
|
qs: qs,
|
||||||
}
|
}
|
||||||
|
|
@ -63,6 +66,11 @@ func (p *Path) Reverse() *Path {
|
||||||
return newPath
|
return newPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Path) Is(nodes ...string) *Path {
|
||||||
|
p.stack = append(p.stack, isMorphism(p.qs, nodes...))
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Path) Tag(tags ...string) *Path {
|
func (p *Path) Tag(tags ...string) *Path {
|
||||||
p.stack = append(p.stack, tagMorphism(tags...))
|
p.stack = append(p.stack, tagMorphism(tags...))
|
||||||
return p
|
return p
|
||||||
|
|
@ -87,6 +95,16 @@ func (p *Path) Or(path *Path) *Path {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Path) Follow(path *Path) *Path {
|
||||||
|
p.stack = append(p.stack, followMorphism(path))
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Path) FollowReverse(path *Path) *Path {
|
||||||
|
p.stack = append(p.stack, followMorphism(path.Reverse()))
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Path) BuildIterator() graph.Iterator {
|
func (p *Path) BuildIterator() graph.Iterator {
|
||||||
f := p.MorphismFunc()
|
f := p.MorphismFunc()
|
||||||
return f(p.qs.NodesAllIterator())
|
return f(p.qs.NodesAllIterator())
|
||||||
|
|
@ -149,10 +167,10 @@ func inMorphism(qs graph.QuadStore, via ...interface{}) morphism {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func intersectIteratorMorphism(it graph.Iterator) morphism {
|
func iteratorMorphism(it graph.Iterator) morphism {
|
||||||
return morphism{
|
return morphism{
|
||||||
"iterator",
|
"iterator",
|
||||||
func() morphism { return intersectIteratorMorphism(it) },
|
func() morphism { return iteratorMorphism(it) },
|
||||||
func(subIt graph.Iterator) graph.Iterator {
|
func(subIt graph.Iterator) graph.Iterator {
|
||||||
and := iterator.NewAnd()
|
and := iterator.NewAnd()
|
||||||
and.AddSubIterator(it)
|
and.AddSubIterator(it)
|
||||||
|
|
@ -190,6 +208,17 @@ func orMorphism(path *Path) morphism {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func followMorphism(path *Path) morphism {
|
||||||
|
return morphism{
|
||||||
|
"follow",
|
||||||
|
func() morphism { return followMorphism(path.Reverse()) },
|
||||||
|
func(base graph.Iterator) graph.Iterator {
|
||||||
|
p := path.MorphismFunc()
|
||||||
|
return p(base)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func inOutIterator(viaPath *Path, reverse bool) graph.MorphismFunc {
|
func inOutIterator(viaPath *Path, reverse bool) graph.MorphismFunc {
|
||||||
return func(base graph.Iterator) graph.Iterator {
|
return func(base graph.Iterator) graph.Iterator {
|
||||||
in, out := quad.Subject, quad.Object
|
in, out := quad.Subject, quad.Object
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,20 @@ import (
|
||||||
_ "github.com/google/cayley/writer"
|
_ "github.com/google/cayley/writer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// This is a simple test graph.
|
||||||
|
//
|
||||||
|
// +---+ +---+
|
||||||
|
// | A |------- ->| F |<--
|
||||||
|
// +---+ \------>+---+-/ +---+ \--+---+
|
||||||
|
// ------>|#B#| | | E |
|
||||||
|
// +---+-------/ >+---+ | +---+
|
||||||
|
// | C | / v
|
||||||
|
// +---+ -/ +---+
|
||||||
|
// ---- +---+/ |#G#|
|
||||||
|
// \-->|#D#|------------->+---+
|
||||||
|
// +---+
|
||||||
|
//
|
||||||
|
|
||||||
var simpleGraph = []quad.Quad{
|
var simpleGraph = []quad.Quad{
|
||||||
{"A", "follows", "B", ""},
|
{"A", "follows", "B", ""},
|
||||||
{"C", "follows", "B", ""},
|
{"C", "follows", "B", ""},
|
||||||
|
|
@ -62,10 +76,28 @@ func runTopLevel(path *Path) []string {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runTag(path *Path, tag string) []string {
|
||||||
|
var out []string
|
||||||
|
it := path.BuildIterator()
|
||||||
|
it, _ = it.Optimize()
|
||||||
|
for graph.Next(it) {
|
||||||
|
tags := make(map[string]graph.Value)
|
||||||
|
it.TagResults(tags)
|
||||||
|
out = append(out, path.qs.NameOf(tags[tag]))
|
||||||
|
for it.NextPath() {
|
||||||
|
tags := make(map[string]graph.Value)
|
||||||
|
it.TagResults(tags)
|
||||||
|
out = append(out, path.qs.NameOf(tags[tag]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
type test struct {
|
type test struct {
|
||||||
message string
|
message string
|
||||||
path *Path
|
path *Path
|
||||||
expect []string
|
expect []string
|
||||||
|
tag string
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSet(qs graph.QuadStore) []test {
|
func testSet(qs graph.QuadStore) []test {
|
||||||
|
|
@ -86,18 +118,50 @@ func testSet(qs graph.QuadStore) []test {
|
||||||
expect: []string{"F", "cool"},
|
expect: []string{"F", "cool"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
message: "in",
|
message: "use And",
|
||||||
path: StartPath(qs, "D").Out("follows").And(
|
path: StartPath(qs, "D").Out("follows").And(
|
||||||
StartPath(qs, "C").Out("follows")),
|
StartPath(qs, "C").Out("follows")),
|
||||||
expect: []string{"B"},
|
expect: []string{"B"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
message: "use Or",
|
||||||
|
path: StartPath(qs, "F").Out("follows").Or(
|
||||||
|
StartPath(qs, "A").Out("follows")),
|
||||||
|
expect: []string{"B", "G"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: "implicit All",
|
||||||
|
path: StartPath(qs),
|
||||||
|
expect: []string{"A", "B", "C", "D", "E", "F", "G", "follows", "status", "cool", "status_graph", "predicates", "are"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: "follow",
|
||||||
|
path: StartPath(qs, "C").Follow(StartPath(qs).Out("follows").Out("follows")),
|
||||||
|
expect: []string{"B", "F", "G"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: "followR",
|
||||||
|
path: StartPath(qs, "F").FollowReverse(StartPath(qs).Out("follows").Out("follows")),
|
||||||
|
expect: []string{"A", "C", "D"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: "is, tag, instead of FollowR",
|
||||||
|
path: StartPath(qs).Tag("first").Follow(StartPath(qs).Out("follows").Out("follows")).Is("F"),
|
||||||
|
expect: []string{"A", "C", "D"},
|
||||||
|
tag: "first",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMorphisms(t *testing.T) {
|
func TestMorphisms(t *testing.T) {
|
||||||
qs := makeTestStore(simpleGraph)
|
qs := makeTestStore(simpleGraph)
|
||||||
for _, test := range testSet(qs) {
|
for _, test := range testSet(qs) {
|
||||||
got := runTopLevel(test.path)
|
var got []string
|
||||||
|
if test.tag == "" {
|
||||||
|
got = runTopLevel(test.path)
|
||||||
|
} else {
|
||||||
|
got = runTag(test.path, test.tag)
|
||||||
|
}
|
||||||
sort.Strings(got)
|
sort.Strings(got)
|
||||||
sort.Strings(test.expect)
|
sort.Strings(test.expect)
|
||||||
if !reflect.DeepEqual(got, test.expect) {
|
if !reflect.DeepEqual(got, test.expect) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue