Replace string type with graph.Direction

This conversion is not complete as there are still uses of string
directions via the Direction.String method in leveldb.
This commit is contained in:
kortschak 2014-06-30 12:33:55 +09:30
parent cd11053c98
commit 0a03cec497
21 changed files with 340 additions and 298 deletions

View file

@ -47,18 +47,18 @@ type HasaIterator struct {
BaseIterator BaseIterator
ts TripleStore ts TripleStore
primaryIt Iterator primaryIt Iterator
direction string dir Direction
resultIt Iterator resultIt Iterator
} }
// Construct a new HasA iterator, given the triple subiterator, and the triple // Construct a new HasA iterator, given the triple subiterator, and the triple
// direction for which it stands. // direction for which it stands.
func NewHasaIterator(ts TripleStore, subIt Iterator, dir string) *HasaIterator { func NewHasaIterator(ts TripleStore, subIt Iterator, d Direction) *HasaIterator {
var hasa HasaIterator var hasa HasaIterator
BaseIteratorInit(&hasa.BaseIterator) BaseIteratorInit(&hasa.BaseIterator)
hasa.ts = ts hasa.ts = ts
hasa.primaryIt = subIt hasa.primaryIt = subIt
hasa.direction = dir hasa.dir = d
return &hasa return &hasa
} }
@ -75,13 +75,13 @@ func (it *HasaIterator) Reset() {
} }
func (it *HasaIterator) Clone() Iterator { func (it *HasaIterator) Clone() Iterator {
out := NewHasaIterator(it.ts, it.primaryIt.Clone(), it.direction) out := NewHasaIterator(it.ts, it.primaryIt.Clone(), it.dir)
out.CopyTagsFrom(it) out.CopyTagsFrom(it)
return out return out
} }
// Direction accessor. // Direction accessor.
func (it *HasaIterator) Direction() string { return it.direction } func (it *HasaIterator) Direction() Direction { return it.dir }
// Pass the Optimize() call along to the subiterator. If it becomes Null, // Pass the Optimize() call along to the subiterator. If it becomes Null,
// then the HasA becomes Null (there are no triples that have any directions). // then the HasA becomes Null (there are no triples that have any directions).
@ -115,7 +115,7 @@ func (it *HasaIterator) DebugString(indent int) string {
for _, k := range it.Tags() { for _, k := range it.Tags() {
tags += fmt.Sprintf("%s;", k) tags += fmt.Sprintf("%s;", k)
} }
return fmt.Sprintf("%s(%s %d tags:%s direction:%s\n%s)", strings.Repeat(" ", indent), it.Type(), it.GetUid(), tags, it.direction, it.primaryIt.DebugString(indent+4)) return fmt.Sprintf("%s(%s %d tags:%s direction:%s\n%s)", strings.Repeat(" ", indent), it.Type(), it.GetUid(), tags, it.dir, it.primaryIt.DebugString(indent+4))
} }
// Check a value against our internal iterator. In order to do this, we must first open a new // Check a value against our internal iterator. In order to do this, we must first open a new
@ -130,7 +130,7 @@ func (it *HasaIterator) Check(val TSVal) bool {
if it.resultIt != nil { if it.resultIt != nil {
it.resultIt.Close() it.resultIt.Close()
} }
it.resultIt = it.ts.GetTripleIterator(it.direction, val) it.resultIt = it.ts.GetTripleIterator(it.dir, val)
return CheckLogOut(it, val, it.GetCheckResult()) return CheckLogOut(it, val, it.GetCheckResult())
} }
@ -147,7 +147,7 @@ func (it *HasaIterator) GetCheckResult() bool {
glog.V(4).Infoln("Triple is", it.ts.GetTriple(linkVal).ToString()) glog.V(4).Infoln("Triple is", it.ts.GetTriple(linkVal).ToString())
} }
if it.primaryIt.Check(linkVal) { if it.primaryIt.Check(linkVal) {
it.Last = it.ts.GetTripleDirection(linkVal, it.direction) it.Last = it.ts.GetTripleDirection(linkVal, it.dir)
return true return true
} }
} }
@ -182,7 +182,7 @@ func (it *HasaIterator) Next() (TSVal, bool) {
if !ok { if !ok {
return NextLogOut(it, 0, false) return NextLogOut(it, 0, false)
} }
name := it.ts.GetTriple(tID).Get(it.direction) name := it.ts.GetTriple(tID).Get(it.dir)
val := it.ts.GetIdFor(name) val := it.ts.GetIdFor(name)
it.Last = val it.Last = val
return NextLogOut(it, val, true) return NextLogOut(it, val, true)

View file

@ -28,21 +28,21 @@ import (
type AllIterator struct { type AllIterator struct {
graph.BaseIterator graph.BaseIterator
prefix []byte prefix []byte
dir string dir graph.Direction
open bool open bool
it iterator.Iterator it iterator.Iterator
ts *TripleStore ts *TripleStore
ro *opt.ReadOptions ro *opt.ReadOptions
} }
func NewAllIterator(prefix, dir string, ts *TripleStore) *AllIterator { func NewAllIterator(prefix string, d graph.Direction, ts *TripleStore) *AllIterator {
var it AllIterator var it AllIterator
graph.BaseIteratorInit(&it.BaseIterator) graph.BaseIteratorInit(&it.BaseIterator)
it.ro = &opt.ReadOptions{} it.ro = &opt.ReadOptions{}
it.ro.DontFillCache = true it.ro.DontFillCache = true
it.it = ts.db.NewIterator(nil, it.ro) it.it = ts.db.NewIterator(nil, it.ro)
it.prefix = []byte(prefix) it.prefix = []byte(prefix)
it.dir = dir it.dir = d
it.open = true it.open = true
it.ts = ts it.ts = ts
it.it.Seek(it.prefix) it.it.Seek(it.prefix)

View file

@ -29,7 +29,7 @@ type Iterator struct {
graph.BaseIterator graph.BaseIterator
nextPrefix []byte nextPrefix []byte
checkId []byte checkId []byte
dir string dir graph.Direction
open bool open bool
it iterator.Iterator it iterator.Iterator
ts *TripleStore ts *TripleStore
@ -37,11 +37,11 @@ type Iterator struct {
originalPrefix string originalPrefix string
} }
func NewIterator(prefix, dir string, value graph.TSVal, ts *TripleStore) *Iterator { func NewIterator(prefix string, d graph.Direction, value graph.TSVal, ts *TripleStore) *Iterator {
var it Iterator var it Iterator
graph.BaseIteratorInit(&it.BaseIterator) graph.BaseIteratorInit(&it.BaseIterator)
it.checkId = value.([]byte) it.checkId = value.([]byte)
it.dir = dir it.dir = d
it.originalPrefix = prefix it.originalPrefix = prefix
it.nextPrefix = make([]byte, 0, 2+ts.hasher.Size()) it.nextPrefix = make([]byte, 0, 2+ts.hasher.Size())
it.nextPrefix = append(it.nextPrefix, []byte(prefix)...) it.nextPrefix = append(it.nextPrefix, []byte(prefix)...)
@ -113,56 +113,56 @@ func (it *Iterator) Next() (graph.TSVal, bool) {
return nil, false return nil, false
} }
func GetPositionFromPrefix(prefix []byte, dir string, ts *TripleStore) int { func GetPositionFromPrefix(prefix []byte, d graph.Direction, ts *TripleStore) int {
if bytes.Equal(prefix, []byte("sp")) { if bytes.Equal(prefix, []byte("sp")) {
switch dir { switch d {
case "s": case graph.Subject:
return 2 return 2
case "p": case graph.Predicate:
return ts.hasher.Size() + 2 return ts.hasher.Size() + 2
case "o": case graph.Object:
return 2*ts.hasher.Size() + 2 return 2*ts.hasher.Size() + 2
case "c": case graph.Provenance:
return -1 return -1
} }
} }
if bytes.Equal(prefix, []byte("po")) { if bytes.Equal(prefix, []byte("po")) {
switch dir { switch d {
case "s": case graph.Subject:
return 2*ts.hasher.Size() + 2 return 2*ts.hasher.Size() + 2
case "p": case graph.Predicate:
return 2 return 2
case "o": case graph.Object:
return ts.hasher.Size() + 2 return ts.hasher.Size() + 2
case "c": case graph.Provenance:
return -1 return -1
} }
} }
if bytes.Equal(prefix, []byte("os")) { if bytes.Equal(prefix, []byte("os")) {
switch dir { switch d {
case "s": case graph.Subject:
return ts.hasher.Size() + 2 return ts.hasher.Size() + 2
case "p": case graph.Predicate:
return 2*ts.hasher.Size() + 2 return 2*ts.hasher.Size() + 2
case "o": case graph.Object:
return 2 return 2
case "c": case graph.Provenance:
return -1 return -1
} }
} }
if bytes.Equal(prefix, []byte("cp")) { if bytes.Equal(prefix, []byte("cp")) {
switch dir { switch d {
case "s": case graph.Subject:
return 2*ts.hasher.Size() + 2 return 2*ts.hasher.Size() + 2
case "p": case graph.Predicate:
return ts.hasher.Size() + 2 return ts.hasher.Size() + 2
case "o": case graph.Object:
return 3*ts.hasher.Size() + 2 return 3*ts.hasher.Size() + 2
case "c": case graph.Provenance:
return 2 return 2
} }
} }
panic("Notreached") panic("unreachable")
} }
func (it *Iterator) Check(v graph.TSVal) bool { func (it *Iterator) Check(v graph.TSVal) bool {

View file

@ -248,7 +248,7 @@ func TestSetIterator(t *testing.T) {
var it graph.Iterator var it graph.Iterator
Convey("Can create a subject iterator", func() { Convey("Can create a subject iterator", func() {
it = ts.GetTripleIterator("s", ts.GetIdFor("C")) it = ts.GetTripleIterator(graph.Subject, ts.GetIdFor("C"))
Convey("Containing the right things", func() { Convey("Containing the right things", func() {
expected := []string{ expected := []string{
@ -282,7 +282,7 @@ func TestSetIterator(t *testing.T) {
}) })
Convey("Can create an object iterator", func() { Convey("Can create an object iterator", func() {
it = ts.GetTripleIterator("o", ts.GetIdFor("F")) it = ts.GetTripleIterator(graph.Object, ts.GetIdFor("F"))
Convey("Containing the right things", func() { Convey("Containing the right things", func() {
expected := []string{ expected := []string{
@ -297,7 +297,7 @@ func TestSetIterator(t *testing.T) {
Convey("Mutually and-checkable", func() { Convey("Mutually and-checkable", func() {
and := graph.NewAndIterator() and := graph.NewAndIterator()
and.AddSubIterator(ts.GetTripleIterator("s", ts.GetIdFor("B"))) and.AddSubIterator(ts.GetTripleIterator(graph.Subject, ts.GetIdFor("B")))
and.AddSubIterator(it) and.AddSubIterator(it)
expected := []string{ expected := []string{
@ -312,7 +312,7 @@ func TestSetIterator(t *testing.T) {
}) })
Convey("Can create a predicate iterator", func() { Convey("Can create a predicate iterator", func() {
it = ts.GetTripleIterator("p", ts.GetIdFor("status")) it = ts.GetTripleIterator(graph.Predicate, ts.GetIdFor("status"))
Convey("Containing the right things", func() { Convey("Containing the right things", func() {
expected := []string{ expected := []string{
@ -329,7 +329,7 @@ func TestSetIterator(t *testing.T) {
}) })
Convey("Can create a provenance iterator", func() { Convey("Can create a provenance iterator", func() {
it = ts.GetTripleIterator("c", ts.GetIdFor("status_graph")) it = ts.GetTripleIterator(graph.Provenance, ts.GetIdFor("status_graph"))
Convey("Containing the right things", func() { Convey("Containing the right things", func() {
expected := []string{ expected := []string{
@ -346,7 +346,7 @@ func TestSetIterator(t *testing.T) {
Convey("Can be cross-checked", func() { Convey("Can be cross-checked", func() {
and := graph.NewAndIterator() and := graph.NewAndIterator()
// Order is important // Order is important
and.AddSubIterator(ts.GetTripleIterator("s", ts.GetIdFor("B"))) and.AddSubIterator(ts.GetTripleIterator(graph.Subject, ts.GetIdFor("B")))
and.AddSubIterator(it) and.AddSubIterator(it)
expected := []string{ expected := []string{
@ -360,7 +360,7 @@ func TestSetIterator(t *testing.T) {
and := graph.NewAndIterator() and := graph.NewAndIterator()
// Order is important // Order is important
and.AddSubIterator(it) and.AddSubIterator(it)
and.AddSubIterator(ts.GetTripleIterator("s", ts.GetIdFor("B"))) and.AddSubIterator(ts.GetTripleIterator(graph.Subject, ts.GetIdFor("B")))
expected := []string{ expected := []string{
graph.MakeTriple("B", "status", "cool", "status_graph").ToString(), graph.MakeTriple("B", "status", "cool", "status_graph").ToString(),
@ -400,7 +400,7 @@ func TestOptimize(t *testing.T) {
fixed := ts.MakeFixed() fixed := ts.MakeFixed()
fixed.AddValue(ts.GetIdFor("F")) fixed.AddValue(ts.GetIdFor("F"))
fixed.AddTag("internal") fixed.AddTag("internal")
lto = graph.NewLinksToIterator(ts, fixed, "o") lto = graph.NewLinksToIterator(ts, fixed, graph.Object)
Convey("Creates an appropriate iterator", func() { Convey("Creates an appropriate iterator", func() {
oldIt := lto.Clone() oldIt := lto.Clone()

View file

@ -24,15 +24,17 @@ import (
"github.com/barakmich/glog" "github.com/barakmich/glog"
"github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb"
cache "github.com/syndtr/goleveldb/leveldb/cache" "github.com/syndtr/goleveldb/leveldb/cache"
"github.com/syndtr/goleveldb/leveldb/opt" "github.com/syndtr/goleveldb/leveldb/opt"
util "github.com/syndtr/goleveldb/leveldb/util" "github.com/syndtr/goleveldb/leveldb/util"
"github.com/google/cayley/graph" "github.com/google/cayley/graph"
) )
const DefaultCacheSize = 2 const (
const DefaultWriteBufferSize = 20 DefaultCacheSize = 2
DefaultWriteBufferSize = 20
)
type TripleStore struct { type TripleStore struct {
dbOpts *opt.Options dbOpts *opt.Options
@ -49,7 +51,7 @@ func CreateNewLevelDB(path string) bool {
opts := &opt.Options{} opts := &opt.Options{}
db, err := leveldb.OpenFile(path, opts) db, err := leveldb.OpenFile(path, opts)
if err != nil { if err != nil {
glog.Errorln("Error: couldn't create database", err) glog.Errorln("Error: couldn't create database: ", err)
return false return false
} }
defer db.Close() defer db.Close()
@ -108,22 +110,24 @@ func (ts *TripleStore) Size() int64 {
return ts.size return ts.size
} }
func (ts *TripleStore) createKeyFor(dir1, dir2, dir3 string, triple *graph.Triple) []byte { func (ts *TripleStore) createKeyFor(d [3]graph.Direction, triple *graph.Triple) []byte {
key := make([]byte, 0, 2+(ts.hasher.Size()*3)) key := make([]byte, 0, 2+(ts.hasher.Size()*3))
key = append(key, []byte(dir1+dir2)...) // TODO(kortschak) Remove dependence on String() method.
key = append(key, ts.convertStringToByteHash(triple.Get(dir1))...) key = append(key, []byte(d[0].String()+d[1].String())...)
key = append(key, ts.convertStringToByteHash(triple.Get(dir2))...) key = append(key, ts.convertStringToByteHash(triple.Get(d[0]))...)
key = append(key, ts.convertStringToByteHash(triple.Get(dir3))...) key = append(key, ts.convertStringToByteHash(triple.Get(d[1]))...)
key = append(key, ts.convertStringToByteHash(triple.Get(d[2]))...)
return key return key
} }
func (ts *TripleStore) createProvKeyFor(dir1, dir2, dir3 string, triple *graph.Triple) []byte { func (ts *TripleStore) createProvKeyFor(d [3]graph.Direction, triple *graph.Triple) []byte {
key := make([]byte, 0, 2+(ts.hasher.Size()*4)) key := make([]byte, 0, 2+(ts.hasher.Size()*4))
key = append(key, []byte("c"+dir1)...) // TODO(kortschak) Remove dependence on String() method.
key = append(key, ts.convertStringToByteHash(triple.Get("c"))...) key = append(key, []byte(graph.Provenance.String()+d[0].String())...)
key = append(key, ts.convertStringToByteHash(triple.Get(dir1))...) key = append(key, ts.convertStringToByteHash(triple.Get(graph.Provenance))...)
key = append(key, ts.convertStringToByteHash(triple.Get(dir2))...) key = append(key, ts.convertStringToByteHash(triple.Get(d[0]))...)
key = append(key, ts.convertStringToByteHash(triple.Get(dir3))...) key = append(key, ts.convertStringToByteHash(triple.Get(d[1]))...)
key = append(key, ts.convertStringToByteHash(triple.Get(d[2]))...)
return key return key
} }
@ -145,8 +149,16 @@ func (ts *TripleStore) AddTriple(t *graph.Triple) {
ts.size++ ts.size++
} }
// Short hand for direction permutations.
var (
spo = [3]graph.Direction{graph.Subject, graph.Predicate, graph.Object}
osp = [3]graph.Direction{graph.Object, graph.Subject, graph.Predicate}
pos = [3]graph.Direction{graph.Predicate, graph.Object, graph.Subject}
pso = [3]graph.Direction{graph.Predicate, graph.Subject, graph.Object}
)
func (ts *TripleStore) RemoveTriple(t *graph.Triple) { func (ts *TripleStore) RemoveTriple(t *graph.Triple) {
_, err := ts.db.Get(ts.createKeyFor("s", "p", "o", t), ts.readopts) _, err := ts.db.Get(ts.createKeyFor(spo, t), ts.readopts)
if err != nil && err != leveldb.ErrNotFound { if err != nil && err != leveldb.ErrNotFound {
glog.Errorf("Couldn't access DB to confirm deletion") glog.Errorf("Couldn't access DB to confirm deletion")
return return
@ -156,15 +168,15 @@ func (ts *TripleStore) RemoveTriple(t *graph.Triple) {
return return
} }
batch := &leveldb.Batch{} batch := &leveldb.Batch{}
batch.Delete(ts.createKeyFor("s", "p", "o", t)) batch.Delete(ts.createKeyFor(spo, t))
batch.Delete(ts.createKeyFor("o", "s", "p", t)) batch.Delete(ts.createKeyFor(osp, t))
batch.Delete(ts.createKeyFor("p", "o", "s", t)) batch.Delete(ts.createKeyFor(pos, t))
ts.UpdateValueKeyBy(t.Get("s"), -1, batch) ts.UpdateValueKeyBy(t.Get(graph.Subject), -1, batch)
ts.UpdateValueKeyBy(t.Get("p"), -1, batch) ts.UpdateValueKeyBy(t.Get(graph.Predicate), -1, batch)
ts.UpdateValueKeyBy(t.Get("o"), -1, batch) ts.UpdateValueKeyBy(t.Get(graph.Object), -1, batch)
if t.Get("c") != "" { if t.Get(graph.Provenance) != "" {
batch.Delete(ts.createProvKeyFor("p", "s", "o", t)) batch.Delete(ts.createProvKeyFor(pso, t))
ts.UpdateValueKeyBy(t.Get("c"), -1, batch) ts.UpdateValueKeyBy(t.Get(graph.Provenance), -1, batch)
} }
err = ts.db.Write(batch, nil) err = ts.db.Write(batch, nil)
if err != nil { if err != nil {
@ -180,21 +192,21 @@ func (ts *TripleStore) buildTripleWrite(batch *leveldb.Batch, t *graph.Triple) {
glog.Errorf("Couldn't write to buffer for triple %s\n %s\n", t.ToString(), err) glog.Errorf("Couldn't write to buffer for triple %s\n %s\n", t.ToString(), err)
return return
} }
batch.Put(ts.createKeyFor("s", "p", "o", t), bytes) batch.Put(ts.createKeyFor(spo, t), bytes)
batch.Put(ts.createKeyFor("o", "s", "p", t), bytes) batch.Put(ts.createKeyFor(osp, t), bytes)
batch.Put(ts.createKeyFor("p", "o", "s", t), bytes) batch.Put(ts.createKeyFor(pos, t), bytes)
if t.Get("c") != "" { if t.Get(graph.Provenance) != "" {
batch.Put(ts.createProvKeyFor("p", "s", "o", t), bytes) batch.Put(ts.createProvKeyFor(pso, t), bytes)
} }
} }
func (ts *TripleStore) buildWrite(batch *leveldb.Batch, t *graph.Triple) { func (ts *TripleStore) buildWrite(batch *leveldb.Batch, t *graph.Triple) {
ts.buildTripleWrite(batch, t) ts.buildTripleWrite(batch, t)
ts.UpdateValueKeyBy(t.Get("s"), 1, nil) ts.UpdateValueKeyBy(t.Get(graph.Subject), 1, nil)
ts.UpdateValueKeyBy(t.Get("p"), 1, nil) ts.UpdateValueKeyBy(t.Get(graph.Predicate), 1, nil)
ts.UpdateValueKeyBy(t.Get("o"), 1, nil) ts.UpdateValueKeyBy(t.Get(graph.Object), 1, nil)
if t.Get("c") != "" { if t.Get(graph.Provenance) != "" {
ts.UpdateValueKeyBy(t.Get("c"), 1, nil) ts.UpdateValueKeyBy(t.Get(graph.Provenance), 1, nil)
} }
} }
@ -255,9 +267,9 @@ func (ts *TripleStore) AddTripleSet(t_s []*graph.Triple) {
resizeMap := make(map[string]int) resizeMap := make(map[string]int)
for _, t := range t_s { for _, t := range t_s {
ts.buildTripleWrite(batch, t) ts.buildTripleWrite(batch, t)
resizeMap[t.Sub]++ resizeMap[t.Subject]++
resizeMap[t.Pred]++ resizeMap[t.Predicate]++
resizeMap[t.Obj]++ resizeMap[t.Object]++
if t.Provenance != "" { if t.Provenance != "" {
resizeMap[t.Provenance]++ resizeMap[t.Provenance]++
} }
@ -388,35 +400,38 @@ func (ts *TripleStore) GetApproximateSizeForPrefix(pre []byte) (int64, error) {
return 0, nil return 0, nil
} }
func (ts *TripleStore) GetTripleIterator(dir string, val graph.TSVal) graph.Iterator { func (ts *TripleStore) GetTripleIterator(d graph.Direction, val graph.TSVal) graph.Iterator {
switch dir { var prefix string
case "s": switch d {
return NewIterator("sp", "s", val, ts) case graph.Subject:
case "p": prefix = "sp"
return NewIterator("po", "p", val, ts) case graph.Predicate:
case "o": prefix = "po"
return NewIterator("os", "o", val, ts) case graph.Object:
case "c": prefix = "os"
return NewIterator("cp", "c", val, ts) case graph.Provenance:
prefix = "cp"
default:
panic("unreachable " + d.String())
} }
panic("Notreached " + dir) return NewIterator(prefix, d, val, ts)
} }
func (ts *TripleStore) GetNodesAllIterator() graph.Iterator { func (ts *TripleStore) GetNodesAllIterator() graph.Iterator {
return NewAllIterator("z", "v", ts) return NewAllIterator("z", graph.Any, ts)
} }
func (ts *TripleStore) GetTriplesAllIterator() graph.Iterator { func (ts *TripleStore) GetTriplesAllIterator() graph.Iterator {
return NewAllIterator("po", "p", ts) return NewAllIterator("po", graph.Predicate, ts)
} }
func (ts *TripleStore) GetTripleDirection(val graph.TSVal, direction string) graph.TSVal { func (ts *TripleStore) GetTripleDirection(val graph.TSVal, d graph.Direction) graph.TSVal {
v := val.([]uint8) v := val.([]uint8)
offset := GetPositionFromPrefix(v[0:2], direction, ts) offset := GetPositionFromPrefix(v[0:2], d, ts)
if offset != -1 { if offset != -1 {
return append([]byte("z"), v[offset:offset+ts.hasher.Size()]...) return append([]byte("z"), v[offset:offset+ts.hasher.Size()]...)
} else { } else {
return ts.GetTriple(val).Get(direction) return ts.GetTriple(val).Get(d)
} }
} }

View file

@ -41,18 +41,18 @@ type LinksToIterator struct {
BaseIterator BaseIterator
ts TripleStore ts TripleStore
primaryIt Iterator primaryIt Iterator
direction string dir Direction
nextIt Iterator nextIt Iterator
} }
// Construct a new LinksTo iterator around a direction and a subiterator of // Construct a new LinksTo iterator around a direction and a subiterator of
// nodes. // nodes.
func NewLinksToIterator(ts TripleStore, it Iterator, dir string) *LinksToIterator { func NewLinksToIterator(ts TripleStore, it Iterator, d Direction) *LinksToIterator {
var lto LinksToIterator var lto LinksToIterator
BaseIteratorInit(&lto.BaseIterator) BaseIteratorInit(&lto.BaseIterator)
lto.ts = ts lto.ts = ts
lto.primaryIt = it lto.primaryIt = it
lto.direction = dir lto.dir = d
lto.nextIt = &NullIterator{} lto.nextIt = &NullIterator{}
return &lto return &lto
} }
@ -66,13 +66,13 @@ func (it *LinksToIterator) Reset() {
} }
func (it *LinksToIterator) Clone() Iterator { func (it *LinksToIterator) Clone() Iterator {
out := NewLinksToIterator(it.ts, it.primaryIt.Clone(), it.direction) out := NewLinksToIterator(it.ts, it.primaryIt.Clone(), it.dir)
out.CopyTagsFrom(it) out.CopyTagsFrom(it)
return out return out
} }
// Return the direction under consideration. // Return the direction under consideration.
func (it *LinksToIterator) Direction() string { return it.direction } func (it *LinksToIterator) Direction() Direction { return it.dir }
// Tag these results, and our subiterator's results. // Tag these results, and our subiterator's results.
func (it *LinksToIterator) TagResults(out *map[string]TSVal) { func (it *LinksToIterator) TagResults(out *map[string]TSVal) {
@ -91,14 +91,14 @@ func (it *LinksToIterator) GetResultTree() *ResultTree {
func (it *LinksToIterator) DebugString(indent int) string { func (it *LinksToIterator) DebugString(indent int) string {
return fmt.Sprintf("%s(%s %d direction:%s\n%s)", return fmt.Sprintf("%s(%s %d direction:%s\n%s)",
strings.Repeat(" ", indent), strings.Repeat(" ", indent),
it.Type(), it.GetUid(), it.direction, it.primaryIt.DebugString(indent+4)) it.Type(), it.GetUid(), it.dir, it.primaryIt.DebugString(indent+4))
} }
// If it checks in the right direction for the subiterator, it is a valid link // If it checks in the right direction for the subiterator, it is a valid link
// for the LinksTo. // for the LinksTo.
func (it *LinksToIterator) Check(val TSVal) bool { func (it *LinksToIterator) Check(val TSVal) bool {
CheckLogIn(it, val) CheckLogIn(it, val)
node := it.ts.GetTripleDirection(val, it.direction) node := it.ts.GetTripleDirection(val, it.dir)
if it.primaryIt.Check(node) { if it.primaryIt.Check(node) {
it.Last = val it.Last = val
return CheckLogOut(it, val, true) return CheckLogOut(it, val, true)
@ -144,7 +144,7 @@ func (it *LinksToIterator) Next() (TSVal, bool) {
return NextLogOut(it, 0, false) return NextLogOut(it, 0, false)
} }
it.nextIt.Close() it.nextIt.Close()
it.nextIt = it.ts.GetTripleIterator(it.direction, candidate) it.nextIt = it.ts.GetTripleIterator(it.dir, candidate)
// Recurse -- return the first in the next set. // Recurse -- return the first in the next set.
return it.Next() return it.Next()
} }

View file

@ -23,10 +23,10 @@ func TestLinksTo(t *testing.T) {
tsFixed := newFixedIterator() tsFixed := newFixedIterator()
tsFixed.AddValue(2) tsFixed.AddValue(2)
ts.On("GetIdFor", "cool").Return(1) ts.On("GetIdFor", "cool").Return(1)
ts.On("GetTripleIterator", "o", 1).Return(tsFixed) ts.On("GetTripleIterator", Object, 1).Return(tsFixed)
fixed := newFixedIterator() fixed := newFixedIterator()
fixed.AddValue(ts.GetIdFor("cool")) fixed.AddValue(ts.GetIdFor("cool"))
lto := NewLinksToIterator(ts, fixed, "o") lto := NewLinksToIterator(ts, fixed, Object)
val, ok := lto.Next() val, ok := lto.Next()
if !ok { if !ok {
t.Error("At least one triple matches the fixed object") t.Error("At least one triple matches the fixed object")

View file

@ -39,29 +39,30 @@ func NewTripleDirectionIndex() *TripleDirectionIndex {
return &tdi return &tdi
} }
func (tdi *TripleDirectionIndex) GetForDir(s string) map[int64]*llrb.LLRB { func (tdi *TripleDirectionIndex) GetForDir(d graph.Direction) map[int64]*llrb.LLRB {
if s == "s" { switch d {
case graph.Subject:
return tdi.subject return tdi.subject
} else if s == "o" { case graph.Object:
return tdi.object return tdi.object
} else if s == "p" { case graph.Predicate:
return tdi.predicate return tdi.predicate
} else if s == "c" { case graph.Provenance:
return tdi.provenance return tdi.provenance
} }
panic("Bad direction") panic("illegal direction")
} }
func (tdi *TripleDirectionIndex) GetOrCreate(dir string, id int64) *llrb.LLRB { func (tdi *TripleDirectionIndex) GetOrCreate(d graph.Direction, id int64) *llrb.LLRB {
directionIndex := tdi.GetForDir(dir) directionIndex := tdi.GetForDir(d)
if _, ok := directionIndex[id]; !ok { if _, ok := directionIndex[id]; !ok {
directionIndex[id] = llrb.New() directionIndex[id] = llrb.New()
} }
return directionIndex[id] return directionIndex[id]
} }
func (tdi *TripleDirectionIndex) Get(dir string, id int64) (*llrb.LLRB, bool) { func (tdi *TripleDirectionIndex) Get(d graph.Direction, id int64) (*llrb.LLRB, bool) {
directionIndex := tdi.GetForDir(dir) directionIndex := tdi.GetForDir(d)
tree, exists := directionIndex[id] tree, exists := directionIndex[id]
return tree, exists return tree, exists
} }
@ -101,9 +102,9 @@ func (ts *TripleStore) AddTripleSet(triples []*graph.Triple) {
func (ts *TripleStore) tripleExists(t *graph.Triple) (bool, int64) { func (ts *TripleStore) tripleExists(t *graph.Triple) (bool, int64) {
smallest := -1 smallest := -1
var smallest_tree *llrb.LLRB var smallest_tree *llrb.LLRB
for _, dir := range graph.TripleDirections { for d := graph.Subject; d <= graph.Provenance; d++ {
sid := t.Get(dir) sid := t.Get(d)
if dir == "c" && sid == "" { if d == graph.Provenance && sid == "" {
continue continue
} }
id, ok := ts.idMap[sid] id, ok := ts.idMap[sid]
@ -111,7 +112,7 @@ func (ts *TripleStore) tripleExists(t *graph.Triple) (bool, int64) {
if !ok { if !ok {
return false, 0 return false, 0
} }
index, exists := ts.index.Get(dir, id) index, exists := ts.index.Get(d, id)
if !exists { if !exists {
// If it's never been indexed in this direction, it can't exist. // If it's never been indexed in this direction, it can't exist.
return false, 0 return false, 0
@ -145,9 +146,9 @@ func (ts *TripleStore) AddTriple(t *graph.Triple) {
ts.size++ ts.size++
ts.tripleIdCounter++ ts.tripleIdCounter++
for _, dir := range graph.TripleDirections { for d := graph.Subject; d <= graph.Provenance; d++ {
sid := t.Get(dir) sid := t.Get(d)
if dir == "c" && sid == "" { if d == graph.Provenance && sid == "" {
continue continue
} }
if _, ok := ts.idMap[sid]; !ok { if _, ok := ts.idMap[sid]; !ok {
@ -157,12 +158,12 @@ func (ts *TripleStore) AddTriple(t *graph.Triple) {
} }
} }
for _, dir := range graph.TripleDirections { for d := graph.Subject; d <= graph.Provenance; d++ {
if dir == "c" && t.Get(dir) == "" { if d == graph.Provenance && t.Get(d) == "" {
continue continue
} }
id := ts.idMap[t.Get(dir)] id := ts.idMap[t.Get(d)]
tree := ts.index.GetOrCreate(dir, id) tree := ts.index.GetOrCreate(d, id)
tree.ReplaceOrInsert(Int64(tripleID)) tree.ReplaceOrInsert(Int64(tripleID))
} }
@ -180,36 +181,36 @@ func (ts *TripleStore) RemoveTriple(t *graph.Triple) {
ts.triples[tripleID] = graph.Triple{} ts.triples[tripleID] = graph.Triple{}
ts.size-- ts.size--
for _, dir := range graph.TripleDirections { for d := graph.Subject; d <= graph.Provenance; d++ {
if dir == "c" && t.Get(dir) == "" { if d == graph.Provenance && t.Get(d) == "" {
continue continue
} }
id := ts.idMap[t.Get(dir)] id := ts.idMap[t.Get(d)]
tree := ts.index.GetOrCreate(dir, id) tree := ts.index.GetOrCreate(d, id)
tree.Delete(Int64(tripleID)) tree.Delete(Int64(tripleID))
} }
for _, dir := range graph.TripleDirections { for d := graph.Subject; d <= graph.Provenance; d++ {
if dir == "c" && t.Get(dir) == "" { if d == graph.Provenance && t.Get(d) == "" {
continue continue
} }
id, ok := ts.idMap[t.Get(dir)] id, ok := ts.idMap[t.Get(d)]
if !ok { if !ok {
continue continue
} }
stillExists := false stillExists := false
for _, dir := range graph.TripleDirections { for d := graph.Subject; d <= graph.Provenance; d++ {
if dir == "c" && t.Get(dir) == "" { if d == graph.Provenance && t.Get(d) == "" {
continue continue
} }
nodeTree := ts.index.GetOrCreate(dir, id) nodeTree := ts.index.GetOrCreate(d, id)
if nodeTree.Len() != 0 { if nodeTree.Len() != 0 {
stillExists = true stillExists = true
break break
} }
} }
if !stillExists { if !stillExists {
delete(ts.idMap, t.Get(dir)) delete(ts.idMap, t.Get(d))
delete(ts.revIdMap, id) delete(ts.revIdMap, id)
} }
} }
@ -219,9 +220,9 @@ func (ts *TripleStore) GetTriple(index graph.TSVal) *graph.Triple {
return &ts.triples[index.(int64)] return &ts.triples[index.(int64)]
} }
func (ts *TripleStore) GetTripleIterator(direction string, value graph.TSVal) graph.Iterator { func (ts *TripleStore) GetTripleIterator(d graph.Direction, value graph.TSVal) graph.Iterator {
index, ok := ts.index.Get(direction, value.(int64)) index, ok := ts.index.Get(d, value.(int64))
data := fmt.Sprintf("dir:%s val:%d", direction, value.(int64)) data := fmt.Sprintf("dir:%s val:%d", d, value.(int64))
if ok { if ok {
return NewLlrbIterator(index, data) return NewLlrbIterator(index, data)
} }
@ -257,8 +258,8 @@ func (ts *TripleStore) MakeFixed() *graph.FixedIterator {
return graph.NewFixedIteratorWithCompare(graph.BasicEquality) return graph.NewFixedIteratorWithCompare(graph.BasicEquality)
} }
func (ts *TripleStore) GetTripleDirection(val graph.TSVal, direction string) graph.TSVal { func (ts *TripleStore) GetTripleDirection(val graph.TSVal, d graph.Direction) graph.TSVal {
name := ts.GetTriple(val).Get(direction) name := ts.GetTriple(val).Get(d)
return ts.GetIdFor(name) return ts.GetIdFor(name)
} }

View file

@ -41,15 +41,15 @@ func TestIteratorsAndNextResultOrderA(t *testing.T) {
fixed := ts.MakeFixed() fixed := ts.MakeFixed()
fixed.AddValue(ts.GetIdFor("C")) fixed.AddValue(ts.GetIdFor("C"))
all := ts.GetNodesAllIterator() all := ts.GetNodesAllIterator()
lto := graph.NewLinksToIterator(ts, all, "o") lto := graph.NewLinksToIterator(ts, all, graph.Object)
innerAnd := graph.NewAndIterator() innerAnd := graph.NewAndIterator()
fixed2 := ts.MakeFixed() fixed2 := ts.MakeFixed()
fixed2.AddValue(ts.GetIdFor("follows")) fixed2.AddValue(ts.GetIdFor("follows"))
lto2 := graph.NewLinksToIterator(ts, fixed2, "p") lto2 := graph.NewLinksToIterator(ts, fixed2, graph.Predicate)
innerAnd.AddSubIterator(lto2) innerAnd.AddSubIterator(lto2)
innerAnd.AddSubIterator(lto) innerAnd.AddSubIterator(lto)
hasa := graph.NewHasaIterator(ts, innerAnd, "s") hasa := graph.NewHasaIterator(ts, innerAnd, graph.Subject)
outerAnd := graph.NewAndIterator() outerAnd := graph.NewAndIterator()
outerAnd.AddSubIterator(fixed) outerAnd.AddSubIterator(fixed)
outerAnd.AddSubIterator(hasa) outerAnd.AddSubIterator(hasa)
@ -98,7 +98,7 @@ func TestLinksToOptimization(t *testing.T) {
ts := MakeTestingMemstore() ts := MakeTestingMemstore()
fixed := ts.MakeFixed() fixed := ts.MakeFixed()
fixed.AddValue(ts.GetIdFor("cool")) fixed.AddValue(ts.GetIdFor("cool"))
lto := graph.NewLinksToIterator(ts, fixed, "o") lto := graph.NewLinksToIterator(ts, fixed, graph.Object)
lto.AddTag("foo") lto.AddTag("foo")
newIt, changed := lto.Optimize() newIt, changed := lto.Optimize()
if !changed { if !changed {
@ -122,14 +122,14 @@ func TestRemoveTriple(t *testing.T) {
ts.RemoveTriple(graph.MakeTriple("E", "follows", "F", "")) ts.RemoveTriple(graph.MakeTriple("E", "follows", "F", ""))
fixed := ts.MakeFixed() fixed := ts.MakeFixed()
fixed.AddValue(ts.GetIdFor("E")) fixed.AddValue(ts.GetIdFor("E"))
lto := graph.NewLinksToIterator(ts, fixed, "s") lto := graph.NewLinksToIterator(ts, fixed, graph.Subject)
fixed2 := ts.MakeFixed() fixed2 := ts.MakeFixed()
fixed2.AddValue(ts.GetIdFor("follows")) fixed2.AddValue(ts.GetIdFor("follows"))
lto2 := graph.NewLinksToIterator(ts, fixed2, "p") lto2 := graph.NewLinksToIterator(ts, fixed2, graph.Predicate)
innerAnd := graph.NewAndIterator() innerAnd := graph.NewAndIterator()
innerAnd.AddSubIterator(lto2) innerAnd.AddSubIterator(lto2)
innerAnd.AddSubIterator(lto) innerAnd.AddSubIterator(lto)
hasa := graph.NewHasaIterator(ts, innerAnd, "o") hasa := graph.NewHasaIterator(ts, innerAnd, graph.Object)
newIt, _ := hasa.Optimize() newIt, _ := hasa.Optimize()
_, ok := newIt.Next() _, ok := newIt.Next()
if ok { if ok {

View file

@ -32,8 +32,8 @@ func (ts *TestTripleStore) GetIdFor(s string) TSVal {
func (ts *TestTripleStore) AddTriple(*Triple) {} func (ts *TestTripleStore) AddTriple(*Triple) {}
func (ts *TestTripleStore) AddTripleSet([]*Triple) {} func (ts *TestTripleStore) AddTripleSet([]*Triple) {}
func (ts *TestTripleStore) GetTriple(TSVal) *Triple { return &Triple{} } func (ts *TestTripleStore) GetTriple(TSVal) *Triple { return &Triple{} }
func (ts *TestTripleStore) GetTripleIterator(s string, i TSVal) Iterator { func (ts *TestTripleStore) GetTripleIterator(d Direction, i TSVal) Iterator {
args := ts.Mock.Called(s, i) args := ts.Mock.Called(d, i)
return args.Get(0).(Iterator) return args.Get(0).(Iterator)
} }
func (ts *TestTripleStore) GetNodesAllIterator() Iterator { return &NullIterator{} } func (ts *TestTripleStore) GetNodesAllIterator() Iterator { return &NullIterator{} }
@ -53,6 +53,6 @@ func (ts *TestTripleStore) OptimizeIterator(it Iterator) (Iterator, bool) {
func (ts *TestTripleStore) MakeFixed() *FixedIterator { func (ts *TestTripleStore) MakeFixed() *FixedIterator {
return NewFixedIteratorWithCompare(BasicEquality) return NewFixedIteratorWithCompare(BasicEquality)
} }
func (ts *TestTripleStore) Close() {} func (ts *TestTripleStore) Close() {}
func (ts *TestTripleStore) GetTripleDirection(TSVal, string) TSVal { return 0 } func (ts *TestTripleStore) GetTripleDirection(TSVal, Direction) TSVal { return 0 }
func (ts *TestTripleStore) RemoveTriple(t *Triple) {} func (ts *TestTripleStore) RemoveTriple(t *Triple) {}

View file

@ -28,7 +28,7 @@ import (
type Iterator struct { type Iterator struct {
graph.BaseIterator graph.BaseIterator
ts *TripleStore ts *TripleStore
dir string dir graph.Direction
iter *mgo.Iter iter *mgo.Iter
hash string hash string
name string name string
@ -38,26 +38,25 @@ type Iterator struct {
collection string collection string
} }
func NewIterator(ts *TripleStore, collection string, dir string, val graph.TSVal) *Iterator { func NewIterator(ts *TripleStore, collection string, d graph.Direction, val graph.TSVal) *Iterator {
var m Iterator var m Iterator
graph.BaseIteratorInit(&m.BaseIterator) graph.BaseIteratorInit(&m.BaseIterator)
m.name = ts.GetNameFor(val) m.name = ts.GetNameFor(val)
m.collection = collection m.collection = collection
switch dir { switch d {
case graph.Subject:
case "s": m.constraint = bson.M{"Subject": m.name}
m.constraint = bson.M{"Sub": m.name} case graph.Predicate:
case "p": m.constraint = bson.M{"Predicate": m.name}
m.constraint = bson.M{"Pred": m.name} case graph.Object:
case "o": m.constraint = bson.M{"Object": m.name}
m.constraint = bson.M{"Obj": m.name} case graph.Provenance:
case "c":
m.constraint = bson.M{"Provenance": m.name} m.constraint = bson.M{"Provenance": m.name}
} }
m.ts = ts m.ts = ts
m.dir = dir m.dir = d
m.iter = ts.db.C(collection).Find(m.constraint).Iter() m.iter = ts.db.C(collection).Find(m.constraint).Iter()
size, err := ts.db.C(collection).Find(m.constraint).Count() size, err := ts.db.C(collection).Find(m.constraint).Count()
if err != nil { if err != nil {
@ -73,7 +72,7 @@ func NewIterator(ts *TripleStore, collection string, dir string, val graph.TSVal
func NewAllIterator(ts *TripleStore, collection string) *Iterator { func NewAllIterator(ts *TripleStore, collection string) *Iterator {
var m Iterator var m Iterator
m.ts = ts m.ts = ts
m.dir = "all" m.dir = graph.Any
m.constraint = nil m.constraint = nil
m.collection = collection m.collection = collection
m.iter = ts.db.C(collection).Find(nil).Iter() m.iter = ts.db.C(collection).Find(nil).Iter()
@ -136,13 +135,13 @@ func (it *Iterator) Check(v graph.TSVal) bool {
} }
var offset int var offset int
switch it.dir { switch it.dir {
case "s": case graph.Subject:
offset = 0 offset = 0
case "p": case graph.Predicate:
offset = (it.ts.hasher.Size() * 2) offset = (it.ts.hasher.Size() * 2)
case "o": case graph.Object:
offset = (it.ts.hasher.Size() * 2) * 2 offset = (it.ts.hasher.Size() * 2) * 2
case "c": case graph.Provenance:
offset = (it.ts.hasher.Size() * 2) * 3 offset = (it.ts.hasher.Size() * 2) * 3
} }
val := v.(string)[offset : it.ts.hasher.Size()*2+offset] val := v.(string)[offset : it.ts.hasher.Size()*2+offset]

View file

@ -84,9 +84,9 @@ func NewTripleStore(addr string, options graph.OptionsDict) *TripleStore {
} }
func (ts *TripleStore) getIdForTriple(t *graph.Triple) string { func (ts *TripleStore) getIdForTriple(t *graph.Triple) string {
id := ts.ConvertStringToByteHash(t.Sub) id := ts.ConvertStringToByteHash(t.Subject)
id += ts.ConvertStringToByteHash(t.Pred) id += ts.ConvertStringToByteHash(t.Predicate)
id += ts.ConvertStringToByteHash(t.Obj) id += ts.ConvertStringToByteHash(t.Object)
id += ts.ConvertStringToByteHash(t.Provenance) id += ts.ConvertStringToByteHash(t.Provenance)
return id return id
} }
@ -143,7 +143,13 @@ func (ts *TripleStore) updateNodeBy(node_name string, inc int) {
} }
func (ts *TripleStore) writeTriple(t *graph.Triple) bool { func (ts *TripleStore) writeTriple(t *graph.Triple) bool {
tripledoc := bson.M{"_id": ts.getIdForTriple(t), "Sub": t.Sub, "Pred": t.Pred, "Obj": t.Obj, "Provenance": t.Provenance} tripledoc := bson.M{
"_id": ts.getIdForTriple(t),
"Subject": t.Subject,
"Predicate": t.Predicate,
"Object": t.Object,
"Provenance": t.Provenance,
}
err := ts.db.C("triples").Insert(tripledoc) err := ts.db.C("triples").Insert(tripledoc)
if err != nil { if err != nil {
// Among the reasons I hate MongoDB. "Errors don't happen! Right guys?" // Among the reasons I hate MongoDB. "Errors don't happen! Right guys?"
@ -158,9 +164,9 @@ func (ts *TripleStore) writeTriple(t *graph.Triple) bool {
func (ts *TripleStore) AddTriple(t *graph.Triple) { func (ts *TripleStore) AddTriple(t *graph.Triple) {
_ = ts.writeTriple(t) _ = ts.writeTriple(t)
ts.updateNodeBy(t.Sub, 1) ts.updateNodeBy(t.Subject, 1)
ts.updateNodeBy(t.Pred, 1) ts.updateNodeBy(t.Predicate, 1)
ts.updateNodeBy(t.Obj, 1) ts.updateNodeBy(t.Object, 1)
if t.Provenance != "" { if t.Provenance != "" {
ts.updateNodeBy(t.Provenance, 1) ts.updateNodeBy(t.Provenance, 1)
} }
@ -168,19 +174,19 @@ func (ts *TripleStore) AddTriple(t *graph.Triple) {
func (ts *TripleStore) AddTripleSet(in []*graph.Triple) { func (ts *TripleStore) AddTripleSet(in []*graph.Triple) {
ts.session.SetSafe(nil) ts.session.SetSafe(nil)
idMap := make(map[string]int) ids := make(map[string]int)
for _, t := range in { for _, t := range in {
wrote := ts.writeTriple(t) wrote := ts.writeTriple(t)
if wrote { if wrote {
idMap[t.Sub]++ ids[t.Subject]++
idMap[t.Obj]++ ids[t.Object]++
idMap[t.Pred]++ ids[t.Predicate]++
if t.Provenance != "" { if t.Provenance != "" {
idMap[t.Provenance]++ ids[t.Provenance]++
} }
} }
} }
for k, v := range idMap { for k, v := range ids {
ts.updateNodeBy(k, v) ts.updateNodeBy(k, v)
} }
ts.session.SetSafe(&mgo.Safe{}) ts.session.SetSafe(&mgo.Safe{})
@ -194,9 +200,9 @@ func (ts *TripleStore) RemoveTriple(t *graph.Triple) {
log.Println("Error: ", err, " while removing triple ", t) log.Println("Error: ", err, " while removing triple ", t)
return return
} }
ts.updateNodeBy(t.Sub, -1) ts.updateNodeBy(t.Subject, -1)
ts.updateNodeBy(t.Pred, -1) ts.updateNodeBy(t.Predicate, -1)
ts.updateNodeBy(t.Obj, -1) ts.updateNodeBy(t.Object, -1)
if t.Provenance != "" { if t.Provenance != "" {
ts.updateNodeBy(t.Provenance, -1) ts.updateNodeBy(t.Provenance, -1)
} }
@ -215,8 +221,8 @@ func (ts *TripleStore) GetTriple(val graph.TSVal) *graph.Triple {
bsonDoc["Provenance"].(string)) bsonDoc["Provenance"].(string))
} }
func (ts *TripleStore) GetTripleIterator(dir string, val graph.TSVal) graph.Iterator { func (ts *TripleStore) GetTripleIterator(d graph.Direction, val graph.TSVal) graph.Iterator {
return NewIterator(ts, "triples", dir, val) return NewIterator(ts, "triples", d, val)
} }
func (ts *TripleStore) GetNodesAllIterator() graph.Iterator { func (ts *TripleStore) GetNodesAllIterator() graph.Iterator {
@ -266,17 +272,17 @@ func (ts *TripleStore) Close() {
ts.db.Session.Close() ts.db.Session.Close()
} }
func (ts *TripleStore) GetTripleDirection(in graph.TSVal, dir string) graph.TSVal { func (ts *TripleStore) GetTripleDirection(in graph.TSVal, d graph.Direction) graph.TSVal {
// Maybe do the trick here // Maybe do the trick here
var offset int var offset int
switch dir { switch d {
case "s": case graph.Subject:
offset = 0 offset = 0
case "p": case graph.Predicate:
offset = (ts.hasher.Size() * 2) offset = (ts.hasher.Size() * 2)
case "o": case graph.Object:
offset = (ts.hasher.Size() * 2) * 2 offset = (ts.hasher.Size() * 2) * 2
case "c": case graph.Provenance:
offset = (ts.hasher.Size() * 2) * 3 offset = (ts.hasher.Size() * 2) * 3
} }
val := in.(string)[offset : ts.hasher.Size()*2+offset] val := in.(string)[offset : ts.hasher.Size()*2+offset]

View file

@ -35,17 +35,14 @@ type queryShape struct {
ts TripleStore ts TripleStore
nodeId int nodeId int
hasaIds []int hasaIds []int
hasaDirs []string hasaDirs []Direction
} }
func OutputQueryShapeForIterator(it Iterator, ts TripleStore, outputMap *map[string]interface{}) { func OutputQueryShapeForIterator(it Iterator, ts TripleStore, outputMap *map[string]interface{}) {
qs := &queryShape{} qs := &queryShape{
qs.nodes = make([]Node, 0) ts: ts,
qs.links = make([]Link, 0) nodeId: 1,
qs.hasaIds = make([]int, 0) }
qs.hasaDirs = make([]string, 0)
qs.ts = ts
qs.nodeId = 1
node := qs.MakeNode(it.Clone()) node := qs.MakeNode(it.Clone())
qs.AddNode(node) qs.AddNode(node)
@ -61,13 +58,13 @@ func (qs *queryShape) AddLink(l *Link) {
qs.links = append(qs.links, *l) qs.links = append(qs.links, *l)
} }
func (qs *queryShape) LastHasa() (int, string) { func (qs *queryShape) LastHasa() (int, Direction) {
return qs.hasaIds[len(qs.hasaIds)-1], qs.hasaDirs[len(qs.hasaDirs)-1] return qs.hasaIds[len(qs.hasaIds)-1], qs.hasaDirs[len(qs.hasaDirs)-1]
} }
func (qs *queryShape) PushHasa(i int, s string) { func (qs *queryShape) PushHasa(i int, d Direction) {
qs.hasaIds = append(qs.hasaIds, i) qs.hasaIds = append(qs.hasaIds, i)
qs.hasaDirs = append(qs.hasaDirs, s) qs.hasaDirs = append(qs.hasaDirs, d)
} }
func (qs *queryShape) RemoveHasa() { func (qs *queryShape) RemoveHasa() {
@ -136,7 +133,7 @@ func (qs *queryShape) MakeNode(it Iterator) *Node {
} }
case "hasa": case "hasa":
hasa := it.(*HasaIterator) hasa := it.(*HasaIterator)
qs.PushHasa(n.Id, hasa.direction) qs.PushHasa(n.Id, hasa.dir)
qs.nodeId++ qs.nodeId++
newNode := qs.MakeNode(hasa.primaryIt) newNode := qs.MakeNode(hasa.primaryIt)
qs.AddNode(newNode) qs.AddNode(newNode)
@ -158,10 +155,10 @@ func (qs *queryShape) MakeNode(it Iterator) *Node {
qs.nodeId++ qs.nodeId++
newNode := qs.MakeNode(lto.primaryIt) newNode := qs.MakeNode(lto.primaryIt)
hasaID, hasaDir := qs.LastHasa() hasaID, hasaDir := qs.LastHasa()
if (hasaDir == "s" && lto.direction == "o") || if (hasaDir == Subject && lto.dir == Object) ||
(hasaDir == "o" && lto.direction == "s") { (hasaDir == Object && lto.dir == Subject) {
qs.AddNode(newNode) qs.AddNode(newNode)
if hasaDir == "s" { if hasaDir == Subject {
qs.AddLink(&Link{hasaID, newNode.Id, 0, n.Id}) qs.AddLink(&Link{hasaID, newNode.Id, 0, n.Id})
} else { } else {
qs.AddLink(&Link{newNode.Id, hasaID, 0, n.Id}) qs.AddLink(&Link{newNode.Id, hasaID, 0, n.Id})

View file

@ -15,8 +15,9 @@
package graph package graph
import ( import (
. "github.com/smartystreets/goconvey/convey"
"testing" "testing"
. "github.com/smartystreets/goconvey/convey"
) )
func buildHasaWithTag(ts TripleStore, tag string, target string) *HasaIterator { func buildHasaWithTag(ts TripleStore, tag string, target string) *HasaIterator {
@ -25,12 +26,12 @@ func buildHasaWithTag(ts TripleStore, tag string, target string) *HasaIterator {
fixed_obj.AddValue(ts.GetIdFor(target)) fixed_obj.AddValue(ts.GetIdFor(target))
fixed_pred.AddValue(ts.GetIdFor("status")) fixed_pred.AddValue(ts.GetIdFor("status"))
fixed_obj.AddTag(tag) fixed_obj.AddTag(tag)
lto1 := NewLinksToIterator(ts, fixed_obj, "o") lto1 := NewLinksToIterator(ts, fixed_obj, Object)
lto2 := NewLinksToIterator(ts, fixed_pred, "p") lto2 := NewLinksToIterator(ts, fixed_pred, Predicate)
and := NewAndIterator() and := NewAndIterator()
and.AddSubIterator(lto1) and.AddSubIterator(lto1)
and.AddSubIterator(lto2) and.AddSubIterator(lto2)
hasa := NewHasaIterator(ts, and, "s") hasa := NewHasaIterator(ts, and, Subject)
return hasa return hasa
} }
@ -91,12 +92,12 @@ func TestQueryShape(t *testing.T) {
andInternal.AddSubIterator(hasa2) andInternal.AddSubIterator(hasa2)
fixed_pred := ts.MakeFixed() fixed_pred := ts.MakeFixed()
fixed_pred.AddValue(ts.GetIdFor("name")) fixed_pred.AddValue(ts.GetIdFor("name"))
lto1 := NewLinksToIterator(ts, andInternal, "s") lto1 := NewLinksToIterator(ts, andInternal, Subject)
lto2 := NewLinksToIterator(ts, fixed_pred, "p") lto2 := NewLinksToIterator(ts, fixed_pred, Predicate)
and := NewAndIterator() and := NewAndIterator()
and.AddSubIterator(lto1) and.AddSubIterator(lto1)
and.AddSubIterator(lto2) and.AddSubIterator(lto2)
hasa := NewHasaIterator(ts, and, "o") hasa := NewHasaIterator(ts, and, Object)
OutputQueryShapeForIterator(hasa, ts, &queryShape) OutputQueryShapeForIterator(hasa, ts, &queryShape)
Convey("It should have seven nodes and three links", func() { Convey("It should have seven nodes and three links", func() {

View file

@ -207,7 +207,7 @@ func buildIteratorTree(tree *peg.ExpressionTree, ts graph.TripleStore) graph.Ite
i++ i++
} }
it := buildIteratorTree(tree.Children[i], ts) it := buildIteratorTree(tree.Children[i], ts)
lto := graph.NewLinksToIterator(ts, it, "p") lto := graph.NewLinksToIterator(ts, it, graph.Predicate)
return lto return lto
case "RootConstraint": case "RootConstraint":
constraintCount := 0 constraintCount := 0
@ -228,16 +228,16 @@ func buildIteratorTree(tree *peg.ExpressionTree, ts graph.TripleStore) graph.Ite
return and return and
case "Constraint": case "Constraint":
var hasa *graph.HasaIterator var hasa *graph.HasaIterator
topLevelDir := "s" topLevelDir := graph.Subject
subItDir := "o" subItDir := graph.Object
subAnd := graph.NewAndIterator() subAnd := graph.NewAndIterator()
isOptional := false isOptional := false
for _, c := range tree.Children { for _, c := range tree.Children {
switch c.Name { switch c.Name {
case "PredIdentifier": case "PredIdentifier":
if c.Children[0].Name == "Reverse" { if c.Children[0].Name == "Reverse" {
topLevelDir = "o" topLevelDir = graph.Object
subItDir = "s" subItDir = graph.Subject
} }
it := buildIteratorTree(c, ts) it := buildIteratorTree(c, ts)
subAnd.AddSubIterator(it) subAnd.AddSubIterator(it)

View file

@ -1,4 +1,4 @@
// Copyright 2014 The Cayley Authors. All rights reserved. // Copyright 2014 The Cayley Authors. Any rights reserved.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -35,16 +35,13 @@ package graph
// There will never be that much in this file except for the definition, but // There will never be that much in this file except for the definition, but
// the consequences are not to be taken lightly. But do suggest cool features! // the consequences are not to be taken lightly. But do suggest cool features!
import ( import "fmt"
"fmt"
"reflect"
)
// Our triple struct, used throughout. // Our triple struct, used throughout.
type Triple struct { type Triple struct {
Sub string `json:"subject"` Subject string `json:"subject"`
Pred string `json:"predicate"` Predicate string `json:"predicate"`
Obj string `json:"object"` Object string `json:"object"`
Provenance string `json:"provenance,omitempty"` Provenance string `json:"provenance,omitempty"`
} }
@ -56,43 +53,68 @@ func MakeTriple(sub string, pred string, obj string, provenance string) *Triple
return &Triple{sub, pred, obj, provenance} return &Triple{sub, pred, obj, provenance}
} }
// List of the valid directions of a triple. // Direction specifies an edge's type.
// TODO(barakmich): Replace all instances of "dir string" in the codebase type Direction byte
// with an enum of valid directions, to make this less stringly typed.
var TripleDirections = [4]string{"s", "p", "o", "c"}
// Per-field accessor for triples // List of the valid directions of a triple.
func (t *Triple) Get(dir string) string { const (
if dir == "s" { Any Direction = iota
return t.Sub Subject
} else if dir == "p" { Predicate
return t.Pred Object
} else if dir == "prov" || dir == "c" { Provenance
return t.Provenance )
} else if dir == "o" {
return t.Obj func (d Direction) String() string {
} else { switch d {
panic(fmt.Sprintf("No Such Triple Direction, %s", dir)) case Any:
return "a"
case Subject:
return "s"
case Predicate:
return "p"
case Provenance:
return "c"
case Object:
return "o"
default:
return fmt.Sprint("illegal direction:", byte(d))
} }
} }
func (t *Triple) Equals(other *Triple) bool { // Per-field accessor for triples
return reflect.DeepEqual(t, other) func (t *Triple) Get(d Direction) string {
switch d {
case Subject:
return t.Subject
case Predicate:
return t.Predicate
case Provenance:
return t.Provenance
case Object:
return t.Object
default:
panic(d.String())
}
}
func (t *Triple) Equals(o *Triple) bool {
return *t == *o
} }
// Pretty-prints a triple. // Pretty-prints a triple.
func (t *Triple) ToString() string { func (t *Triple) ToString() string {
return fmt.Sprintf("%s -- %s -> %s\n", t.Sub, t.Pred, t.Obj) return fmt.Sprintf("%s -- %s -> %s\n", t.Subject, t.Predicate, t.Object)
} }
func (t *Triple) IsValid() bool { func (t *Triple) IsValid() bool {
if t.Sub == "" { if t.Subject == "" {
return false return false
} }
if t.Pred == "" { if t.Predicate == "" {
return false return false
} }
if t.Obj == "" { if t.Object == "" {
return false return false
} }
return true return true
@ -102,8 +124,8 @@ func (t *Triple) IsValid() bool {
func (t *Triple) ToNTriple() string { func (t *Triple) ToNTriple() string {
if t.Provenance == "" { if t.Provenance == "" {
//TODO(barakmich): Proper escaping. //TODO(barakmich): Proper escaping.
return fmt.Sprintf("%s %s %s .", t.Sub, t.Pred, t.Obj) return fmt.Sprintf("%s %s %s .", t.Subject, t.Predicate, t.Object)
} else { } else {
return fmt.Sprintf("%s %s %s %s .", t.Sub, t.Pred, t.Obj, t.Provenance) return fmt.Sprintf("%s %s %s %s .", t.Subject, t.Predicate, t.Object, t.Provenance)
} }
} }

View file

@ -51,7 +51,7 @@ type TripleStore interface {
// Given a direction and a token, creates an iterator of links which have // Given a direction and a token, creates an iterator of links which have
// that node token in that directional field. // that node token in that directional field.
GetTripleIterator(string, TSVal) Iterator GetTripleIterator(Direction, TSVal) Iterator
// Returns an iterator enumerating all nodes in the graph. // Returns an iterator enumerating all nodes in the graph.
GetNodesAllIterator() Iterator GetNodesAllIterator() Iterator
@ -89,7 +89,7 @@ type TripleStore interface {
// //
// Iterators will call this. At worst, a valid implementation is // Iterators will call this. At worst, a valid implementation is
// self.GetIdFor(self.GetTriple(triple_id).Get(dir)) // self.GetIdFor(self.GetTriple(triple_id).Get(dir))
GetTripleDirection(triple_id TSVal, dir string) TSVal GetTripleDirection(triple_id TSVal, d Direction) TSVal
} }
type OptionsDict map[string]interface{} type OptionsDict map[string]interface{}

View file

@ -16,6 +16,7 @@ package http
import ( import (
"testing" "testing"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
) )
@ -28,7 +29,7 @@ func TestParseJSONOkay(t *testing.T) {
x, err := ParseJsonToTripleList(bytelist) x, err := ParseJsonToTripleList(bytelist)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(x), ShouldEqual, 2) So(len(x), ShouldEqual, 2)
So(x[0].Sub, ShouldEqual, "foo") So(x[0].Subject, ShouldEqual, "foo")
So(x[0].Provenance, ShouldEqual, "") So(x[0].Provenance, ShouldEqual, "")
So(x[1].Provenance, ShouldEqual, "graph") So(x[1].Provenance, ShouldEqual, "graph")
}) })

View file

@ -35,55 +35,55 @@ func TestParsingNTriples(t *testing.T) {
Convey("It should parse simple triples", func() { Convey("It should parse simple triples", func() {
x := Parse("this is valid .") x := Parse("this is valid .")
So(x, ShouldNotBeNil) So(x, ShouldNotBeNil)
So(x.Sub, ShouldEqual, "this") So(x.Subject, ShouldEqual, "this")
}) })
Convey("It should parse quoted triples", func() { Convey("It should parse quoted triples", func() {
x := Parse("this is \"valid too\" .") x := Parse("this is \"valid too\" .")
So(x, ShouldNotBeNil) So(x, ShouldNotBeNil)
So(x.Obj, ShouldEqual, "valid too") So(x.Object, ShouldEqual, "valid too")
So(x.Provenance, ShouldEqual, "") So(x.Provenance, ShouldEqual, "")
}) })
Convey("It should parse escaped quoted triples", func() { Convey("It should parse escaped quoted triples", func() {
x := Parse("he said \"\\\"That's all folks\\\"\" .") x := Parse("he said \"\\\"That's all folks\\\"\" .")
So(x, ShouldNotBeNil) So(x, ShouldNotBeNil)
So(x.Obj, ShouldEqual, "\"That's all folks\"") So(x.Object, ShouldEqual, "\"That's all folks\"")
So(x.Provenance, ShouldEqual, "") So(x.Provenance, ShouldEqual, "")
}) })
Convey("It should parse an example real triple", func() { Convey("It should parse an example real triple", func() {
x := Parse("\":/guid/9202a8c04000641f80000000010c843c\" \"name\" \"George Morris\" .") x := Parse("\":/guid/9202a8c04000641f80000000010c843c\" \"name\" \"George Morris\" .")
So(x, ShouldNotBeNil) So(x, ShouldNotBeNil)
So(x.Obj, ShouldEqual, "George Morris") So(x.Object, ShouldEqual, "George Morris")
So(x.Provenance, ShouldEqual, "") So(x.Provenance, ShouldEqual, "")
}) })
Convey("It should parse a pathologically spaced triple", func() { Convey("It should parse a pathologically spaced triple", func() {
x := Parse("foo is \"\\tA big tough\\r\\nDeal\\\\\" .") x := Parse("foo is \"\\tA big tough\\r\\nDeal\\\\\" .")
So(x, ShouldNotBeNil) So(x, ShouldNotBeNil)
So(x.Obj, ShouldEqual, "\tA big tough\r\nDeal\\") So(x.Object, ShouldEqual, "\tA big tough\r\nDeal\\")
So(x.Provenance, ShouldEqual, "") So(x.Provenance, ShouldEqual, "")
}) })
Convey("It should parse a simple quad", func() { Convey("It should parse a simple quad", func() {
x := Parse("this is valid quad .") x := Parse("this is valid quad .")
So(x, ShouldNotBeNil) So(x, ShouldNotBeNil)
So(x.Obj, ShouldEqual, "valid") So(x.Object, ShouldEqual, "valid")
So(x.Provenance, ShouldEqual, "quad") So(x.Provenance, ShouldEqual, "quad")
}) })
Convey("It should parse a quoted quad", func() { Convey("It should parse a quoted quad", func() {
x := Parse("this is valid \"quad thing\" .") x := Parse("this is valid \"quad thing\" .")
So(x, ShouldNotBeNil) So(x, ShouldNotBeNil)
So(x.Obj, ShouldEqual, "valid") So(x.Object, ShouldEqual, "valid")
So(x.Provenance, ShouldEqual, "quad thing") So(x.Provenance, ShouldEqual, "quad thing")
}) })
Convey("It should parse crazy escaped quads", func() { Convey("It should parse crazy escaped quads", func() {
x := Parse("\"\\\"this\" \"\\\"is\" \"\\\"valid\" \"\\\"quad thing\".") x := Parse("\"\\\"this\" \"\\\"is\" \"\\\"valid\" \"\\\"quad thing\".")
So(x, ShouldNotBeNil) So(x, ShouldNotBeNil)
So(x.Sub, ShouldEqual, "\"this") So(x.Subject, ShouldEqual, "\"this")
So(x.Pred, ShouldEqual, "\"is") So(x.Predicate, ShouldEqual, "\"is")
So(x.Obj, ShouldEqual, "\"valid") So(x.Object, ShouldEqual, "\"valid")
So(x.Provenance, ShouldEqual, "\"quad thing") So(x.Provenance, ShouldEqual, "\"quad thing")
}) })
}) })
@ -95,27 +95,27 @@ func TestParsingNTriplesOfficial(t *testing.T) {
var x *graph.Triple var x *graph.Triple
x = Parse("<http://example/s> <http://example/p> <http://example/o> . # comment") x = Parse("<http://example/s> <http://example/p> <http://example/o> . # comment")
So(x, ShouldNotBeNil) So(x, ShouldNotBeNil)
So(x.Sub, ShouldEqual, "http://example/s") So(x.Subject, ShouldEqual, "http://example/s")
So(x.Pred, ShouldEqual, "http://example/p") So(x.Predicate, ShouldEqual, "http://example/p")
So(x.Obj, ShouldEqual, "http://example/o") So(x.Object, ShouldEqual, "http://example/o")
So(x.Provenance, ShouldEqual, "") So(x.Provenance, ShouldEqual, "")
x = Parse("<http://example/s> <http://example/p> _:o . # comment") x = Parse("<http://example/s> <http://example/p> _:o . # comment")
So(x, ShouldNotBeNil) So(x, ShouldNotBeNil)
So(x.Sub, ShouldEqual, "http://example/s") So(x.Subject, ShouldEqual, "http://example/s")
So(x.Pred, ShouldEqual, "http://example/p") So(x.Predicate, ShouldEqual, "http://example/p")
So(x.Obj, ShouldEqual, "_:o") So(x.Object, ShouldEqual, "_:o")
So(x.Provenance, ShouldEqual, "") So(x.Provenance, ShouldEqual, "")
x = Parse("<http://example/s> <http://example/p> \"o\" . # comment") x = Parse("<http://example/s> <http://example/p> \"o\" . # comment")
So(x, ShouldNotBeNil) So(x, ShouldNotBeNil)
So(x.Obj, ShouldEqual, "o") So(x.Object, ShouldEqual, "o")
So(x.Provenance, ShouldEqual, "") So(x.Provenance, ShouldEqual, "")
x = Parse("<http://example/s> <http://example/p> \"o\"^^<http://example/dt> . # comment") x = Parse("<http://example/s> <http://example/p> \"o\"^^<http://example/dt> . # comment")
So(x, ShouldNotBeNil) So(x, ShouldNotBeNil)
So(x.Obj, ShouldEqual, "o") So(x.Object, ShouldEqual, "o")
So(x.Provenance, ShouldEqual, "") So(x.Provenance, ShouldEqual, "")
x = Parse("<http://example/s> <http://example/p> \"o\"@en . # comment") x = Parse("<http://example/s> <http://example/p> \"o\"@en . # comment")
So(x, ShouldNotBeNil) So(x, ShouldNotBeNil)
So(x.Obj, ShouldEqual, "o") So(x.Object, ShouldEqual, "o")
So(x.Provenance, ShouldEqual, "") So(x.Provenance, ShouldEqual, "")
}) })
}) })
@ -124,7 +124,7 @@ func TestParsingNTriplesOfficial(t *testing.T) {
func BenchmarkParser(b *testing.B) { func BenchmarkParser(b *testing.B) {
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
x := Parse("<http://example/s> <http://example/p> \"object of some real\\tlength\"@en . # comment") x := Parse("<http://example/s> <http://example/p> \"object of some real\\tlength\"@en . # comment")
if x.Obj != "object of some real\tlength" { if x.Object != "object of some real\tlength" {
b.Fail() b.Fail()
} }
} }

View file

@ -138,13 +138,13 @@ func buildInOutIterator(obj *otto.Object, ts graph.TripleStore, base graph.Itera
} }
} }
in, out := "s", "o" in, out := graph.Subject, graph.Object
if isReverse { if isReverse {
in, out = out, in in, out = out, in
} }
lto := graph.NewLinksToIterator(ts, base, in) lto := graph.NewLinksToIterator(ts, base, in)
and := graph.NewAndIterator() and := graph.NewAndIterator()
and.AddSubIterator(graph.NewLinksToIterator(ts, predicateNodeIterator, "p")) and.AddSubIterator(graph.NewLinksToIterator(ts, predicateNodeIterator, graph.Predicate))
and.AddSubIterator(lto) and.AddSubIterator(lto)
return graph.NewHasaIterator(ts, and, out) return graph.NewHasaIterator(ts, and, out)
} }
@ -193,9 +193,9 @@ func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph.
predFixed := ts.MakeFixed() predFixed := ts.MakeFixed()
predFixed.AddValue(ts.GetIdFor(stringArgs[0])) predFixed.AddValue(ts.GetIdFor(stringArgs[0]))
subAnd := graph.NewAndIterator() subAnd := graph.NewAndIterator()
subAnd.AddSubIterator(graph.NewLinksToIterator(ts, predFixed, "p")) subAnd.AddSubIterator(graph.NewLinksToIterator(ts, predFixed, graph.Predicate))
subAnd.AddSubIterator(graph.NewLinksToIterator(ts, all, "o")) subAnd.AddSubIterator(graph.NewLinksToIterator(ts, all, graph.Object))
hasa := graph.NewHasaIterator(ts, subAnd, "s") hasa := graph.NewHasaIterator(ts, subAnd, graph.Subject)
and := graph.NewAndIterator() and := graph.NewAndIterator()
and.AddSubIterator(hasa) and.AddSubIterator(hasa)
and.AddSubIterator(subIt) and.AddSubIterator(subIt)
@ -213,9 +213,9 @@ func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph.
predFixed := ts.MakeFixed() predFixed := ts.MakeFixed()
predFixed.AddValue(ts.GetIdFor(stringArgs[0])) predFixed.AddValue(ts.GetIdFor(stringArgs[0]))
subAnd := graph.NewAndIterator() subAnd := graph.NewAndIterator()
subAnd.AddSubIterator(graph.NewLinksToIterator(ts, predFixed, "p")) subAnd.AddSubIterator(graph.NewLinksToIterator(ts, predFixed, graph.Predicate))
subAnd.AddSubIterator(graph.NewLinksToIterator(ts, all, "s")) subAnd.AddSubIterator(graph.NewLinksToIterator(ts, all, graph.Subject))
hasa := graph.NewHasaIterator(ts, subAnd, "o") hasa := graph.NewHasaIterator(ts, subAnd, graph.Object)
and := graph.NewAndIterator() and := graph.NewAndIterator()
and.AddSubIterator(hasa) and.AddSubIterator(hasa)
and.AddSubIterator(subIt) and.AddSubIterator(subIt)
@ -231,9 +231,9 @@ func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph.
predFixed := ts.MakeFixed() predFixed := ts.MakeFixed()
predFixed.AddValue(ts.GetIdFor(stringArgs[0])) predFixed.AddValue(ts.GetIdFor(stringArgs[0]))
subAnd := graph.NewAndIterator() subAnd := graph.NewAndIterator()
subAnd.AddSubIterator(graph.NewLinksToIterator(ts, predFixed, "p")) subAnd.AddSubIterator(graph.NewLinksToIterator(ts, predFixed, graph.Predicate))
subAnd.AddSubIterator(graph.NewLinksToIterator(ts, fixed, "o")) subAnd.AddSubIterator(graph.NewLinksToIterator(ts, fixed, graph.Object))
hasa := graph.NewHasaIterator(ts, subAnd, "s") hasa := graph.NewHasaIterator(ts, subAnd, graph.Subject)
and := graph.NewAndIterator() and := graph.NewAndIterator()
and.AddSubIterator(hasa) and.AddSubIterator(hasa)
and.AddSubIterator(subIt) and.AddSubIterator(subIt)

View file

@ -138,16 +138,16 @@ func (q *Query) buildIteratorTreeMapInternal(query map[string]interface{}, path
subAnd := graph.NewAndIterator() subAnd := graph.NewAndIterator()
predFixed := q.ses.ts.MakeFixed() predFixed := q.ses.ts.MakeFixed()
predFixed.AddValue(q.ses.ts.GetIdFor(pred)) predFixed.AddValue(q.ses.ts.GetIdFor(pred))
subAnd.AddSubIterator(graph.NewLinksToIterator(q.ses.ts, predFixed, "p")) subAnd.AddSubIterator(graph.NewLinksToIterator(q.ses.ts, predFixed, graph.Predicate))
if reverse { if reverse {
lto := graph.NewLinksToIterator(q.ses.ts, builtIt, "s") lto := graph.NewLinksToIterator(q.ses.ts, builtIt, graph.Subject)
subAnd.AddSubIterator(lto) subAnd.AddSubIterator(lto)
hasa := graph.NewHasaIterator(q.ses.ts, subAnd, "o") hasa := graph.NewHasaIterator(q.ses.ts, subAnd, graph.Object)
subit = hasa subit = hasa
} else { } else {
lto := graph.NewLinksToIterator(q.ses.ts, builtIt, "o") lto := graph.NewLinksToIterator(q.ses.ts, builtIt, graph.Object)
subAnd.AddSubIterator(lto) subAnd.AddSubIterator(lto)
hasa := graph.NewHasaIterator(q.ses.ts, subAnd, "s") hasa := graph.NewHasaIterator(q.ses.ts, subAnd, graph.Subject)
subit = hasa subit = hasa
} }
} }