From 0a03cec497710d13d827a09e9b77687556d3aafc Mon Sep 17 00:00:00 2001 From: kortschak Date: Mon, 30 Jun 2014 12:33:55 +0930 Subject: [PATCH 1/2] 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. --- graph/hasa_iterator.go | 18 +++--- graph/leveldb/all_iterator.go | 6 +- graph/leveldb/iterator.go | 50 +++++++-------- graph/leveldb/leveldb_test.go | 16 ++--- graph/leveldb/triplestore.go | 125 +++++++++++++++++++++---------------- graph/linksto_iterator.go | 16 ++--- graph/linksto_iterator_test.go | 4 +- graph/memstore/triplestore.go | 75 +++++++++++----------- graph/memstore/triplestore_test.go | 14 ++--- graph/mock_ts.go | 10 +-- graph/mongo/iterator.go | 33 +++++----- graph/mongo/triplestore.go | 54 +++++++++------- graph/query_shape.go | 27 ++++---- graph/query_shape_test.go | 15 ++--- graph/sexp/parser.go | 10 +-- graph/triple.go | 86 +++++++++++++++---------- graph/triplestore.go | 4 +- http/http_test.go | 3 +- nquads/nquads_test.go | 40 ++++++------ query/gremlin/build_iterator.go | 22 +++---- query/mql/build_iterator.go | 10 +-- 21 files changed, 340 insertions(+), 298 deletions(-) diff --git a/graph/hasa_iterator.go b/graph/hasa_iterator.go index c177538..16088c8 100644 --- a/graph/hasa_iterator.go +++ b/graph/hasa_iterator.go @@ -47,18 +47,18 @@ type HasaIterator struct { BaseIterator ts TripleStore primaryIt Iterator - direction string + dir Direction resultIt Iterator } // Construct a new HasA iterator, given the triple subiterator, and the triple // 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 BaseIteratorInit(&hasa.BaseIterator) hasa.ts = ts hasa.primaryIt = subIt - hasa.direction = dir + hasa.dir = d return &hasa } @@ -75,13 +75,13 @@ func (it *HasaIterator) Reset() { } 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) return out } // 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, // 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() { 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 @@ -130,7 +130,7 @@ func (it *HasaIterator) Check(val TSVal) bool { if it.resultIt != nil { 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()) } @@ -147,7 +147,7 @@ func (it *HasaIterator) GetCheckResult() bool { glog.V(4).Infoln("Triple is", it.ts.GetTriple(linkVal).ToString()) } if it.primaryIt.Check(linkVal) { - it.Last = it.ts.GetTripleDirection(linkVal, it.direction) + it.Last = it.ts.GetTripleDirection(linkVal, it.dir) return true } } @@ -182,7 +182,7 @@ func (it *HasaIterator) Next() (TSVal, bool) { if !ok { 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) it.Last = val return NextLogOut(it, val, true) diff --git a/graph/leveldb/all_iterator.go b/graph/leveldb/all_iterator.go index 2c1edb1..35d403f 100644 --- a/graph/leveldb/all_iterator.go +++ b/graph/leveldb/all_iterator.go @@ -28,21 +28,21 @@ import ( type AllIterator struct { graph.BaseIterator prefix []byte - dir string + dir graph.Direction open bool it iterator.Iterator ts *TripleStore ro *opt.ReadOptions } -func NewAllIterator(prefix, dir string, ts *TripleStore) *AllIterator { +func NewAllIterator(prefix string, d graph.Direction, ts *TripleStore) *AllIterator { var it AllIterator graph.BaseIteratorInit(&it.BaseIterator) it.ro = &opt.ReadOptions{} it.ro.DontFillCache = true it.it = ts.db.NewIterator(nil, it.ro) it.prefix = []byte(prefix) - it.dir = dir + it.dir = d it.open = true it.ts = ts it.it.Seek(it.prefix) diff --git a/graph/leveldb/iterator.go b/graph/leveldb/iterator.go index 05d122b..bb5fa07 100644 --- a/graph/leveldb/iterator.go +++ b/graph/leveldb/iterator.go @@ -29,7 +29,7 @@ type Iterator struct { graph.BaseIterator nextPrefix []byte checkId []byte - dir string + dir graph.Direction open bool it iterator.Iterator ts *TripleStore @@ -37,11 +37,11 @@ type Iterator struct { 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 graph.BaseIteratorInit(&it.BaseIterator) it.checkId = value.([]byte) - it.dir = dir + it.dir = d it.originalPrefix = prefix it.nextPrefix = make([]byte, 0, 2+ts.hasher.Size()) it.nextPrefix = append(it.nextPrefix, []byte(prefix)...) @@ -113,56 +113,56 @@ func (it *Iterator) Next() (graph.TSVal, bool) { 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")) { - switch dir { - case "s": + switch d { + case graph.Subject: return 2 - case "p": + case graph.Predicate: return ts.hasher.Size() + 2 - case "o": + case graph.Object: return 2*ts.hasher.Size() + 2 - case "c": + case graph.Provenance: return -1 } } if bytes.Equal(prefix, []byte("po")) { - switch dir { - case "s": + switch d { + case graph.Subject: return 2*ts.hasher.Size() + 2 - case "p": + case graph.Predicate: return 2 - case "o": + case graph.Object: return ts.hasher.Size() + 2 - case "c": + case graph.Provenance: return -1 } } if bytes.Equal(prefix, []byte("os")) { - switch dir { - case "s": + switch d { + case graph.Subject: return ts.hasher.Size() + 2 - case "p": + case graph.Predicate: return 2*ts.hasher.Size() + 2 - case "o": + case graph.Object: return 2 - case "c": + case graph.Provenance: return -1 } } if bytes.Equal(prefix, []byte("cp")) { - switch dir { - case "s": + switch d { + case graph.Subject: return 2*ts.hasher.Size() + 2 - case "p": + case graph.Predicate: return ts.hasher.Size() + 2 - case "o": + case graph.Object: return 3*ts.hasher.Size() + 2 - case "c": + case graph.Provenance: return 2 } } - panic("Notreached") + panic("unreachable") } func (it *Iterator) Check(v graph.TSVal) bool { diff --git a/graph/leveldb/leveldb_test.go b/graph/leveldb/leveldb_test.go index b4e9b61..91263c6 100644 --- a/graph/leveldb/leveldb_test.go +++ b/graph/leveldb/leveldb_test.go @@ -248,7 +248,7 @@ func TestSetIterator(t *testing.T) { var it graph.Iterator 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() { expected := []string{ @@ -282,7 +282,7 @@ func TestSetIterator(t *testing.T) { }) 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() { expected := []string{ @@ -297,7 +297,7 @@ func TestSetIterator(t *testing.T) { Convey("Mutually and-checkable", func() { and := graph.NewAndIterator() - and.AddSubIterator(ts.GetTripleIterator("s", ts.GetIdFor("B"))) + and.AddSubIterator(ts.GetTripleIterator(graph.Subject, ts.GetIdFor("B"))) and.AddSubIterator(it) expected := []string{ @@ -312,7 +312,7 @@ func TestSetIterator(t *testing.T) { }) 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() { expected := []string{ @@ -329,7 +329,7 @@ func TestSetIterator(t *testing.T) { }) 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() { expected := []string{ @@ -346,7 +346,7 @@ func TestSetIterator(t *testing.T) { Convey("Can be cross-checked", func() { and := graph.NewAndIterator() // Order is important - and.AddSubIterator(ts.GetTripleIterator("s", ts.GetIdFor("B"))) + and.AddSubIterator(ts.GetTripleIterator(graph.Subject, ts.GetIdFor("B"))) and.AddSubIterator(it) expected := []string{ @@ -360,7 +360,7 @@ func TestSetIterator(t *testing.T) { and := graph.NewAndIterator() // Order is important and.AddSubIterator(it) - and.AddSubIterator(ts.GetTripleIterator("s", ts.GetIdFor("B"))) + and.AddSubIterator(ts.GetTripleIterator(graph.Subject, ts.GetIdFor("B"))) expected := []string{ graph.MakeTriple("B", "status", "cool", "status_graph").ToString(), @@ -400,7 +400,7 @@ func TestOptimize(t *testing.T) { fixed := ts.MakeFixed() fixed.AddValue(ts.GetIdFor("F")) fixed.AddTag("internal") - lto = graph.NewLinksToIterator(ts, fixed, "o") + lto = graph.NewLinksToIterator(ts, fixed, graph.Object) Convey("Creates an appropriate iterator", func() { oldIt := lto.Clone() diff --git a/graph/leveldb/triplestore.go b/graph/leveldb/triplestore.go index 3a651c5..e386bf4 100644 --- a/graph/leveldb/triplestore.go +++ b/graph/leveldb/triplestore.go @@ -24,15 +24,17 @@ import ( "github.com/barakmich/glog" "github.com/syndtr/goleveldb/leveldb" - cache "github.com/syndtr/goleveldb/leveldb/cache" + "github.com/syndtr/goleveldb/leveldb/cache" "github.com/syndtr/goleveldb/leveldb/opt" - util "github.com/syndtr/goleveldb/leveldb/util" + "github.com/syndtr/goleveldb/leveldb/util" "github.com/google/cayley/graph" ) -const DefaultCacheSize = 2 -const DefaultWriteBufferSize = 20 +const ( + DefaultCacheSize = 2 + DefaultWriteBufferSize = 20 +) type TripleStore struct { dbOpts *opt.Options @@ -49,7 +51,7 @@ func CreateNewLevelDB(path string) bool { opts := &opt.Options{} db, err := leveldb.OpenFile(path, opts) if err != nil { - glog.Errorln("Error: couldn't create database", err) + glog.Errorln("Error: couldn't create database: ", err) return false } defer db.Close() @@ -108,22 +110,24 @@ func (ts *TripleStore) Size() int64 { 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 = append(key, []byte(dir1+dir2)...) - key = append(key, ts.convertStringToByteHash(triple.Get(dir1))...) - key = append(key, ts.convertStringToByteHash(triple.Get(dir2))...) - key = append(key, ts.convertStringToByteHash(triple.Get(dir3))...) + // TODO(kortschak) Remove dependence on String() method. + key = append(key, []byte(d[0].String()+d[1].String())...) + key = append(key, ts.convertStringToByteHash(triple.Get(d[0]))...) + key = append(key, ts.convertStringToByteHash(triple.Get(d[1]))...) + key = append(key, ts.convertStringToByteHash(triple.Get(d[2]))...) 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 = append(key, []byte("c"+dir1)...) - key = append(key, ts.convertStringToByteHash(triple.Get("c"))...) - key = append(key, ts.convertStringToByteHash(triple.Get(dir1))...) - key = append(key, ts.convertStringToByteHash(triple.Get(dir2))...) - key = append(key, ts.convertStringToByteHash(triple.Get(dir3))...) + // TODO(kortschak) Remove dependence on String() method. + key = append(key, []byte(graph.Provenance.String()+d[0].String())...) + key = append(key, ts.convertStringToByteHash(triple.Get(graph.Provenance))...) + key = append(key, ts.convertStringToByteHash(triple.Get(d[0]))...) + key = append(key, ts.convertStringToByteHash(triple.Get(d[1]))...) + key = append(key, ts.convertStringToByteHash(triple.Get(d[2]))...) return key } @@ -145,8 +149,16 @@ func (ts *TripleStore) AddTriple(t *graph.Triple) { 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) { - _, 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 { glog.Errorf("Couldn't access DB to confirm deletion") return @@ -156,15 +168,15 @@ func (ts *TripleStore) RemoveTriple(t *graph.Triple) { return } batch := &leveldb.Batch{} - batch.Delete(ts.createKeyFor("s", "p", "o", t)) - batch.Delete(ts.createKeyFor("o", "s", "p", t)) - batch.Delete(ts.createKeyFor("p", "o", "s", t)) - ts.UpdateValueKeyBy(t.Get("s"), -1, batch) - ts.UpdateValueKeyBy(t.Get("p"), -1, batch) - ts.UpdateValueKeyBy(t.Get("o"), -1, batch) - if t.Get("c") != "" { - batch.Delete(ts.createProvKeyFor("p", "s", "o", t)) - ts.UpdateValueKeyBy(t.Get("c"), -1, batch) + batch.Delete(ts.createKeyFor(spo, t)) + batch.Delete(ts.createKeyFor(osp, t)) + batch.Delete(ts.createKeyFor(pos, t)) + ts.UpdateValueKeyBy(t.Get(graph.Subject), -1, batch) + ts.UpdateValueKeyBy(t.Get(graph.Predicate), -1, batch) + ts.UpdateValueKeyBy(t.Get(graph.Object), -1, batch) + if t.Get(graph.Provenance) != "" { + batch.Delete(ts.createProvKeyFor(pso, t)) + ts.UpdateValueKeyBy(t.Get(graph.Provenance), -1, batch) } err = ts.db.Write(batch, 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) return } - batch.Put(ts.createKeyFor("s", "p", "o", t), bytes) - batch.Put(ts.createKeyFor("o", "s", "p", t), bytes) - batch.Put(ts.createKeyFor("p", "o", "s", t), bytes) - if t.Get("c") != "" { - batch.Put(ts.createProvKeyFor("p", "s", "o", t), bytes) + batch.Put(ts.createKeyFor(spo, t), bytes) + batch.Put(ts.createKeyFor(osp, t), bytes) + batch.Put(ts.createKeyFor(pos, t), bytes) + if t.Get(graph.Provenance) != "" { + batch.Put(ts.createProvKeyFor(pso, t), bytes) } } func (ts *TripleStore) buildWrite(batch *leveldb.Batch, t *graph.Triple) { ts.buildTripleWrite(batch, t) - ts.UpdateValueKeyBy(t.Get("s"), 1, nil) - ts.UpdateValueKeyBy(t.Get("p"), 1, nil) - ts.UpdateValueKeyBy(t.Get("o"), 1, nil) - if t.Get("c") != "" { - ts.UpdateValueKeyBy(t.Get("c"), 1, nil) + ts.UpdateValueKeyBy(t.Get(graph.Subject), 1, nil) + ts.UpdateValueKeyBy(t.Get(graph.Predicate), 1, nil) + ts.UpdateValueKeyBy(t.Get(graph.Object), 1, nil) + if t.Get(graph.Provenance) != "" { + 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) for _, t := range t_s { ts.buildTripleWrite(batch, t) - resizeMap[t.Sub]++ - resizeMap[t.Pred]++ - resizeMap[t.Obj]++ + resizeMap[t.Subject]++ + resizeMap[t.Predicate]++ + resizeMap[t.Object]++ if t.Provenance != "" { resizeMap[t.Provenance]++ } @@ -388,35 +400,38 @@ func (ts *TripleStore) GetApproximateSizeForPrefix(pre []byte) (int64, error) { return 0, nil } -func (ts *TripleStore) GetTripleIterator(dir string, val graph.TSVal) graph.Iterator { - switch dir { - case "s": - return NewIterator("sp", "s", val, ts) - case "p": - return NewIterator("po", "p", val, ts) - case "o": - return NewIterator("os", "o", val, ts) - case "c": - return NewIterator("cp", "c", val, ts) +func (ts *TripleStore) GetTripleIterator(d graph.Direction, val graph.TSVal) graph.Iterator { + var prefix string + switch d { + case graph.Subject: + prefix = "sp" + case graph.Predicate: + prefix = "po" + case graph.Object: + prefix = "os" + 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 { - return NewAllIterator("z", "v", ts) + return NewAllIterator("z", graph.Any, ts) } 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) - offset := GetPositionFromPrefix(v[0:2], direction, ts) + offset := GetPositionFromPrefix(v[0:2], d, ts) if offset != -1 { return append([]byte("z"), v[offset:offset+ts.hasher.Size()]...) } else { - return ts.GetTriple(val).Get(direction) + return ts.GetTriple(val).Get(d) } } diff --git a/graph/linksto_iterator.go b/graph/linksto_iterator.go index 61a42cb..b67c306 100644 --- a/graph/linksto_iterator.go +++ b/graph/linksto_iterator.go @@ -41,18 +41,18 @@ type LinksToIterator struct { BaseIterator ts TripleStore primaryIt Iterator - direction string + dir Direction nextIt Iterator } // Construct a new LinksTo iterator around a direction and a subiterator of // nodes. -func NewLinksToIterator(ts TripleStore, it Iterator, dir string) *LinksToIterator { +func NewLinksToIterator(ts TripleStore, it Iterator, d Direction) *LinksToIterator { var lto LinksToIterator BaseIteratorInit(<o.BaseIterator) lto.ts = ts lto.primaryIt = it - lto.direction = dir + lto.dir = d lto.nextIt = &NullIterator{} return <o } @@ -66,13 +66,13 @@ func (it *LinksToIterator) Reset() { } 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) return out } // 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. func (it *LinksToIterator) TagResults(out *map[string]TSVal) { @@ -91,14 +91,14 @@ func (it *LinksToIterator) GetResultTree() *ResultTree { func (it *LinksToIterator) DebugString(indent int) string { return fmt.Sprintf("%s(%s %d direction:%s\n%s)", 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 // for the LinksTo. func (it *LinksToIterator) Check(val TSVal) bool { CheckLogIn(it, val) - node := it.ts.GetTripleDirection(val, it.direction) + node := it.ts.GetTripleDirection(val, it.dir) if it.primaryIt.Check(node) { it.Last = val return CheckLogOut(it, val, true) @@ -144,7 +144,7 @@ func (it *LinksToIterator) Next() (TSVal, bool) { return NextLogOut(it, 0, false) } 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. return it.Next() } diff --git a/graph/linksto_iterator_test.go b/graph/linksto_iterator_test.go index 06cdd2a..7fbed33 100644 --- a/graph/linksto_iterator_test.go +++ b/graph/linksto_iterator_test.go @@ -23,10 +23,10 @@ func TestLinksTo(t *testing.T) { tsFixed := newFixedIterator() tsFixed.AddValue(2) ts.On("GetIdFor", "cool").Return(1) - ts.On("GetTripleIterator", "o", 1).Return(tsFixed) + ts.On("GetTripleIterator", Object, 1).Return(tsFixed) fixed := newFixedIterator() fixed.AddValue(ts.GetIdFor("cool")) - lto := NewLinksToIterator(ts, fixed, "o") + lto := NewLinksToIterator(ts, fixed, Object) val, ok := lto.Next() if !ok { t.Error("At least one triple matches the fixed object") diff --git a/graph/memstore/triplestore.go b/graph/memstore/triplestore.go index fd9f232..76e0ba0 100644 --- a/graph/memstore/triplestore.go +++ b/graph/memstore/triplestore.go @@ -39,29 +39,30 @@ func NewTripleDirectionIndex() *TripleDirectionIndex { return &tdi } -func (tdi *TripleDirectionIndex) GetForDir(s string) map[int64]*llrb.LLRB { - if s == "s" { +func (tdi *TripleDirectionIndex) GetForDir(d graph.Direction) map[int64]*llrb.LLRB { + switch d { + case graph.Subject: return tdi.subject - } else if s == "o" { + case graph.Object: return tdi.object - } else if s == "p" { + case graph.Predicate: return tdi.predicate - } else if s == "c" { + case graph.Provenance: return tdi.provenance } - panic("Bad direction") + panic("illegal direction") } -func (tdi *TripleDirectionIndex) GetOrCreate(dir string, id int64) *llrb.LLRB { - directionIndex := tdi.GetForDir(dir) +func (tdi *TripleDirectionIndex) GetOrCreate(d graph.Direction, id int64) *llrb.LLRB { + directionIndex := tdi.GetForDir(d) if _, ok := directionIndex[id]; !ok { directionIndex[id] = llrb.New() } return directionIndex[id] } -func (tdi *TripleDirectionIndex) Get(dir string, id int64) (*llrb.LLRB, bool) { - directionIndex := tdi.GetForDir(dir) +func (tdi *TripleDirectionIndex) Get(d graph.Direction, id int64) (*llrb.LLRB, bool) { + directionIndex := tdi.GetForDir(d) tree, exists := directionIndex[id] return tree, exists } @@ -101,9 +102,9 @@ func (ts *TripleStore) AddTripleSet(triples []*graph.Triple) { func (ts *TripleStore) tripleExists(t *graph.Triple) (bool, int64) { smallest := -1 var smallest_tree *llrb.LLRB - for _, dir := range graph.TripleDirections { - sid := t.Get(dir) - if dir == "c" && sid == "" { + for d := graph.Subject; d <= graph.Provenance; d++ { + sid := t.Get(d) + if d == graph.Provenance && sid == "" { continue } id, ok := ts.idMap[sid] @@ -111,7 +112,7 @@ func (ts *TripleStore) tripleExists(t *graph.Triple) (bool, int64) { if !ok { return false, 0 } - index, exists := ts.index.Get(dir, id) + index, exists := ts.index.Get(d, id) if !exists { // If it's never been indexed in this direction, it can't exist. return false, 0 @@ -145,9 +146,9 @@ func (ts *TripleStore) AddTriple(t *graph.Triple) { ts.size++ ts.tripleIdCounter++ - for _, dir := range graph.TripleDirections { - sid := t.Get(dir) - if dir == "c" && sid == "" { + for d := graph.Subject; d <= graph.Provenance; d++ { + sid := t.Get(d) + if d == graph.Provenance && sid == "" { continue } if _, ok := ts.idMap[sid]; !ok { @@ -157,12 +158,12 @@ func (ts *TripleStore) AddTriple(t *graph.Triple) { } } - for _, dir := range graph.TripleDirections { - if dir == "c" && t.Get(dir) == "" { + for d := graph.Subject; d <= graph.Provenance; d++ { + if d == graph.Provenance && t.Get(d) == "" { continue } - id := ts.idMap[t.Get(dir)] - tree := ts.index.GetOrCreate(dir, id) + id := ts.idMap[t.Get(d)] + tree := ts.index.GetOrCreate(d, id) tree.ReplaceOrInsert(Int64(tripleID)) } @@ -180,36 +181,36 @@ func (ts *TripleStore) RemoveTriple(t *graph.Triple) { ts.triples[tripleID] = graph.Triple{} ts.size-- - for _, dir := range graph.TripleDirections { - if dir == "c" && t.Get(dir) == "" { + for d := graph.Subject; d <= graph.Provenance; d++ { + if d == graph.Provenance && t.Get(d) == "" { continue } - id := ts.idMap[t.Get(dir)] - tree := ts.index.GetOrCreate(dir, id) + id := ts.idMap[t.Get(d)] + tree := ts.index.GetOrCreate(d, id) tree.Delete(Int64(tripleID)) } - for _, dir := range graph.TripleDirections { - if dir == "c" && t.Get(dir) == "" { + for d := graph.Subject; d <= graph.Provenance; d++ { + if d == graph.Provenance && t.Get(d) == "" { continue } - id, ok := ts.idMap[t.Get(dir)] + id, ok := ts.idMap[t.Get(d)] if !ok { continue } stillExists := false - for _, dir := range graph.TripleDirections { - if dir == "c" && t.Get(dir) == "" { + for d := graph.Subject; d <= graph.Provenance; d++ { + if d == graph.Provenance && t.Get(d) == "" { continue } - nodeTree := ts.index.GetOrCreate(dir, id) + nodeTree := ts.index.GetOrCreate(d, id) if nodeTree.Len() != 0 { stillExists = true break } } if !stillExists { - delete(ts.idMap, t.Get(dir)) + delete(ts.idMap, t.Get(d)) delete(ts.revIdMap, id) } } @@ -219,9 +220,9 @@ func (ts *TripleStore) GetTriple(index graph.TSVal) *graph.Triple { return &ts.triples[index.(int64)] } -func (ts *TripleStore) GetTripleIterator(direction string, value graph.TSVal) graph.Iterator { - index, ok := ts.index.Get(direction, value.(int64)) - data := fmt.Sprintf("dir:%s val:%d", direction, value.(int64)) +func (ts *TripleStore) GetTripleIterator(d graph.Direction, value graph.TSVal) graph.Iterator { + index, ok := ts.index.Get(d, value.(int64)) + data := fmt.Sprintf("dir:%s val:%d", d, value.(int64)) if ok { return NewLlrbIterator(index, data) } @@ -257,8 +258,8 @@ func (ts *TripleStore) MakeFixed() *graph.FixedIterator { return graph.NewFixedIteratorWithCompare(graph.BasicEquality) } -func (ts *TripleStore) GetTripleDirection(val graph.TSVal, direction string) graph.TSVal { - name := ts.GetTriple(val).Get(direction) +func (ts *TripleStore) GetTripleDirection(val graph.TSVal, d graph.Direction) graph.TSVal { + name := ts.GetTriple(val).Get(d) return ts.GetIdFor(name) } diff --git a/graph/memstore/triplestore_test.go b/graph/memstore/triplestore_test.go index afd24da..4d98c0c 100644 --- a/graph/memstore/triplestore_test.go +++ b/graph/memstore/triplestore_test.go @@ -41,15 +41,15 @@ func TestIteratorsAndNextResultOrderA(t *testing.T) { fixed := ts.MakeFixed() fixed.AddValue(ts.GetIdFor("C")) all := ts.GetNodesAllIterator() - lto := graph.NewLinksToIterator(ts, all, "o") + lto := graph.NewLinksToIterator(ts, all, graph.Object) innerAnd := graph.NewAndIterator() fixed2 := ts.MakeFixed() fixed2.AddValue(ts.GetIdFor("follows")) - lto2 := graph.NewLinksToIterator(ts, fixed2, "p") + lto2 := graph.NewLinksToIterator(ts, fixed2, graph.Predicate) innerAnd.AddSubIterator(lto2) innerAnd.AddSubIterator(lto) - hasa := graph.NewHasaIterator(ts, innerAnd, "s") + hasa := graph.NewHasaIterator(ts, innerAnd, graph.Subject) outerAnd := graph.NewAndIterator() outerAnd.AddSubIterator(fixed) outerAnd.AddSubIterator(hasa) @@ -98,7 +98,7 @@ func TestLinksToOptimization(t *testing.T) { ts := MakeTestingMemstore() fixed := ts.MakeFixed() fixed.AddValue(ts.GetIdFor("cool")) - lto := graph.NewLinksToIterator(ts, fixed, "o") + lto := graph.NewLinksToIterator(ts, fixed, graph.Object) lto.AddTag("foo") newIt, changed := lto.Optimize() if !changed { @@ -122,14 +122,14 @@ func TestRemoveTriple(t *testing.T) { ts.RemoveTriple(graph.MakeTriple("E", "follows", "F", "")) fixed := ts.MakeFixed() fixed.AddValue(ts.GetIdFor("E")) - lto := graph.NewLinksToIterator(ts, fixed, "s") + lto := graph.NewLinksToIterator(ts, fixed, graph.Subject) fixed2 := ts.MakeFixed() fixed2.AddValue(ts.GetIdFor("follows")) - lto2 := graph.NewLinksToIterator(ts, fixed2, "p") + lto2 := graph.NewLinksToIterator(ts, fixed2, graph.Predicate) innerAnd := graph.NewAndIterator() innerAnd.AddSubIterator(lto2) innerAnd.AddSubIterator(lto) - hasa := graph.NewHasaIterator(ts, innerAnd, "o") + hasa := graph.NewHasaIterator(ts, innerAnd, graph.Object) newIt, _ := hasa.Optimize() _, ok := newIt.Next() if ok { diff --git a/graph/mock_ts.go b/graph/mock_ts.go index fcd9244..1145f9d 100644 --- a/graph/mock_ts.go +++ b/graph/mock_ts.go @@ -32,8 +32,8 @@ func (ts *TestTripleStore) GetIdFor(s string) TSVal { func (ts *TestTripleStore) AddTriple(*Triple) {} func (ts *TestTripleStore) AddTripleSet([]*Triple) {} func (ts *TestTripleStore) GetTriple(TSVal) *Triple { return &Triple{} } -func (ts *TestTripleStore) GetTripleIterator(s string, i TSVal) Iterator { - args := ts.Mock.Called(s, i) +func (ts *TestTripleStore) GetTripleIterator(d Direction, i TSVal) Iterator { + args := ts.Mock.Called(d, i) return args.Get(0).(Iterator) } func (ts *TestTripleStore) GetNodesAllIterator() Iterator { return &NullIterator{} } @@ -53,6 +53,6 @@ func (ts *TestTripleStore) OptimizeIterator(it Iterator) (Iterator, bool) { func (ts *TestTripleStore) MakeFixed() *FixedIterator { return NewFixedIteratorWithCompare(BasicEquality) } -func (ts *TestTripleStore) Close() {} -func (ts *TestTripleStore) GetTripleDirection(TSVal, string) TSVal { return 0 } -func (ts *TestTripleStore) RemoveTriple(t *Triple) {} +func (ts *TestTripleStore) Close() {} +func (ts *TestTripleStore) GetTripleDirection(TSVal, Direction) TSVal { return 0 } +func (ts *TestTripleStore) RemoveTriple(t *Triple) {} diff --git a/graph/mongo/iterator.go b/graph/mongo/iterator.go index 16dc992..f6c1075 100644 --- a/graph/mongo/iterator.go +++ b/graph/mongo/iterator.go @@ -28,7 +28,7 @@ import ( type Iterator struct { graph.BaseIterator ts *TripleStore - dir string + dir graph.Direction iter *mgo.Iter hash string name string @@ -38,26 +38,25 @@ type Iterator struct { 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 graph.BaseIteratorInit(&m.BaseIterator) m.name = ts.GetNameFor(val) m.collection = collection - switch dir { - - case "s": - m.constraint = bson.M{"Sub": m.name} - case "p": - m.constraint = bson.M{"Pred": m.name} - case "o": - m.constraint = bson.M{"Obj": m.name} - case "c": + switch d { + case graph.Subject: + m.constraint = bson.M{"Subject": m.name} + case graph.Predicate: + m.constraint = bson.M{"Predicate": m.name} + case graph.Object: + m.constraint = bson.M{"Object": m.name} + case graph.Provenance: m.constraint = bson.M{"Provenance": m.name} } m.ts = ts - m.dir = dir + m.dir = d m.iter = ts.db.C(collection).Find(m.constraint).Iter() size, err := ts.db.C(collection).Find(m.constraint).Count() 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 { var m Iterator m.ts = ts - m.dir = "all" + m.dir = graph.Any m.constraint = nil m.collection = collection m.iter = ts.db.C(collection).Find(nil).Iter() @@ -136,13 +135,13 @@ func (it *Iterator) Check(v graph.TSVal) bool { } var offset int switch it.dir { - case "s": + case graph.Subject: offset = 0 - case "p": + case graph.Predicate: offset = (it.ts.hasher.Size() * 2) - case "o": + case graph.Object: offset = (it.ts.hasher.Size() * 2) * 2 - case "c": + case graph.Provenance: offset = (it.ts.hasher.Size() * 2) * 3 } val := v.(string)[offset : it.ts.hasher.Size()*2+offset] diff --git a/graph/mongo/triplestore.go b/graph/mongo/triplestore.go index c57b407..8fdd08f 100644 --- a/graph/mongo/triplestore.go +++ b/graph/mongo/triplestore.go @@ -84,9 +84,9 @@ func NewTripleStore(addr string, options graph.OptionsDict) *TripleStore { } func (ts *TripleStore) getIdForTriple(t *graph.Triple) string { - id := ts.ConvertStringToByteHash(t.Sub) - id += ts.ConvertStringToByteHash(t.Pred) - id += ts.ConvertStringToByteHash(t.Obj) + id := ts.ConvertStringToByteHash(t.Subject) + id += ts.ConvertStringToByteHash(t.Predicate) + id += ts.ConvertStringToByteHash(t.Object) id += ts.ConvertStringToByteHash(t.Provenance) return id } @@ -143,7 +143,13 @@ func (ts *TripleStore) updateNodeBy(node_name string, inc int) { } 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) if err != nil { // 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) { _ = ts.writeTriple(t) - ts.updateNodeBy(t.Sub, 1) - ts.updateNodeBy(t.Pred, 1) - ts.updateNodeBy(t.Obj, 1) + ts.updateNodeBy(t.Subject, 1) + ts.updateNodeBy(t.Predicate, 1) + ts.updateNodeBy(t.Object, 1) if t.Provenance != "" { ts.updateNodeBy(t.Provenance, 1) } @@ -168,19 +174,19 @@ func (ts *TripleStore) AddTriple(t *graph.Triple) { func (ts *TripleStore) AddTripleSet(in []*graph.Triple) { ts.session.SetSafe(nil) - idMap := make(map[string]int) + ids := make(map[string]int) for _, t := range in { wrote := ts.writeTriple(t) if wrote { - idMap[t.Sub]++ - idMap[t.Obj]++ - idMap[t.Pred]++ + ids[t.Subject]++ + ids[t.Object]++ + ids[t.Predicate]++ if t.Provenance != "" { - idMap[t.Provenance]++ + ids[t.Provenance]++ } } } - for k, v := range idMap { + for k, v := range ids { ts.updateNodeBy(k, v) } ts.session.SetSafe(&mgo.Safe{}) @@ -194,9 +200,9 @@ func (ts *TripleStore) RemoveTriple(t *graph.Triple) { log.Println("Error: ", err, " while removing triple ", t) return } - ts.updateNodeBy(t.Sub, -1) - ts.updateNodeBy(t.Pred, -1) - ts.updateNodeBy(t.Obj, -1) + ts.updateNodeBy(t.Subject, -1) + ts.updateNodeBy(t.Predicate, -1) + ts.updateNodeBy(t.Object, -1) if t.Provenance != "" { ts.updateNodeBy(t.Provenance, -1) } @@ -215,8 +221,8 @@ func (ts *TripleStore) GetTriple(val graph.TSVal) *graph.Triple { bsonDoc["Provenance"].(string)) } -func (ts *TripleStore) GetTripleIterator(dir string, val graph.TSVal) graph.Iterator { - return NewIterator(ts, "triples", dir, val) +func (ts *TripleStore) GetTripleIterator(d graph.Direction, val graph.TSVal) graph.Iterator { + return NewIterator(ts, "triples", d, val) } func (ts *TripleStore) GetNodesAllIterator() graph.Iterator { @@ -266,17 +272,17 @@ func (ts *TripleStore) 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 var offset int - switch dir { - case "s": + switch d { + case graph.Subject: offset = 0 - case "p": + case graph.Predicate: offset = (ts.hasher.Size() * 2) - case "o": + case graph.Object: offset = (ts.hasher.Size() * 2) * 2 - case "c": + case graph.Provenance: offset = (ts.hasher.Size() * 2) * 3 } val := in.(string)[offset : ts.hasher.Size()*2+offset] diff --git a/graph/query_shape.go b/graph/query_shape.go index 1c20ca1..d59a5c0 100644 --- a/graph/query_shape.go +++ b/graph/query_shape.go @@ -35,17 +35,14 @@ type queryShape struct { ts TripleStore nodeId int hasaIds []int - hasaDirs []string + hasaDirs []Direction } func OutputQueryShapeForIterator(it Iterator, ts TripleStore, outputMap *map[string]interface{}) { - qs := &queryShape{} - qs.nodes = make([]Node, 0) - qs.links = make([]Link, 0) - qs.hasaIds = make([]int, 0) - qs.hasaDirs = make([]string, 0) - qs.ts = ts - qs.nodeId = 1 + qs := &queryShape{ + ts: ts, + nodeId: 1, + } node := qs.MakeNode(it.Clone()) qs.AddNode(node) @@ -61,13 +58,13 @@ func (qs *queryShape) AddLink(l *Link) { 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] } -func (qs *queryShape) PushHasa(i int, s string) { +func (qs *queryShape) PushHasa(i int, d Direction) { qs.hasaIds = append(qs.hasaIds, i) - qs.hasaDirs = append(qs.hasaDirs, s) + qs.hasaDirs = append(qs.hasaDirs, d) } func (qs *queryShape) RemoveHasa() { @@ -136,7 +133,7 @@ func (qs *queryShape) MakeNode(it Iterator) *Node { } case "hasa": hasa := it.(*HasaIterator) - qs.PushHasa(n.Id, hasa.direction) + qs.PushHasa(n.Id, hasa.dir) qs.nodeId++ newNode := qs.MakeNode(hasa.primaryIt) qs.AddNode(newNode) @@ -158,10 +155,10 @@ func (qs *queryShape) MakeNode(it Iterator) *Node { qs.nodeId++ newNode := qs.MakeNode(lto.primaryIt) hasaID, hasaDir := qs.LastHasa() - if (hasaDir == "s" && lto.direction == "o") || - (hasaDir == "o" && lto.direction == "s") { + if (hasaDir == Subject && lto.dir == Object) || + (hasaDir == Object && lto.dir == Subject) { qs.AddNode(newNode) - if hasaDir == "s" { + if hasaDir == Subject { qs.AddLink(&Link{hasaID, newNode.Id, 0, n.Id}) } else { qs.AddLink(&Link{newNode.Id, hasaID, 0, n.Id}) diff --git a/graph/query_shape_test.go b/graph/query_shape_test.go index b0d6950..dc33fc3 100644 --- a/graph/query_shape_test.go +++ b/graph/query_shape_test.go @@ -15,8 +15,9 @@ package graph import ( - . "github.com/smartystreets/goconvey/convey" "testing" + + . "github.com/smartystreets/goconvey/convey" ) 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_pred.AddValue(ts.GetIdFor("status")) fixed_obj.AddTag(tag) - lto1 := NewLinksToIterator(ts, fixed_obj, "o") - lto2 := NewLinksToIterator(ts, fixed_pred, "p") + lto1 := NewLinksToIterator(ts, fixed_obj, Object) + lto2 := NewLinksToIterator(ts, fixed_pred, Predicate) and := NewAndIterator() and.AddSubIterator(lto1) and.AddSubIterator(lto2) - hasa := NewHasaIterator(ts, and, "s") + hasa := NewHasaIterator(ts, and, Subject) return hasa } @@ -91,12 +92,12 @@ func TestQueryShape(t *testing.T) { andInternal.AddSubIterator(hasa2) fixed_pred := ts.MakeFixed() fixed_pred.AddValue(ts.GetIdFor("name")) - lto1 := NewLinksToIterator(ts, andInternal, "s") - lto2 := NewLinksToIterator(ts, fixed_pred, "p") + lto1 := NewLinksToIterator(ts, andInternal, Subject) + lto2 := NewLinksToIterator(ts, fixed_pred, Predicate) and := NewAndIterator() and.AddSubIterator(lto1) and.AddSubIterator(lto2) - hasa := NewHasaIterator(ts, and, "o") + hasa := NewHasaIterator(ts, and, Object) OutputQueryShapeForIterator(hasa, ts, &queryShape) Convey("It should have seven nodes and three links", func() { diff --git a/graph/sexp/parser.go b/graph/sexp/parser.go index 2efcf49..aeab8d6 100644 --- a/graph/sexp/parser.go +++ b/graph/sexp/parser.go @@ -207,7 +207,7 @@ func buildIteratorTree(tree *peg.ExpressionTree, ts graph.TripleStore) graph.Ite i++ } it := buildIteratorTree(tree.Children[i], ts) - lto := graph.NewLinksToIterator(ts, it, "p") + lto := graph.NewLinksToIterator(ts, it, graph.Predicate) return lto case "RootConstraint": constraintCount := 0 @@ -228,16 +228,16 @@ func buildIteratorTree(tree *peg.ExpressionTree, ts graph.TripleStore) graph.Ite return and case "Constraint": var hasa *graph.HasaIterator - topLevelDir := "s" - subItDir := "o" + topLevelDir := graph.Subject + subItDir := graph.Object subAnd := graph.NewAndIterator() isOptional := false for _, c := range tree.Children { switch c.Name { case "PredIdentifier": if c.Children[0].Name == "Reverse" { - topLevelDir = "o" - subItDir = "s" + topLevelDir = graph.Object + subItDir = graph.Subject } it := buildIteratorTree(c, ts) subAnd.AddSubIterator(it) diff --git a/graph/triple.go b/graph/triple.go index 5abdb59..7744edc 100644 --- a/graph/triple.go +++ b/graph/triple.go @@ -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"); // 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 // the consequences are not to be taken lightly. But do suggest cool features! -import ( - "fmt" - "reflect" -) +import "fmt" // Our triple struct, used throughout. type Triple struct { - Sub string `json:"subject"` - Pred string `json:"predicate"` - Obj string `json:"object"` + Subject string `json:"subject"` + Predicate string `json:"predicate"` + Object string `json:"object"` 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} } -// List of the valid directions of a triple. -// TODO(barakmich): Replace all instances of "dir string" in the codebase -// with an enum of valid directions, to make this less stringly typed. -var TripleDirections = [4]string{"s", "p", "o", "c"} +// Direction specifies an edge's type. +type Direction byte -// Per-field accessor for triples -func (t *Triple) Get(dir string) string { - if dir == "s" { - return t.Sub - } else if dir == "p" { - return t.Pred - } else if dir == "prov" || dir == "c" { - return t.Provenance - } else if dir == "o" { - return t.Obj - } else { - panic(fmt.Sprintf("No Such Triple Direction, %s", dir)) +// List of the valid directions of a triple. +const ( + Any Direction = iota + Subject + Predicate + Object + Provenance +) + +func (d Direction) String() string { + switch d { + 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 { - return reflect.DeepEqual(t, other) +// Per-field accessor for triples +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. 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 { - if t.Sub == "" { + if t.Subject == "" { return false } - if t.Pred == "" { + if t.Predicate == "" { return false } - if t.Obj == "" { + if t.Object == "" { return false } return true @@ -102,8 +124,8 @@ func (t *Triple) IsValid() bool { func (t *Triple) ToNTriple() string { if t.Provenance == "" { //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 { - 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) } } diff --git a/graph/triplestore.go b/graph/triplestore.go index 1e6d9ce..759d507 100644 --- a/graph/triplestore.go +++ b/graph/triplestore.go @@ -51,7 +51,7 @@ type TripleStore interface { // Given a direction and a token, creates an iterator of links which have // that node token in that directional field. - GetTripleIterator(string, TSVal) Iterator + GetTripleIterator(Direction, TSVal) Iterator // Returns an iterator enumerating all nodes in the graph. GetNodesAllIterator() Iterator @@ -89,7 +89,7 @@ type TripleStore interface { // // Iterators will call this. At worst, a valid implementation is // 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{} diff --git a/http/http_test.go b/http/http_test.go index d59749f..eea76f2 100644 --- a/http/http_test.go +++ b/http/http_test.go @@ -16,6 +16,7 @@ package http import ( "testing" + . "github.com/smartystreets/goconvey/convey" ) @@ -28,7 +29,7 @@ func TestParseJSONOkay(t *testing.T) { x, err := ParseJsonToTripleList(bytelist) So(err, ShouldBeNil) So(len(x), ShouldEqual, 2) - So(x[0].Sub, ShouldEqual, "foo") + So(x[0].Subject, ShouldEqual, "foo") So(x[0].Provenance, ShouldEqual, "") So(x[1].Provenance, ShouldEqual, "graph") }) diff --git a/nquads/nquads_test.go b/nquads/nquads_test.go index e4c0dcb..a8a83bc 100644 --- a/nquads/nquads_test.go +++ b/nquads/nquads_test.go @@ -35,55 +35,55 @@ func TestParsingNTriples(t *testing.T) { Convey("It should parse simple triples", func() { x := Parse("this is valid .") So(x, ShouldNotBeNil) - So(x.Sub, ShouldEqual, "this") + So(x.Subject, ShouldEqual, "this") }) Convey("It should parse quoted triples", func() { x := Parse("this is \"valid too\" .") So(x, ShouldNotBeNil) - So(x.Obj, ShouldEqual, "valid too") + So(x.Object, ShouldEqual, "valid too") So(x.Provenance, ShouldEqual, "") }) Convey("It should parse escaped quoted triples", func() { x := Parse("he said \"\\\"That's all folks\\\"\" .") So(x, ShouldNotBeNil) - So(x.Obj, ShouldEqual, "\"That's all folks\"") + So(x.Object, ShouldEqual, "\"That's all folks\"") So(x.Provenance, ShouldEqual, "") }) Convey("It should parse an example real triple", func() { x := Parse("\":/guid/9202a8c04000641f80000000010c843c\" \"name\" \"George Morris\" .") So(x, ShouldNotBeNil) - So(x.Obj, ShouldEqual, "George Morris") + So(x.Object, ShouldEqual, "George Morris") So(x.Provenance, ShouldEqual, "") }) Convey("It should parse a pathologically spaced triple", func() { x := Parse("foo is \"\\tA big tough\\r\\nDeal\\\\\" .") 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, "") }) Convey("It should parse a simple quad", func() { x := Parse("this is valid quad .") So(x, ShouldNotBeNil) - So(x.Obj, ShouldEqual, "valid") + So(x.Object, ShouldEqual, "valid") So(x.Provenance, ShouldEqual, "quad") }) Convey("It should parse a quoted quad", func() { x := Parse("this is valid \"quad thing\" .") So(x, ShouldNotBeNil) - So(x.Obj, ShouldEqual, "valid") + So(x.Object, ShouldEqual, "valid") So(x.Provenance, ShouldEqual, "quad thing") }) Convey("It should parse crazy escaped quads", func() { x := Parse("\"\\\"this\" \"\\\"is\" \"\\\"valid\" \"\\\"quad thing\".") So(x, ShouldNotBeNil) - So(x.Sub, ShouldEqual, "\"this") - So(x.Pred, ShouldEqual, "\"is") - So(x.Obj, ShouldEqual, "\"valid") + So(x.Subject, ShouldEqual, "\"this") + So(x.Predicate, ShouldEqual, "\"is") + So(x.Object, ShouldEqual, "\"valid") So(x.Provenance, ShouldEqual, "\"quad thing") }) }) @@ -95,27 +95,27 @@ func TestParsingNTriplesOfficial(t *testing.T) { var x *graph.Triple x = Parse(" . # comment") So(x, ShouldNotBeNil) - So(x.Sub, ShouldEqual, "http://example/s") - So(x.Pred, ShouldEqual, "http://example/p") - So(x.Obj, ShouldEqual, "http://example/o") + So(x.Subject, ShouldEqual, "http://example/s") + So(x.Predicate, ShouldEqual, "http://example/p") + So(x.Object, ShouldEqual, "http://example/o") So(x.Provenance, ShouldEqual, "") x = Parse(" _:o . # comment") So(x, ShouldNotBeNil) - So(x.Sub, ShouldEqual, "http://example/s") - So(x.Pred, ShouldEqual, "http://example/p") - So(x.Obj, ShouldEqual, "_:o") + So(x.Subject, ShouldEqual, "http://example/s") + So(x.Predicate, ShouldEqual, "http://example/p") + So(x.Object, ShouldEqual, "_:o") So(x.Provenance, ShouldEqual, "") x = Parse(" \"o\" . # comment") So(x, ShouldNotBeNil) - So(x.Obj, ShouldEqual, "o") + So(x.Object, ShouldEqual, "o") So(x.Provenance, ShouldEqual, "") x = Parse(" \"o\"^^ . # comment") So(x, ShouldNotBeNil) - So(x.Obj, ShouldEqual, "o") + So(x.Object, ShouldEqual, "o") So(x.Provenance, ShouldEqual, "") x = Parse(" \"o\"@en . # comment") So(x, ShouldNotBeNil) - So(x.Obj, ShouldEqual, "o") + So(x.Object, ShouldEqual, "o") So(x.Provenance, ShouldEqual, "") }) }) @@ -124,7 +124,7 @@ func TestParsingNTriplesOfficial(t *testing.T) { func BenchmarkParser(b *testing.B) { for n := 0; n < b.N; n++ { x := Parse(" \"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() } } diff --git a/query/gremlin/build_iterator.go b/query/gremlin/build_iterator.go index b6e9a45..6bdfac2 100644 --- a/query/gremlin/build_iterator.go +++ b/query/gremlin/build_iterator.go @@ -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 { in, out = out, in } lto := graph.NewLinksToIterator(ts, base, in) and := graph.NewAndIterator() - and.AddSubIterator(graph.NewLinksToIterator(ts, predicateNodeIterator, "p")) + and.AddSubIterator(graph.NewLinksToIterator(ts, predicateNodeIterator, graph.Predicate)) and.AddSubIterator(lto) return graph.NewHasaIterator(ts, and, out) } @@ -193,9 +193,9 @@ func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph. predFixed := ts.MakeFixed() predFixed.AddValue(ts.GetIdFor(stringArgs[0])) subAnd := graph.NewAndIterator() - subAnd.AddSubIterator(graph.NewLinksToIterator(ts, predFixed, "p")) - subAnd.AddSubIterator(graph.NewLinksToIterator(ts, all, "o")) - hasa := graph.NewHasaIterator(ts, subAnd, "s") + subAnd.AddSubIterator(graph.NewLinksToIterator(ts, predFixed, graph.Predicate)) + subAnd.AddSubIterator(graph.NewLinksToIterator(ts, all, graph.Object)) + hasa := graph.NewHasaIterator(ts, subAnd, graph.Subject) and := graph.NewAndIterator() and.AddSubIterator(hasa) and.AddSubIterator(subIt) @@ -213,9 +213,9 @@ func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph. predFixed := ts.MakeFixed() predFixed.AddValue(ts.GetIdFor(stringArgs[0])) subAnd := graph.NewAndIterator() - subAnd.AddSubIterator(graph.NewLinksToIterator(ts, predFixed, "p")) - subAnd.AddSubIterator(graph.NewLinksToIterator(ts, all, "s")) - hasa := graph.NewHasaIterator(ts, subAnd, "o") + subAnd.AddSubIterator(graph.NewLinksToIterator(ts, predFixed, graph.Predicate)) + subAnd.AddSubIterator(graph.NewLinksToIterator(ts, all, graph.Subject)) + hasa := graph.NewHasaIterator(ts, subAnd, graph.Object) and := graph.NewAndIterator() and.AddSubIterator(hasa) and.AddSubIterator(subIt) @@ -231,9 +231,9 @@ func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph. predFixed := ts.MakeFixed() predFixed.AddValue(ts.GetIdFor(stringArgs[0])) subAnd := graph.NewAndIterator() - subAnd.AddSubIterator(graph.NewLinksToIterator(ts, predFixed, "p")) - subAnd.AddSubIterator(graph.NewLinksToIterator(ts, fixed, "o")) - hasa := graph.NewHasaIterator(ts, subAnd, "s") + subAnd.AddSubIterator(graph.NewLinksToIterator(ts, predFixed, graph.Predicate)) + subAnd.AddSubIterator(graph.NewLinksToIterator(ts, fixed, graph.Object)) + hasa := graph.NewHasaIterator(ts, subAnd, graph.Subject) and := graph.NewAndIterator() and.AddSubIterator(hasa) and.AddSubIterator(subIt) diff --git a/query/mql/build_iterator.go b/query/mql/build_iterator.go index 5594552..f0a0b1b 100644 --- a/query/mql/build_iterator.go +++ b/query/mql/build_iterator.go @@ -138,16 +138,16 @@ func (q *Query) buildIteratorTreeMapInternal(query map[string]interface{}, path subAnd := graph.NewAndIterator() predFixed := q.ses.ts.MakeFixed() 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 { - lto := graph.NewLinksToIterator(q.ses.ts, builtIt, "s") + lto := graph.NewLinksToIterator(q.ses.ts, builtIt, graph.Subject) subAnd.AddSubIterator(lto) - hasa := graph.NewHasaIterator(q.ses.ts, subAnd, "o") + hasa := graph.NewHasaIterator(q.ses.ts, subAnd, graph.Object) subit = hasa } else { - lto := graph.NewLinksToIterator(q.ses.ts, builtIt, "o") + lto := graph.NewLinksToIterator(q.ses.ts, builtIt, graph.Object) subAnd.AddSubIterator(lto) - hasa := graph.NewHasaIterator(q.ses.ts, subAnd, "s") + hasa := graph.NewHasaIterator(q.ses.ts, subAnd, graph.Subject) subit = hasa } } From 12c876974456d9c91a2330fc3752ac32c2095117 Mon Sep 17 00:00:00 2001 From: kortschak Date: Mon, 30 Jun 2014 12:58:37 +0930 Subject: [PATCH 2/2] Retain correct copyright notice --- graph/triple.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/triple.go b/graph/triple.go index 7744edc..c0029c6 100644 --- a/graph/triple.go +++ b/graph/triple.go @@ -1,4 +1,4 @@ -// Copyright 2014 The Cayley Authors. Any rights reserved. +// Copyright 2014 The Cayley Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License.