document path context, pipe it through Reversal() as well, and update the godoc
This commit is contained in:
parent
f74051a520
commit
3d286f5245
2 changed files with 64 additions and 35 deletions
|
|
@ -38,7 +38,7 @@ func join(qs graph.QuadStore, itL, itR graph.Iterator) graph.Iterator {
|
|||
func isMorphism(nodes ...string) morphism {
|
||||
return morphism{
|
||||
Name: "is",
|
||||
Reversal: func() morphism { return isMorphism(nodes...) },
|
||||
Reversal: func(ctx *context) (morphism, *context) { return isMorphism(nodes...), ctx },
|
||||
Apply: func(qs graph.QuadStore, in graph.Iterator, ctx *context) (graph.Iterator, *context) {
|
||||
if len(nodes) == 0 {
|
||||
// Acting as a passthrough here is equivalent to
|
||||
|
|
@ -64,7 +64,7 @@ func isMorphism(nodes ...string) morphism {
|
|||
func hasMorphism(via interface{}, nodes ...string) morphism {
|
||||
return morphism{
|
||||
Name: "has",
|
||||
Reversal: func() morphism { return hasMorphism(via, nodes...) },
|
||||
Reversal: func(ctx *context) (morphism, *context) { return hasMorphism(via, nodes...), ctx },
|
||||
Apply: func(qs graph.QuadStore, in graph.Iterator, ctx *context) (graph.Iterator, *context) {
|
||||
viaIter := buildViaPath(qs, via).
|
||||
BuildIterator()
|
||||
|
|
@ -104,7 +104,7 @@ func hasMorphism(via interface{}, nodes ...string) morphism {
|
|||
func tagMorphism(tags ...string) morphism {
|
||||
return morphism{
|
||||
Name: "tag",
|
||||
Reversal: func() morphism { return tagMorphism(tags...) },
|
||||
Reversal: func(ctx *context) (morphism, *context) { return tagMorphism(tags...), ctx },
|
||||
Apply: func(qs graph.QuadStore, in graph.Iterator, ctx *context) (graph.Iterator, *context) {
|
||||
for _, t := range tags {
|
||||
in.Tagger().Add(t)
|
||||
|
|
@ -119,7 +119,7 @@ func tagMorphism(tags ...string) morphism {
|
|||
func outMorphism(tags []string, via ...interface{}) morphism {
|
||||
return morphism{
|
||||
Name: "out",
|
||||
Reversal: func() morphism { return inMorphism(tags, via...) },
|
||||
Reversal: func(ctx *context) (morphism, *context) { return inMorphism(tags, via...), ctx },
|
||||
Apply: func(qs graph.QuadStore, in graph.Iterator, ctx *context) (graph.Iterator, *context) {
|
||||
path := buildViaPath(qs, via...)
|
||||
return inOutIterator(path, in, false, tags), ctx
|
||||
|
|
@ -131,7 +131,7 @@ func outMorphism(tags []string, via ...interface{}) morphism {
|
|||
func inMorphism(tags []string, via ...interface{}) morphism {
|
||||
return morphism{
|
||||
Name: "in",
|
||||
Reversal: func() morphism { return outMorphism(tags, via...) },
|
||||
Reversal: func(ctx *context) (morphism, *context) { return outMorphism(tags, via...), ctx },
|
||||
Apply: func(qs graph.QuadStore, in graph.Iterator, ctx *context) (graph.Iterator, *context) {
|
||||
path := buildViaPath(qs, via...)
|
||||
return inOutIterator(path, in, true, tags), ctx
|
||||
|
|
@ -142,7 +142,7 @@ func inMorphism(tags []string, via ...interface{}) morphism {
|
|||
func bothMorphism(tags []string, via ...interface{}) morphism {
|
||||
return morphism{
|
||||
Name: "in",
|
||||
Reversal: func() morphism { return bothMorphism(tags, via...) },
|
||||
Reversal: func(ctx *context) (morphism, *context) { return bothMorphism(tags, via...), ctx },
|
||||
Apply: func(qs graph.QuadStore, in graph.Iterator, ctx *context) (graph.Iterator, *context) {
|
||||
path := buildViaPath(qs, via...)
|
||||
inSide := inOutIterator(path, in, true, tags)
|
||||
|
|
@ -159,8 +159,10 @@ func bothMorphism(tags []string, via ...interface{}) morphism {
|
|||
// 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") },
|
||||
Name: "out_predicates",
|
||||
Reversal: func(ctx *context) (morphism, *context) {
|
||||
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 {
|
||||
|
|
@ -181,7 +183,7 @@ func predicatesMorphism(isIn bool) morphism {
|
|||
func iteratorMorphism(it graph.Iterator) morphism {
|
||||
return morphism{
|
||||
Name: "iterator",
|
||||
Reversal: func() morphism { return iteratorMorphism(it) },
|
||||
Reversal: func(ctx *context) (morphism, *context) { return iteratorMorphism(it), ctx },
|
||||
Apply: func(qs graph.QuadStore, in graph.Iterator, ctx *context) (graph.Iterator, *context) {
|
||||
return join(qs, it, in), ctx
|
||||
},
|
||||
|
|
@ -192,7 +194,7 @@ func iteratorMorphism(it graph.Iterator) morphism {
|
|||
func andMorphism(p *Path) morphism {
|
||||
return morphism{
|
||||
Name: "and",
|
||||
Reversal: func() morphism { return andMorphism(p) },
|
||||
Reversal: func(ctx *context) (morphism, *context) { return andMorphism(p), ctx },
|
||||
Apply: func(qs graph.QuadStore, in graph.Iterator, ctx *context) (graph.Iterator, *context) {
|
||||
itR := p.BuildIteratorOn(qs)
|
||||
|
||||
|
|
@ -205,7 +207,7 @@ func andMorphism(p *Path) morphism {
|
|||
func orMorphism(p *Path) morphism {
|
||||
return morphism{
|
||||
Name: "or",
|
||||
Reversal: func() morphism { return orMorphism(p) },
|
||||
Reversal: func(ctx *context) (morphism, *context) { return orMorphism(p), ctx },
|
||||
Apply: func(qs graph.QuadStore, in graph.Iterator, ctx *context) (graph.Iterator, *context) {
|
||||
itR := p.BuildIteratorOn(qs)
|
||||
|
||||
|
|
@ -220,7 +222,7 @@ func orMorphism(p *Path) morphism {
|
|||
func followMorphism(p *Path) morphism {
|
||||
return morphism{
|
||||
Name: "follow",
|
||||
Reversal: func() morphism { return followMorphism(p.Reverse()) },
|
||||
Reversal: func(ctx *context) (morphism, *context) { return followMorphism(p.Reverse()), ctx },
|
||||
Apply: func(qs graph.QuadStore, in graph.Iterator, ctx *context) (graph.Iterator, *context) {
|
||||
return p.Morphism()(qs, in), ctx
|
||||
},
|
||||
|
|
@ -231,7 +233,7 @@ func followMorphism(p *Path) morphism {
|
|||
func exceptMorphism(p *Path) morphism {
|
||||
return morphism{
|
||||
Name: "except",
|
||||
Reversal: func() morphism { return exceptMorphism(p) },
|
||||
Reversal: func(ctx *context) (morphism, *context) { return exceptMorphism(p), ctx },
|
||||
Apply: func(qs graph.QuadStore, in graph.Iterator, ctx *context) (graph.Iterator, *context) {
|
||||
subIt := p.BuildIteratorOn(qs)
|
||||
allNodes := qs.NodesAllIterator()
|
||||
|
|
@ -245,7 +247,7 @@ func exceptMorphism(p *Path) morphism {
|
|||
func saveMorphism(via interface{}, tag string) morphism {
|
||||
return morphism{
|
||||
Name: "save",
|
||||
Reversal: func() morphism { return saveMorphism(via, tag) },
|
||||
Reversal: func(ctx *context) (morphism, *context) { return saveMorphism(via, tag), ctx },
|
||||
Apply: func(qs graph.QuadStore, in graph.Iterator, ctx *context) (graph.Iterator, *context) {
|
||||
return buildSave(qs, via, tag, in, false), ctx
|
||||
},
|
||||
|
|
@ -256,7 +258,7 @@ func saveMorphism(via interface{}, tag string) morphism {
|
|||
func saveReverseMorphism(via interface{}, tag string) morphism {
|
||||
return morphism{
|
||||
Name: "saver",
|
||||
Reversal: func() morphism { return saveReverseMorphism(via, tag) },
|
||||
Reversal: func(ctx *context) (morphism, *context) { return saveReverseMorphism(via, tag), ctx },
|
||||
Apply: func(qs graph.QuadStore, in graph.Iterator, ctx *context) (graph.Iterator, *context) {
|
||||
return buildSave(qs, via, tag, in, true), ctx
|
||||
},
|
||||
|
|
|
|||
|
|
@ -20,13 +20,35 @@ type applyMorphism func(graph.QuadStore, graph.Iterator, *context) (graph.Iterat
|
|||
|
||||
type morphism struct {
|
||||
Name string
|
||||
Reversal func() morphism
|
||||
Reversal func(*context) (morphism, *context)
|
||||
Apply applyMorphism
|
||||
tags []string
|
||||
context context
|
||||
}
|
||||
|
||||
// context allows a high-level change to the way paths are constructed. Some
|
||||
// functions may change the context, causing following chained calls to act
|
||||
// cdifferently.
|
||||
//
|
||||
// In a sense, this is a global state which can be changed as the path
|
||||
// continues. And as with dealing with any global state, care should be taken:
|
||||
//
|
||||
// When modifying the context in Apply(), please copy the passed struct,
|
||||
// modifying the relevant fields if need be (or pass the given context onward).
|
||||
//
|
||||
// Under Reversal(), any functions that wish to change the context should
|
||||
// appropriately change the passed context (that is, the context that came after
|
||||
// them will now be what the application of the function would have been) and
|
||||
// then yield a pointer to their own member context as the return value.
|
||||
//
|
||||
// For more examples, look at the morphisms which claim the individual fields.
|
||||
type context struct {
|
||||
labelSet Path
|
||||
// Represents the path to the limiting set of labels that should be considered under traversal.
|
||||
// inMorphism, outMorphism, et al should constrain edges by this set.
|
||||
// A nil in this field represents all labels.
|
||||
//
|
||||
// Claimed by the withLabel morphism
|
||||
labelSet *Path
|
||||
}
|
||||
|
||||
// Path represents either a morphism (a pre-defined path stored for later use),
|
||||
|
|
@ -34,7 +56,7 @@ type context struct {
|
|||
type Path struct {
|
||||
stack []morphism
|
||||
qs graph.QuadStore // Optionally. A nil qs is equivalent to a morphism.
|
||||
baseContext *context
|
||||
baseContext context
|
||||
}
|
||||
|
||||
// IsMorphism returns whether this Path is a morphism.
|
||||
|
|
@ -74,8 +96,11 @@ func NewPath(qs graph.QuadStore) *Path {
|
|||
// Reverse returns a new Path that is the reverse of the current one.
|
||||
func (p *Path) Reverse() *Path {
|
||||
newPath := NewPath(p.qs)
|
||||
ctx := &newPath.baseContext
|
||||
for i := len(p.stack) - 1; i >= 0; i-- {
|
||||
newPath.stack = append(newPath.stack, p.stack[i].Reversal())
|
||||
var revMorphism morphism
|
||||
revMorphism, ctx = p.stack[i].Reversal(ctx)
|
||||
newPath.stack = append(newPath.stack, revMorphism)
|
||||
}
|
||||
return newPath
|
||||
}
|
||||
|
|
@ -153,10 +178,10 @@ func (p *Path) Both(via ...interface{}) *Path {
|
|||
// 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()
|
||||
// // 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
|
||||
|
|
@ -166,11 +191,11 @@ func (p *Path) InPredicates() *Path {
|
|||
// 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()
|
||||
// // 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
|
||||
|
|
@ -220,8 +245,8 @@ func (p *Path) FollowReverse(path *Path) *Path {
|
|||
// tag, and propagate that to the result set.
|
||||
//
|
||||
// For example:
|
||||
// // Will return []map[string]string{{"social_status: "cool"}}
|
||||
// StartPath(qs, "B").Save("status", "social_status"
|
||||
// // Will return []map[string]string{{"social_status: "cool"}}
|
||||
// StartPath(qs, "B").Save("status", "social_status"
|
||||
func (p *Path) Save(via interface{}, tag string) *Path {
|
||||
p.stack = append(p.stack, saveMorphism(via, tag))
|
||||
return p
|
||||
|
|
@ -244,12 +269,12 @@ func (p *Path) Has(via interface{}, nodes ...string) *Path {
|
|||
// Back returns to a previously tagged place in the path. Any constraints applied after the Tag will remain in effect, but traversal continues from the tagged point instead, not from the end of the chain.
|
||||
//
|
||||
// For example:
|
||||
// // Will return "bob" iff "bob" is cool
|
||||
// StartPath(qs, "bob").Tag("person_tag").Out("status").Is("cool").Back("person_tag")
|
||||
// // Will return "bob" iff "bob" is cool
|
||||
// StartPath(qs, "bob").Tag("person_tag").Out("status").Is("cool").Back("person_tag")
|
||||
func (p *Path) Back(tag string) *Path {
|
||||
newPath := NewPath(p.qs)
|
||||
i := len(p.stack) - 1
|
||||
|
||||
ctx := &newPath.baseContext
|
||||
for {
|
||||
if i < 0 {
|
||||
return p.Reverse()
|
||||
|
|
@ -263,7 +288,9 @@ func (p *Path) Back(tag string) *Path {
|
|||
}
|
||||
}
|
||||
}
|
||||
newPath.stack = append(newPath.stack, p.stack[i].Reversal())
|
||||
var revMorphism morphism
|
||||
revMorphism, ctx = p.stack[i].Reversal(ctx)
|
||||
newPath.stack = append(newPath.stack, revMorphism)
|
||||
i--
|
||||
}
|
||||
}
|
||||
|
|
@ -291,7 +318,7 @@ func (p *Path) BuildIteratorOn(qs graph.QuadStore) graph.Iterator {
|
|||
func (p *Path) Morphism() graph.ApplyMorphism {
|
||||
return func(qs graph.QuadStore, it graph.Iterator) graph.Iterator {
|
||||
i := it.Clone()
|
||||
ctx := p.baseContext
|
||||
ctx := &p.baseContext
|
||||
for _, m := range p.stack {
|
||||
i, ctx = m.Apply(qs, i, ctx)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue