Late bind the QuadStore and add Except and Tag

This commit is contained in:
Barak Michener 2015-02-08 18:49:51 -05:00
parent 4128133675
commit b9ca485321
3 changed files with 100 additions and 52 deletions

View file

@ -166,7 +166,7 @@ type Description struct {
} }
// A curried function that can generates a new iterator based on some prior iterator. // A curried function that can generates a new iterator based on some prior iterator.
type MorphismFunc func(Iterator) Iterator type ApplyMorphismFunc func(QuadStore, Iterator) Iterator
type Nexter interface { type Nexter interface {
// Next advances the iterator to the next value, which will then be available through // Next advances the iterator to the next value, which will then be available through

View file

@ -23,21 +23,24 @@ import (
type morphism struct { type morphism struct {
Name string Name string
Reversal func() morphism Reversal func() morphism
Apply graph.MorphismFunc Apply graph.ApplyMorphismFunc
} }
type Path struct { type Path struct {
stack []morphism stack []morphism
qs graph.QuadStore qs graph.QuadStore // Optionally. A nil qs is equivalent to a morphism.
}
func (p *Path) IsMorphism() bool { return p.qs == nil }
func StartMorphism(nodes ...string) *Path {
return StartPath(nil, nodes...)
} }
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(nodes...),
}, },
qs: qs, qs: qs,
} }
@ -67,7 +70,7 @@ func (p *Path) Reverse() *Path {
} }
func (p *Path) Is(nodes ...string) *Path { func (p *Path) Is(nodes ...string) *Path {
p.stack = append(p.stack, isMorphism(p.qs, nodes...)) p.stack = append(p.stack, isMorphism(nodes...))
return p return p
} }
@ -77,11 +80,11 @@ func (p *Path) Tag(tags ...string) *Path {
} }
func (p *Path) Out(via ...interface{}) *Path { func (p *Path) Out(via ...interface{}) *Path {
p.stack = append(p.stack, outMorphism(p.qs, via...)) p.stack = append(p.stack, outMorphism(via...))
return p return p
} }
func (p *Path) In(via ...interface{}) *Path { func (p *Path) In(via ...interface{}) *Path {
p.stack = append(p.stack, inMorphism(p.qs, via...)) p.stack = append(p.stack, inMorphism(via...))
return p return p
} }
@ -95,6 +98,11 @@ func (p *Path) Or(path *Path) *Path {
return p return p
} }
func (p *Path) Except(path *Path) *Path {
p.stack = append(p.stack, exceptMorphism(path))
return p
}
func (p *Path) Follow(path *Path) *Path { func (p *Path) Follow(path *Path) *Path {
p.stack = append(p.stack, followMorphism(path)) p.stack = append(p.stack, followMorphism(path))
return p return p
@ -106,31 +114,44 @@ func (p *Path) FollowReverse(path *Path) *Path {
} }
func (p *Path) BuildIterator() graph.Iterator { func (p *Path) BuildIterator() graph.Iterator {
f := p.MorphismFunc() if p.IsMorphism() {
return f(p.qs.NodesAllIterator()) panic("Building an iterator from a morphism. Bind a QuadStore with BuildIteratorOn(qs)")
}
return p.BuildIteratorOn(p.qs)
} }
func (p *Path) MorphismFunc() graph.MorphismFunc { func (p *Path) BuildIteratorOn(qs graph.QuadStore) graph.Iterator {
return func(it graph.Iterator) graph.Iterator { f := p.MorphismFunc()
return f(qs, qs.NodesAllIterator())
}
func (p *Path) MorphismFunc() graph.ApplyMorphismFunc {
return func(qs graph.QuadStore, it graph.Iterator) graph.Iterator {
i := it.Clone() i := it.Clone()
for _, m := range p.stack { for _, m := range p.stack {
i = m.Apply(i) i = m.Apply(qs, i)
} }
return i return i
} }
} }
func isMorphism(qs graph.QuadStore, nodes ...string) morphism { func isMorphism(nodes ...string) morphism {
return morphism{ return morphism{
"is", "is",
func() morphism { return isMorphism(qs, nodes...) }, func() morphism { return isMorphism(nodes...) },
func(it graph.Iterator) graph.Iterator { func(qs graph.QuadStore, it graph.Iterator) graph.Iterator {
fixed := qs.FixedIterator() var sub graph.Iterator
for _, n := range nodes { if len(nodes) == 0 {
fixed.Add(qs.ValueOf(n)) sub = qs.NodesAllIterator()
} else {
fixed := qs.FixedIterator()
for _, n := range nodes {
fixed.Add(qs.ValueOf(n))
}
sub = fixed
} }
and := iterator.NewAnd() and := iterator.NewAnd()
and.AddSubIterator(fixed) and.AddSubIterator(sub)
and.AddSubIterator(it) and.AddSubIterator(it)
return and return and
}, },
@ -141,7 +162,7 @@ func tagMorphism(tags ...string) morphism {
return morphism{ return morphism{
"tag", "tag",
func() morphism { return tagMorphism(tags...) }, func() morphism { return tagMorphism(tags...) },
func(it graph.Iterator) graph.Iterator { func(qs graph.QuadStore, it graph.Iterator) graph.Iterator {
for _, t := range tags { for _, t := range tags {
it.Tagger().Add(t) it.Tagger().Add(t)
} }
@ -149,21 +170,25 @@ func tagMorphism(tags ...string) morphism {
}} }}
} }
func outMorphism(qs graph.QuadStore, via ...interface{}) morphism { func outMorphism(via ...interface{}) morphism {
path := buildViaPath(qs, via...)
return morphism{ return morphism{
"out", "out",
func() morphism { return inMorphism(qs, via...) }, func() morphism { return inMorphism(via...) },
inOutIterator(path, false), func(qs graph.QuadStore, it graph.Iterator) graph.Iterator {
path := buildViaPath(qs, via...)
return inOutIterator(path, it, false)
},
} }
} }
func inMorphism(qs graph.QuadStore, via ...interface{}) morphism { func inMorphism(via ...interface{}) morphism {
path := buildViaPath(qs, via...)
return morphism{ return morphism{
"in", "in",
func() morphism { return outMorphism(qs, via...) }, func() morphism { return outMorphism(via...) },
inOutIterator(path, true), func(qs graph.QuadStore, it graph.Iterator) graph.Iterator {
path := buildViaPath(qs, via...)
return inOutIterator(path, it, true)
},
} }
} }
@ -171,7 +196,7 @@ func iteratorMorphism(it graph.Iterator) morphism {
return morphism{ return morphism{
"iterator", "iterator",
func() morphism { return iteratorMorphism(it) }, func() morphism { return iteratorMorphism(it) },
func(subIt graph.Iterator) graph.Iterator { func(_ graph.QuadStore, subIt graph.Iterator) graph.Iterator {
and := iterator.NewAnd() and := iterator.NewAnd()
and.AddSubIterator(it) and.AddSubIterator(it)
and.AddSubIterator(subIt) and.AddSubIterator(subIt)
@ -184,8 +209,8 @@ func andMorphism(path *Path) morphism {
return morphism{ return morphism{
"and", "and",
func() morphism { return andMorphism(path) }, func() morphism { return andMorphism(path) },
func(it graph.Iterator) graph.Iterator { func(qs graph.QuadStore, it graph.Iterator) graph.Iterator {
subIt := path.BuildIterator() subIt := path.BuildIteratorOn(qs)
and := iterator.NewAnd() and := iterator.NewAnd()
and.AddSubIterator(it) and.AddSubIterator(it)
and.AddSubIterator(subIt) and.AddSubIterator(subIt)
@ -198,8 +223,8 @@ func orMorphism(path *Path) morphism {
return morphism{ return morphism{
"or", "or",
func() morphism { return orMorphism(path) }, func() morphism { return orMorphism(path) },
func(it graph.Iterator) graph.Iterator { func(qs graph.QuadStore, it graph.Iterator) graph.Iterator {
subIt := path.BuildIterator() subIt := path.BuildIteratorOn(qs)
and := iterator.NewOr() and := iterator.NewOr()
and.AddSubIterator(it) and.AddSubIterator(it)
and.AddSubIterator(subIt) and.AddSubIterator(subIt)
@ -212,27 +237,40 @@ func followMorphism(path *Path) morphism {
return morphism{ return morphism{
"follow", "follow",
func() morphism { return followMorphism(path.Reverse()) }, func() morphism { return followMorphism(path.Reverse()) },
func(base graph.Iterator) graph.Iterator { func(qs graph.QuadStore, base graph.Iterator) graph.Iterator {
p := path.MorphismFunc() p := path.MorphismFunc()
return p(base) return p(qs, base)
}, },
} }
} }
func inOutIterator(viaPath *Path, reverse bool) graph.MorphismFunc { func exceptMorphism(path *Path) morphism {
return func(base graph.Iterator) graph.Iterator { return morphism{
in, out := quad.Subject, quad.Object "except",
if reverse { func() morphism { return exceptMorphism(path) },
in, out = out, in func(qs graph.QuadStore, base graph.Iterator) graph.Iterator {
} subIt := path.BuildIteratorOn(qs)
lto := iterator.NewLinksTo(viaPath.qs, base, in) notIt := iterator.NewNot(subIt, qs.NodesAllIterator())
and := iterator.NewAnd() and := iterator.NewAnd()
and.AddSubIterator(iterator.NewLinksTo(viaPath.qs, viaPath.BuildIterator(), quad.Predicate)) and.AddSubIterator(base)
and.AddSubIterator(lto) and.AddSubIterator(notIt)
return iterator.NewHasA(viaPath.qs, and, out) return and
},
} }
} }
func inOutIterator(viaPath *Path, it graph.Iterator, reverse bool) graph.Iterator {
in, out := quad.Subject, quad.Object
if reverse {
in, out = out, in
}
lto := iterator.NewLinksTo(viaPath.qs, it, in)
and := iterator.NewAnd()
and.AddSubIterator(iterator.NewLinksTo(viaPath.qs, viaPath.BuildIterator(), quad.Predicate))
and.AddSubIterator(lto)
return iterator.NewHasA(viaPath.qs, and, out)
}
func buildViaPath(qs graph.QuadStore, via ...interface{}) *Path { func buildViaPath(qs graph.QuadStore, via ...interface{}) *Path {
if len(via) == 0 { if len(via) == 0 {
return PathFromIterator(qs, qs.NodesAllIterator()) return PathFromIterator(qs, qs.NodesAllIterator())

View file

@ -136,20 +136,30 @@ func testSet(qs graph.QuadStore) []test {
}, },
{ {
message: "follow", message: "follow",
path: StartPath(qs, "C").Follow(StartPath(qs).Out("follows").Out("follows")), path: StartPath(qs, "C").Follow(StartMorphism().Out("follows").Out("follows")),
expect: []string{"B", "F", "G"}, expect: []string{"B", "F", "G"},
}, },
{ {
message: "followR", message: "followR",
path: StartPath(qs, "F").FollowReverse(StartPath(qs).Out("follows").Out("follows")), path: StartPath(qs, "F").FollowReverse(StartMorphism().Out("follows").Out("follows")),
expect: []string{"A", "C", "D"}, expect: []string{"A", "C", "D"},
}, },
{ {
message: "is, tag, instead of FollowR", message: "is, tag, instead of FollowR",
path: StartPath(qs).Tag("first").Follow(StartPath(qs).Out("follows").Out("follows")).Is("F"), path: StartPath(qs).Tag("first").Follow(StartMorphism().Out("follows").Out("follows")).Is("F"),
expect: []string{"A", "C", "D"}, expect: []string{"A", "C", "D"},
tag: "first", tag: "first",
}, },
{
message: "use Except to filter out a single vertex",
path: StartPath(qs, "A", "B").Except(StartPath(qs, "A")),
expect: []string{"B"},
},
{
message: "use chained Except",
path: StartPath(qs, "A", "B", "C").Except(StartPath(qs, "B")).Except(StartPath(qs, "A")),
expect: []string{"C"},
},
} }
} }