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
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)

View file

@ -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)

View file

@ -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 {

View file

@ -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()

View file

@ -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)
}
}

View file

@ -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(&lto.BaseIterator)
lto.ts = ts
lto.primaryIt = it
lto.direction = dir
lto.dir = d
lto.nextIt = &NullIterator{}
return &lto
}
@ -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()
}

View file

@ -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")

View file

@ -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)
}

View file

@ -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 {

View file

@ -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) {}

View file

@ -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]

View file

@ -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]

View file

@ -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})

View file

@ -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() {

View file

@ -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)

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");
// 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)
}
}

View file

@ -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{}

View file

@ -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")
})

View file

@ -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("<http://example/s> <http://example/p> <http://example/o> . # 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("<http://example/s> <http://example/p> _: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("<http://example/s> <http://example/p> \"o\" . # comment")
So(x, ShouldNotBeNil)
So(x.Obj, ShouldEqual, "o")
So(x.Object, ShouldEqual, "o")
So(x.Provenance, ShouldEqual, "")
x = Parse("<http://example/s> <http://example/p> \"o\"^^<http://example/dt> . # comment")
So(x, ShouldNotBeNil)
So(x.Obj, ShouldEqual, "o")
So(x.Object, ShouldEqual, "o")
So(x.Provenance, ShouldEqual, "")
x = Parse("<http://example/s> <http://example/p> \"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("<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()
}
}

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 {
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)

View file

@ -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
}
}