From 97247ae40ff3406e25ba5e5cc9a6decfaff56ca0 Mon Sep 17 00:00:00 2001 From: Barak Michener Date: Wed, 28 Oct 2015 19:42:59 -0400 Subject: [PATCH] add InPredicates/OutPredicates --- graph/path/morphism_apply_functions.go | 22 ++++++++++++++++++++++ graph/path/path.go | 33 +++++++++++++++++++++++++++------ graph/path/path_test.go | 29 ++++++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 7 deletions(-) diff --git a/graph/path/morphism_apply_functions.go b/graph/path/morphism_apply_functions.go index c6b3800..e4160e6 100644 --- a/graph/path/morphism_apply_functions.go +++ b/graph/path/morphism_apply_functions.go @@ -137,6 +137,28 @@ func inMorphism(via ...interface{}) morphism { } } +// predicatesMorphism iterates to the uniqified set of predicates from +// the given set of nodes in the path. +func predicatesMorphism(isIn bool) morphism { + m := morphism{ + Name: "out_predicates", + Reversal: func() morphism { panic("not implemented: need a function from predicates to their associated edges") }, + Apply: func(qs graph.QuadStore, in graph.Iterator, ctx *context) (graph.Iterator, *context) { + dir := quad.Subject + if isIn { + dir = quad.Object + } + lto := iterator.NewLinksTo(qs, in, dir) + hasa := iterator.NewHasA(qs, lto, quad.Predicate) + return iterator.NewUnique(hasa), ctx + }, + } + if isIn { + m.Name = "in_predicates" + } + return m +} + // iteratorMorphism simply tacks the input iterator onto the chain. func iteratorMorphism(it graph.Iterator) morphism { return morphism{ diff --git a/graph/path/path.go b/graph/path/path.go index 54506ce..be7e8fd 100644 --- a/graph/path/path.go +++ b/graph/path/path.go @@ -98,11 +98,6 @@ func (p *Path) Tag(tags ...string) *Path { return p } -// As is a synonym for Tag. -func (p *Path) As(tags ...string) *Path { - return p.Tag(tags...) -} - // Out updates this Path to represent the nodes that are adjacent to the // current nodes, via the given outbound predicate. // @@ -131,6 +126,33 @@ func (p *Path) In(via ...interface{}) *Path { return p } +// InPredicates updates this path to represent the nodes of the valid inbound +// predicates from the current nodes. +// +// For example: +// // Returns a list of predicates valid from "bob" +// // +// // Will return []string{"follows"} if there are any things that "follow" Bob +// StartPath(qs, "bob").InPredicates() +func (p *Path) InPredicates() *Path { + p.stack = append(p.stack, predicatesMorphism(true)) + return p +} + +// OutPredicates updates this path to represent the nodes of the valid inbound +// predicates from the current nodes. +// +// For example: +// // Returns a list of predicates valid from "bob" +// // +// // Will return []string{"follows", "status"} if there are edges from "bob" +// // labelled "follows", and edges from "bob" that describe his "status". +// StartPath(qs, "bob").OutPredicates() +func (p *Path) OutPredicates() *Path { + p.stack = append(p.stack, predicatesMorphism(false)) + return p +} + // And updates the current Path to represent the nodes that match both the // current Path so far, and the given Path. func (p *Path) And(path *Path) *Path { @@ -221,7 +243,6 @@ func (p *Path) Back(tag string) *Path { newPath.stack = append(newPath.stack, p.stack[i].Reversal()) i-- } - } // BuildIterator returns an iterator from this given Path. Note that you must diff --git a/graph/path/path_test.go b/graph/path/path_test.go index bf22c16..ecae42d 100644 --- a/graph/path/path_test.go +++ b/graph/path/path_test.go @@ -108,6 +108,12 @@ type test struct { tag string } +// Define morphisms without a QuadStore + +var ( + grandfollows = StartMorphism().Out("follows").Out("follows") +) + func testSet(qs graph.QuadStore) []test { return []test{ { @@ -197,10 +203,31 @@ func testSet(qs graph.QuadStore) []test { }, { message: "do multiple .Back()s", - path: StartPath(qs, "emily").Out("follows").As("f").Out("follows").Out("status").Is("cool_person").Back("f").In("follows").In("follows").As("acd").Out("status").Is("cool_person").Back("f"), + path: StartPath(qs, "emily").Out("follows").Tag("f").Out("follows").Out("status").Is("cool_person").Back("f").In("follows").In("follows").Tag("acd").Out("status").Is("cool_person").Back("f"), tag: "acd", expect: []string{"dani"}, }, + { + message: "InPredicates()", + path: StartPath(qs, "bob").InPredicates(), + expect: []string{"follows"}, + }, + { + message: "OutPredicates()", + path: StartPath(qs, "bob").OutPredicates(), + expect: []string{"follows", "status"}, + }, + // Morphism tests + { + message: "show simple morphism", + path: StartPath(qs, "charlie").Follow(grandfollows), + expect: []string{"greg", "fred", "bob"}, + }, + { + message: "show reverse morphism", + path: StartPath(qs, "fred").FollowReverse(grandfollows), + expect: []string{"alice", "charlie", "dani"}, + }, } }