func TestRemoveQuad(t *testing.T) {
	qs, w, _ := makeTestStore(simpleGraph)

	w.RemoveQuad(quad.Quad{
		Subject:   "E",
		Predicate: "follows",
		Object:    "F",
		Label:     "",
	})

	fixed := qs.FixedIterator()
	fixed.Add(qs.ValueOf("E"))

	fixed2 := qs.FixedIterator()
	fixed2.Add(qs.ValueOf("follows"))

	innerAnd := iterator.NewAnd()
	innerAnd.AddSubIterator(iterator.NewLinksTo(qs, fixed, quad.Subject))
	innerAnd.AddSubIterator(iterator.NewLinksTo(qs, fixed2, quad.Predicate))

	hasa := iterator.NewHasA(qs, innerAnd, quad.Object)

	newIt, _ := hasa.Optimize()
	if graph.Next(newIt) {
		t.Error("E should not have any followers.")
	}
}
func hasMorphism(via interface{}, nodes ...string) morphism {
	return morphism{
		Name:     "has",
		Reversal: func() morphism { return hasMorphism(via, nodes...) },
		Apply: func(qs graph.QuadStore, it graph.Iterator) graph.Iterator {
			var sub graph.Iterator
			if len(nodes) == 0 {
				sub = qs.NodesAllIterator()
			} else {
				fixed := qs.FixedIterator()
				for _, n := range nodes {
					fixed.Add(qs.ValueOf(n))
				}
				sub = fixed
			}
			var viaPath *Path
			if via != nil {
				viaPath = buildViaPath(qs, via)
			} else {
				viaPath = buildViaPath(qs)
			}
			subAnd := iterator.NewAnd(qs)
			subAnd.AddSubIterator(iterator.NewLinksTo(qs, sub, quad.Object))
			subAnd.AddSubIterator(iterator.NewLinksTo(qs, viaPath.BuildIterator(), quad.Predicate))
			hasa := iterator.NewHasA(qs, subAnd, quad.Subject)
			and := iterator.NewAnd(qs)
			and.AddSubIterator(it)
			and.AddSubIterator(hasa)
			return and
		},
	}
}
Exemple #3
0
func TestRemoveQuad(t *testing.T) {
	qs, w, _ := makeTestStore(simpleGraph)

	err := w.RemoveQuad(quad.Make(
		"E",
		"follows",
		"F",
		"",
	))

	if err != nil {
		t.Error("Couldn't remove quad", err)
	}

	fixed := qs.FixedIterator()
	fixed.Add(qs.ValueOf(quad.Raw("E")))

	fixed2 := qs.FixedIterator()
	fixed2.Add(qs.ValueOf(quad.Raw("follows")))

	innerAnd := iterator.NewAnd(qs)
	innerAnd.AddSubIterator(iterator.NewLinksTo(qs, fixed, quad.Subject))
	innerAnd.AddSubIterator(iterator.NewLinksTo(qs, fixed2, quad.Predicate))

	hasa := iterator.NewHasA(qs, innerAnd, quad.Object)

	newIt, _ := hasa.Optimize()
	if graph.Next(newIt) {
		t.Error("E should not have any followers.")
	}
}
func buildSave(
	qs graph.QuadStore, via interface{},
	tag string, from graph.Iterator, reverse bool, optional bool,
) graph.Iterator {

	allNodes := qs.NodesAllIterator()
	allNodes.Tagger().Add(tag)

	start, goal := quad.Subject, quad.Object
	if reverse {
		start, goal = goal, start
	}
	viaIter := buildViaPath(qs, via).
		BuildIterator()

	dest := iterator.NewLinksTo(qs, allNodes, goal)
	trail := iterator.NewLinksTo(qs, viaIter, quad.Predicate)

	route := join(qs, trail, dest)
	save := graph.Iterator(iterator.NewHasA(qs, route, start))

	if optional {
		save = iterator.NewOptional(save)
	}
	return join(qs, from, save)
}
Exemple #5
0
func TestIteratorsAndNextResultOrderA(t *testing.T) {
	glog.Info("\n-----------\n")
	inst, opts, err := createInstance()
	defer inst.Close()

	if err != nil {
		t.Fatalf("failed to create instance: %v", err)
	}
	qs, _, _ := makeTestStore(simpleGraph, opts)
	if qs.Size() != 11 {
		t.Fatal("Incorrect number of quads")
	}

	fixed := qs.FixedIterator()
	fixed.Add(qs.ValueOf("C"))

	fixed2 := qs.FixedIterator()
	fixed2.Add(qs.ValueOf("follows"))

	all := qs.NodesAllIterator()

	innerAnd := iterator.NewAnd(qs)
	innerAnd.AddSubIterator(iterator.NewLinksTo(qs, fixed2, quad.Predicate))
	innerAnd.AddSubIterator(iterator.NewLinksTo(qs, all, quad.Object))

	hasa := iterator.NewHasA(qs, innerAnd, quad.Subject)
	outerAnd := iterator.NewAnd(qs)
	outerAnd.AddSubIterator(fixed)
	outerAnd.AddSubIterator(hasa)

	if !outerAnd.Next() {
		t.Error("Expected one matching subtree")
	}
	val := outerAnd.Result()
	if qs.NameOf(val) != "C" {
		t.Errorf("Matching subtree should be %s, got %s", "barak", qs.NameOf(val))
	}

	var (
		got    []string
		expect = []string{"B", "D"}
	)
	for {
		got = append(got, qs.NameOf(all.Result()))
		if !outerAnd.NextPath() {
			break
		}
	}
	sort.Strings(got)

	if !reflect.DeepEqual(got, expect) {
		t.Errorf("Unexpected result, got:%q expect:%q", got, expect)
	}

	if outerAnd.Next() {
		t.Error("More than one possible top level output?")
	}
}
func inOutIterator(viaPath *Path, it graph.Iterator, reverse bool) graph.Iterator {
	in, out := quad.Subject, quad.Object
	if reverse {
		in, out = out, in
	}
	lto := iterator.NewLinksTo(viaPath.qs, it, in)
	and := iterator.NewAnd(viaPath.qs)
	and.AddSubIterator(iterator.NewLinksTo(viaPath.qs, viaPath.BuildIterator(), quad.Predicate))
	and.AddSubIterator(lto)
	return iterator.NewHasA(viaPath.qs, and, out)
}
Exemple #7
0
func TestIteratorsAndNextResultOrderA(t *testing.T) {
	ts, _ := makeTestStore(simpleGraph)

	fixed := ts.FixedIterator()
	fixed.Add(ts.ValueOf("C"))

	fixed2 := ts.FixedIterator()
	fixed2.Add(ts.ValueOf("follows"))

	all := ts.NodesAllIterator()

	innerAnd := iterator.NewAnd()
	innerAnd.AddSubIterator(iterator.NewLinksTo(ts, fixed2, graph.Predicate))
	innerAnd.AddSubIterator(iterator.NewLinksTo(ts, all, graph.Object))

	hasa := iterator.NewHasA(ts, innerAnd, graph.Subject)
	outerAnd := iterator.NewAnd()
	outerAnd.AddSubIterator(fixed)
	outerAnd.AddSubIterator(hasa)

	val, ok := outerAnd.Next()
	if !ok {
		t.Error("Expected one matching subtree")
	}
	if ts.NameOf(val) != "C" {
		t.Errorf("Matching subtree should be %s, got %s", "barak", ts.NameOf(val))
	}

	var (
		got    []string
		expect = []string{"B", "D"}
	)
	for {
		got = append(got, ts.NameOf(all.Result()))
		if !outerAnd.NextResult() {
			break
		}
	}
	sort.Strings(got)

	if !reflect.DeepEqual(got, expect) {
		t.Errorf("Unexpected result, got:%q expect:%q", got, expect)
	}

	val, ok = outerAnd.Next()
	if ok {
		t.Error("More than one possible top level output?")
	}
}
func inOutIterator(viaPath *Path, from graph.Iterator, inIterator bool) graph.Iterator {
	start, goal := quad.Subject, quad.Object
	if inIterator {
		start, goal = goal, start
	}

	viaIter := viaPath.BuildIterator()

	source := iterator.NewLinksTo(viaPath.qs, from, start)
	trail := iterator.NewLinksTo(viaPath.qs, viaIter, quad.Predicate)

	route := join(viaPath.qs, source, trail)

	return iterator.NewHasA(viaPath.qs, route, goal)
}
Exemple #9
0
func TestLinksToOptimization(t *testing.T) {
	ts, _ := makeTestStore(simpleGraph)

	fixed := ts.FixedIterator()
	fixed.Add(ts.ValueOf("cool"))

	lto := iterator.NewLinksTo(ts, fixed, graph.Object)
	lto.AddTag("foo")

	newIt, changed := lto.Optimize()
	if !changed {
		t.Error("Iterator didn't change")
	}
	if newIt.Type() != Type() {
		t.Fatal("Didn't swap out to LLRB")
	}

	v := newIt.(*Iterator)
	v_clone := v.Clone()
	if v_clone.DebugString(0) != v.DebugString(0) {
		t.Fatal("Wrong iterator. Got ", v_clone.DebugString(0))
	}
	if len(v_clone.Tags()) < 1 || v_clone.Tags()[0] != "foo" {
		t.Fatal("Tag on LinksTo did not persist")
	}
}
func TestLinksToOptimization(t *testing.T) {
	qs, _, _ := makeTestStore(simpleGraph)

	fixed := qs.FixedIterator()
	fixed.Add(qs.ValueOf("cool"))

	lto := iterator.NewLinksTo(qs, fixed, quad.Object)
	lto.Tagger().Add("foo")

	newIt, changed := lto.Optimize()
	if !changed {
		t.Error("Iterator didn't change")
	}
	if newIt.Type() != Type() {
		t.Fatal("Didn't swap out to LLRB")
	}

	v := newIt.(*Iterator)
	vClone := v.Clone()
	origDesc := v.Describe()
	cloneDesc := vClone.Describe()
	origDesc.UID, cloneDesc.UID = 0, 0 // We are more strict now, so fake UID equality.
	if !reflect.DeepEqual(cloneDesc, origDesc) {
		t.Fatalf("Unexpected iterator description.\ngot: %#v\nexpect: %#v", cloneDesc, origDesc)
	}
	vt := vClone.Tagger()
	if len(vt.Tags()) < 1 || vt.Tags()[0] != "foo" {
		t.Fatal("Tag on LinksTo did not persist")
	}
}
Exemple #11
0
func TestIteratorsAndNextResultOrderA(t testing.TB, gen DatabaseFunc) {
	qs, opts, closer := gen(t)
	defer closer()

	MakeWriter(t, qs, opts, MakeQuadSet()...)

	require.Equal(t, int64(11), qs.Size(), "Incorrect number of quads")

	fixed := qs.FixedIterator()
	fixed.Add(qs.ValueOf(quad.Raw("C")))

	fixed2 := qs.FixedIterator()
	fixed2.Add(qs.ValueOf(quad.Raw("follows")))

	all := qs.NodesAllIterator()

	innerAnd := iterator.NewAnd(qs)
	innerAnd.AddSubIterator(iterator.NewLinksTo(qs, fixed2, quad.Predicate))
	innerAnd.AddSubIterator(iterator.NewLinksTo(qs, all, quad.Object))

	hasa := iterator.NewHasA(qs, innerAnd, quad.Subject)
	outerAnd := iterator.NewAnd(qs)
	outerAnd.AddSubIterator(fixed)
	outerAnd.AddSubIterator(hasa)

	require.True(t, outerAnd.Next(), "Expected one matching subtree")

	val := outerAnd.Result()
	require.Equal(t, quad.Raw("C"), qs.NameOf(val))

	var (
		got    []string
		expect = []string{"B", "D"}
	)
	for {
		got = append(got, qs.NameOf(all.Result()).String())
		if !outerAnd.NextPath() {
			break
		}
	}
	sort.Strings(got)

	require.Equal(t, expect, got)

	require.True(t, !outerAnd.Next(), "More than one possible top level output?")
}
Exemple #12
0
func buildInOutPredicateIterator(obj *otto.Object, qs graph.QuadStore, base graph.Iterator, isReverse bool) graph.Iterator {
	dir := quad.Subject
	if isReverse {
		dir = quad.Object
	}
	lto := iterator.NewLinksTo(qs, base, dir)
	hasa := iterator.NewHasA(qs, lto, quad.Predicate)
	return iterator.NewUnique(hasa)
}
func inOutIterator(viaPath *Path, from graph.Iterator, inIterator bool, tags []string) graph.Iterator {
	start, goal := quad.Subject, quad.Object
	if inIterator {
		start, goal = goal, start
	}

	viaIter := viaPath.BuildIterator()
	for _, tag := range tags {
		viaIter.Tagger().Add(tag)
	}

	source := iterator.NewLinksTo(viaPath.qs, from, start)
	trail := iterator.NewLinksTo(viaPath.qs, viaIter, quad.Predicate)

	route := join(viaPath.qs, source, trail)

	return iterator.NewHasA(viaPath.qs, route, goal)
}
Exemple #14
0
func TestIteratorsAndNextResultOrderA(t *testing.T) {
	ts := MakeTestingMemstore()
	fixed := ts.FixedIterator()
	fixed.AddValue(ts.GetIdFor("C"))
	all := ts.GetNodesAllIterator()
	lto := iterator.NewLinksTo(ts, all, graph.Object)
	innerAnd := iterator.NewAnd()

	fixed2 := ts.FixedIterator()
	fixed2.AddValue(ts.GetIdFor("follows"))
	lto2 := iterator.NewLinksTo(ts, fixed2, graph.Predicate)
	innerAnd.AddSubIterator(lto2)
	innerAnd.AddSubIterator(lto)
	hasa := iterator.NewHasA(ts, innerAnd, graph.Subject)
	outerAnd := iterator.NewAnd()
	outerAnd.AddSubIterator(fixed)
	outerAnd.AddSubIterator(hasa)
	val, ok := outerAnd.Next()
	if !ok {
		t.Error("Expected one matching subtree")
	}
	if ts.GetNameFor(val) != "C" {
		t.Errorf("Matching subtree should be %s, got %s", "barak", ts.GetNameFor(val))
	}
	expected := make([]string, 2)
	expected[0] = "B"
	expected[1] = "D"
	actualOut := make([]string, 2)
	actualOut[0] = ts.GetNameFor(all.LastResult())
	nresultOk := outerAnd.NextResult()
	if !nresultOk {
		t.Error("Expected two results got one")
	}
	actualOut[1] = ts.GetNameFor(all.LastResult())
	nresultOk = outerAnd.NextResult()
	if nresultOk {
		t.Error("Expected two results got three")
	}
	CompareStringSlices(t, expected, actualOut)
	val, ok = outerAnd.Next()
	if ok {
		t.Error("More than one possible top level output?")
	}
}
Exemple #15
0
func TestRemoveTriple(t *testing.T) {
	ts := MakeTestingMemstore()
	ts.RemoveTriple(&graph.Triple{"E", "follows", "F", ""})
	fixed := ts.FixedIterator()
	fixed.AddValue(ts.GetIdFor("E"))
	lto := iterator.NewLinksTo(ts, fixed, graph.Subject)
	fixed2 := ts.FixedIterator()
	fixed2.AddValue(ts.GetIdFor("follows"))
	lto2 := iterator.NewLinksTo(ts, fixed2, graph.Predicate)
	innerAnd := iterator.NewAnd()
	innerAnd.AddSubIterator(lto2)
	innerAnd.AddSubIterator(lto)
	hasa := iterator.NewHasA(ts, innerAnd, graph.Object)
	newIt, _ := hasa.Optimize()
	_, ok := newIt.Next()
	if ok {
		t.Error("E should not have any followers.")
	}
}
Exemple #16
0
func buildInOutIterator(obj *otto.Object, ts graph.TripleStore, base graph.Iterator, isReverse bool) graph.Iterator {
	argList, _ := obj.Get("_gremlin_values")
	if argList.Class() != "GoArray" {
		glog.Errorln("How is arglist not an array? Return nothing.", argList.Class())
		return iterator.NewNull()
	}
	argArray := argList.Object()
	lengthVal, _ := argArray.Get("length")
	length, _ := lengthVal.ToInteger()
	var predicateNodeIterator graph.Iterator
	if length == 0 {
		predicateNodeIterator = ts.NodesAllIterator()
	} else {
		zero, _ := argArray.Get("0")
		predicateNodeIterator = buildIteratorFromValue(zero, ts)
	}
	if length >= 2 {
		var tags []string
		one, _ := argArray.Get("1")
		if one.IsString() {
			s, _ := one.ToString()
			tags = append(tags, s)
		} else if one.Class() == "Array" {
			tags = makeListOfStringsFromArrayValue(one.Object())
		}
		for _, tag := range tags {
			predicateNodeIterator.Tagger().Add(tag)
		}
	}

	in, out := quad.Subject, quad.Object
	if isReverse {
		in, out = out, in
	}
	lto := iterator.NewLinksTo(ts, base, in)
	and := iterator.NewAnd()
	and.AddSubIterator(iterator.NewLinksTo(ts, predicateNodeIterator, quad.Predicate))
	and.AddSubIterator(lto)
	return iterator.NewHasA(ts, and, out)
}
// hasMorphism is the set of nodes that is reachable via either a *Path, a
// single node.(string) or a list of nodes.([]string).
func hasMorphism(via interface{}, nodes ...string) morphism {
	return morphism{
		Name:     "has",
		Reversal: func(ctx *context) (morphism, *context) { return hasMorphism(via, nodes...), ctx },
		Apply: func(qs graph.QuadStore, in graph.Iterator, ctx *context) (graph.Iterator, *context) {
			viaIter := buildViaPath(qs, via).
				BuildIterator()
			ends := func() graph.Iterator {
				if len(nodes) == 0 {
					return qs.NodesAllIterator()
				}

				fixed := qs.FixedIterator()
				for _, n := range nodes {
					fixed.Add(qs.ValueOf(n))
				}
				return fixed
			}()

			trail := iterator.NewLinksTo(qs, viaIter, quad.Predicate)
			dest := iterator.NewLinksTo(qs, ends, quad.Object)

			// If we were given nodes, intersecting with them first will
			// be extremely cheap-- otherwise, it will be the most expensive
			// (requiring iteration over all nodes). We have enough info to
			// make this optimization now since intersections are commutative
			if len(nodes) == 0 { // Where dest involves an All iterator.
				route := join(qs, trail, dest)
				has := iterator.NewHasA(qs, route, quad.Subject)
				return join(qs, in, has), ctx
			}

			// This looks backwards. That's OK-- see the note above.
			route := join(qs, dest, trail)
			has := iterator.NewHasA(qs, route, quad.Subject)
			return join(qs, has, in), ctx
		},
	}
}
Exemple #18
0
func TestOptimize(t *testing.T) {
	var ts *TripleStore
	var lto graph.Iterator
	var tmpDir string

	Convey("Given a prepared database", t, func() {
		tmpDir, _ = ioutil.TempDir(os.TempDir(), "cayley_test")
		t.Log(tmpDir)
		defer os.RemoveAll(tmpDir)
		ok := CreateNewLevelDB(tmpDir)
		So(ok, ShouldBeTrue)
		ts = NewTripleStore(tmpDir, nil)
		ts.AddTripleSet(makeTripleSet())

		Convey("With an linksto-fixed pair", func() {
			fixed := ts.FixedIterator()
			fixed.AddValue(ts.GetIdFor("F"))
			fixed.AddTag("internal")
			lto = iterator.NewLinksTo(ts, fixed, graph.Object)

			Convey("Creates an appropriate iterator", func() {
				oldIt := lto.Clone()
				newIt, ok := lto.Optimize()
				So(ok, ShouldBeTrue)
				So(newIt.Type(), ShouldEqual, "leveldb")

				Convey("Containing the right things", func() {
					afterOp := extractTripleFromIterator(ts, newIt)
					beforeOp := extractTripleFromIterator(ts, oldIt)
					sort.Strings(afterOp)
					sort.Strings(beforeOp)
					So(afterOp, ShouldResemble, beforeOp)
				})

				Convey("With the correct tags", func() {
					oldIt.Next()
					newIt.Next()
					oldResults := make(map[string]graph.TSVal)
					oldIt.TagResults(&oldResults)
					newResults := make(map[string]graph.TSVal)
					oldIt.TagResults(&newResults)
					So(newResults, ShouldResemble, oldResults)
				})

			})

		})

	})

}
func buildHas(qs graph.QuadStore, via interface{}, in graph.Iterator, reverse bool, nodes []quad.Value) graph.Iterator {
	viaIter := buildViaPath(qs, via).
		BuildIterator()
	ends := func() graph.Iterator {
		if len(nodes) == 0 {
			return qs.NodesAllIterator()
		}

		fixed := qs.FixedIterator()
		for _, n := range nodes {
			fixed.Add(qs.ValueOf(n))
		}
		return fixed
	}()

	start, goal := quad.Subject, quad.Object
	if reverse {
		start, goal = goal, start
	}

	trail := iterator.NewLinksTo(qs, viaIter, quad.Predicate)
	dest := iterator.NewLinksTo(qs, ends, goal)

	// If we were given nodes, intersecting with them first will
	// be extremely cheap-- otherwise, it will be the most expensive
	// (requiring iteration over all nodes). We have enough info to
	// make this optimization now since intersections are commutative
	if len(nodes) == 0 { // Where dest involves an All iterator.
		route := join(qs, trail, dest)
		has := iterator.NewHasA(qs, route, start)
		return join(qs, in, has)
	}

	// This looks backwards. That's OK-- see the note above.
	route := join(qs, dest, trail)
	has := iterator.NewHasA(qs, route, start)
	return join(qs, has, in)
}
func buildSave(qs graph.QuadStore, via interface{}, tag string, it graph.Iterator, reverse bool) graph.Iterator {
	all := qs.NodesAllIterator()
	all.Tagger().Add(tag)
	node, allDir := quad.Subject, quad.Object
	var viaPath *Path
	if via != nil {
		viaPath = buildViaPath(qs, via)
	} else {
		viaPath = buildViaPath(qs)
	}
	if reverse {
		node, allDir = allDir, node
	}
	lto := iterator.NewLinksTo(qs, all, allDir)
	subAnd := iterator.NewAnd(qs)
	subAnd.AddSubIterator(iterator.NewLinksTo(qs, viaPath.BuildIterator(), quad.Predicate))
	subAnd.AddSubIterator(lto)
	hasa := iterator.NewHasA(qs, subAnd, node)
	and := iterator.NewAnd(qs)
	and.AddSubIterator(hasa)
	and.AddSubIterator(it)
	return and
}
Exemple #21
0
func TestRemoveTriple(t *testing.T) {
	ts, _ := makeTestStore(simpleGraph)

	ts.RemoveTriple(&graph.Triple{"E", "follows", "F", ""})

	fixed := ts.FixedIterator()
	fixed.Add(ts.ValueOf("E"))

	fixed2 := ts.FixedIterator()
	fixed2.Add(ts.ValueOf("follows"))

	innerAnd := iterator.NewAnd()
	innerAnd.AddSubIterator(iterator.NewLinksTo(ts, fixed, graph.Subject))
	innerAnd.AddSubIterator(iterator.NewLinksTo(ts, fixed2, graph.Predicate))

	hasa := iterator.NewHasA(ts, innerAnd, graph.Object)

	newIt, _ := hasa.Optimize()
	_, ok := newIt.Next()
	if ok {
		t.Error("E should not have any followers.")
	}
}
func inOutIterator(viaPath *Path, from graph.Iterator, inIterator bool, tags []string, ctx *context) graph.Iterator {
	start, goal := quad.Subject, quad.Object
	if inIterator {
		start, goal = goal, start
	}

	viaIter := viaPath.BuildIterator()
	for _, tag := range tags {
		viaIter.Tagger().Add(tag)
	}

	source := iterator.NewLinksTo(viaPath.qs, from, start)
	trail := iterator.NewLinksTo(viaPath.qs, viaIter, quad.Predicate)
	var label graph.Iterator
	if ctx != nil {
		if ctx.labelSet != nil {
			labeliter := ctx.labelSet.BuildIteratorOn(viaPath.qs)
			label = iterator.NewLinksTo(viaPath.qs, labeliter, quad.Label)
		}
	}
	route := join(viaPath.qs, source, trail, label)

	return iterator.NewHasA(viaPath.qs, route, goal)
}
Exemple #23
0
func TestOptimize(t *testing.T) {
	tmpFile, _ := ioutil.TempFile(os.TempDir(), "cayley_test")
	t.Log(tmpFile.Name())
	defer os.RemoveAll(tmpFile.Name())
	err := createNewBolt(tmpFile.Name(), nil)
	if err != nil {
		t.Fatalf("Failed to create working directory")
	}
	qs, err := newQuadStore(tmpFile.Name(), nil)
	if qs == nil || err != nil {
		t.Error("Failed to create leveldb QuadStore.")
	}

	w, _ := writer.NewSingleReplication(qs, nil)
	w.AddQuadSet(makeQuadSet())

	// With an linksto-fixed pair
	fixed := qs.FixedIterator()
	fixed.Add(qs.ValueOf("F"))
	fixed.Tagger().Add("internal")
	lto := iterator.NewLinksTo(qs, fixed, quad.Object)

	oldIt := lto.Clone()
	newIt, ok := lto.Optimize()
	if !ok {
		t.Errorf("Failed to optimize iterator")
	}
	if newIt.Type() != Type() {
		t.Errorf("Optimized iterator type does not match original, got:%v expect:%v", newIt.Type(), Type())
	}

	newQuads := iteratedQuads(qs, newIt)
	oldQuads := iteratedQuads(qs, oldIt)
	if !reflect.DeepEqual(newQuads, oldQuads) {
		t.Errorf("Optimized iteration does not match original")
	}

	graph.Next(oldIt)
	oldResults := make(map[string]graph.Value)
	oldIt.TagResults(oldResults)
	graph.Next(newIt)
	newResults := make(map[string]graph.Value)
	newIt.TagResults(newResults)
	if !reflect.DeepEqual(newResults, oldResults) {
		t.Errorf("Discordant tag results, new:%v old:%v", newResults, oldResults)
	}
}
Exemple #24
0
func TestOptimize(t *testing.T) {
	tmpDir, _ := ioutil.TempDir(os.TempDir(), "cayley_test")
	t.Log(tmpDir)
	defer os.RemoveAll(tmpDir)
	err := createNewLevelDB(tmpDir, nil)
	if err != nil {
		t.Fatalf("Failed to create working directory")
	}
	ts, err := newTripleStore(tmpDir, nil)
	if ts == nil || err != nil {
		t.Error("Failed to create leveldb TripleStore.")
	}
	ts.AddTripleSet(makeTripleSet())

	// With an linksto-fixed pair
	fixed := ts.FixedIterator()
	fixed.Add(ts.ValueOf("F"))
	fixed.AddTag("internal")
	lto := iterator.NewLinksTo(ts, fixed, graph.Object)

	oldIt := lto.Clone()
	newIt, ok := lto.Optimize()
	if !ok {
		t.Errorf("Failed to optimize iterator")
	}
	if newIt.Type() != Type() {
		t.Errorf("Optimized iterator type does not match original, got:%v expect:%v", newIt.Type(), Type())
	}

	newTriples := iteratedTriples(ts, newIt)
	oldTriples := iteratedTriples(ts, oldIt)
	if !reflect.DeepEqual(newTriples, oldTriples) {
		t.Errorf("Optimized iteration does not match original")
	}

	oldIt.Next()
	oldResults := make(map[string]graph.Value)
	oldIt.TagResults(oldResults)
	newIt.Next()
	newResults := make(map[string]graph.Value)
	newIt.TagResults(newResults)
	if !reflect.DeepEqual(newResults, oldResults) {
		t.Errorf("Discordant tag results, new:%v old:%v", newResults, oldResults)
	}
}
// predicatesMorphism iterates to the uniqified set of predicates from
// the given set of nodes in the path.
func predicatesMorphism(isIn bool) morphism {
	m := morphism{
		Name: "out_predicates",
		Reversal: func(ctx *context) (morphism, *context) {
			panic("not implemented: need a function from predicates to their associated edges")
		},
		Apply: func(qs graph.QuadStore, in graph.Iterator, ctx *context) (graph.Iterator, *context) {
			dir := quad.Subject
			if isIn {
				dir = quad.Object
			}
			lto := iterator.NewLinksTo(qs, in, dir)
			hasa := iterator.NewHasA(qs, lto, quad.Predicate)
			return iterator.NewUnique(hasa), ctx
		},
	}
	if isIn {
		m.Name = "in_predicates"
	}
	return m
}
Exemple #26
0
func TestOptimize(t *testing.T) {
	qs, opts, closer := makeBolt(t)
	defer closer()

	graphtest.MakeWriter(t, qs, opts, graphtest.MakeQuadSet()...)

	// With an linksto-fixed pair
	fixed := qs.FixedIterator()
	fixed.Add(qs.ValueOf(quad.Raw("F")))
	fixed.Tagger().Add("internal")
	lto := iterator.NewLinksTo(qs, fixed, quad.Object)

	oldIt := lto.Clone()
	newIt, ok := lto.Optimize()
	if !ok {
		t.Errorf("Failed to optimize iterator")
	}
	if newIt.Type() != Type() {
		t.Errorf("Optimized iterator type does not match original, got:%v expect:%v", newIt.Type(), Type())
	}

	newQuads := graphtest.IteratedQuads(t, qs, newIt)
	oldQuads := graphtest.IteratedQuads(t, qs, oldIt)
	if !reflect.DeepEqual(newQuads, oldQuads) {
		t.Errorf("Optimized iteration does not match original")
	}

	graph.Next(oldIt)
	oldResults := make(map[string]graph.Value)
	oldIt.TagResults(oldResults)
	graph.Next(newIt)
	newResults := make(map[string]graph.Value)
	newIt.TagResults(newResults)
	if !reflect.DeepEqual(newResults, oldResults) {
		t.Errorf("Discordant tag results, new:%v old:%v", newResults, oldResults)
	}
}
Exemple #27
0
func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph.Iterator) graph.Iterator {
	var it graph.Iterator
	it = base
	// TODO: Better error handling
	kindVal, _ := obj.Get("_gremlin_type")
	stringArgs := getStringArgs(obj)
	var subIt graph.Iterator
	prevVal, _ := obj.Get("_gremlin_prev")
	if !prevVal.IsObject() {
		subIt = base
	} else {
		subIt = buildIteratorTreeHelper(prevVal.Object(), ts, base)
	}

	kind, _ := kindVal.ToString()
	switch kind {
	case "vertex":
		if len(stringArgs) == 0 {
			it = ts.NodesAllIterator()
		} else {
			fixed := ts.FixedIterator()
			for _, name := range stringArgs {
				fixed.Add(ts.ValueOf(name))
			}
			it = fixed
		}
	case "tag":
		it = subIt
		for _, tag := range stringArgs {
			it.Tagger().Add(tag)
		}
	case "save":
		all := ts.NodesAllIterator()
		if len(stringArgs) > 2 || len(stringArgs) == 0 {
			return iterator.NewNull()
		}
		if len(stringArgs) == 2 {
			all.Tagger().Add(stringArgs[1])
		} else {
			all.Tagger().Add(stringArgs[0])
		}
		predFixed := ts.FixedIterator()
		predFixed.Add(ts.ValueOf(stringArgs[0]))
		subAnd := iterator.NewAnd()
		subAnd.AddSubIterator(iterator.NewLinksTo(ts, predFixed, quad.Predicate))
		subAnd.AddSubIterator(iterator.NewLinksTo(ts, all, quad.Object))
		hasa := iterator.NewHasA(ts, subAnd, quad.Subject)
		and := iterator.NewAnd()
		and.AddSubIterator(hasa)
		and.AddSubIterator(subIt)
		it = and
	case "saver":
		all := ts.NodesAllIterator()
		if len(stringArgs) > 2 || len(stringArgs) == 0 {
			return iterator.NewNull()
		}
		if len(stringArgs) == 2 {
			all.Tagger().Add(stringArgs[1])
		} else {
			all.Tagger().Add(stringArgs[0])
		}
		predFixed := ts.FixedIterator()
		predFixed.Add(ts.ValueOf(stringArgs[0]))
		subAnd := iterator.NewAnd()
		subAnd.AddSubIterator(iterator.NewLinksTo(ts, predFixed, quad.Predicate))
		subAnd.AddSubIterator(iterator.NewLinksTo(ts, all, quad.Subject))
		hasa := iterator.NewHasA(ts, subAnd, quad.Object)
		and := iterator.NewAnd()
		and.AddSubIterator(hasa)
		and.AddSubIterator(subIt)
		it = and
	case "has":
		fixed := ts.FixedIterator()
		if len(stringArgs) < 2 {
			return iterator.NewNull()
		}
		for _, name := range stringArgs[1:] {
			fixed.Add(ts.ValueOf(name))
		}
		predFixed := ts.FixedIterator()
		predFixed.Add(ts.ValueOf(stringArgs[0]))
		subAnd := iterator.NewAnd()
		subAnd.AddSubIterator(iterator.NewLinksTo(ts, predFixed, quad.Predicate))
		subAnd.AddSubIterator(iterator.NewLinksTo(ts, fixed, quad.Object))
		hasa := iterator.NewHasA(ts, subAnd, quad.Subject)
		and := iterator.NewAnd()
		and.AddSubIterator(hasa)
		and.AddSubIterator(subIt)
		it = and
	case "morphism":
		it = base
	case "and":
		arg, _ := obj.Get("_gremlin_values")
		firstArg, _ := arg.Object().Get("0")
		if !isVertexChain(firstArg.Object()) {
			return iterator.NewNull()
		}
		argIt := buildIteratorTree(firstArg.Object(), ts)

		and := iterator.NewAnd()
		and.AddSubIterator(subIt)
		and.AddSubIterator(argIt)
		it = and
	case "back":
		arg, _ := obj.Get("_gremlin_back_chain")
		argIt := buildIteratorTree(arg.Object(), ts)
		and := iterator.NewAnd()
		and.AddSubIterator(subIt)
		and.AddSubIterator(argIt)
		it = and
	case "is":
		fixed := ts.FixedIterator()
		for _, name := range stringArgs {
			fixed.Add(ts.ValueOf(name))
		}
		and := iterator.NewAnd()
		and.AddSubIterator(fixed)
		and.AddSubIterator(subIt)
		it = and
	case "or":
		arg, _ := obj.Get("_gremlin_values")
		firstArg, _ := arg.Object().Get("0")
		if !isVertexChain(firstArg.Object()) {
			return iterator.NewNull()
		}
		argIt := buildIteratorTree(firstArg.Object(), ts)

		or := iterator.NewOr()
		or.AddSubIterator(subIt)
		or.AddSubIterator(argIt)
		it = or
	case "both":
		// Hardly the most efficient pattern, but the most general.
		// Worth looking into an Optimize() optimization here.
		clone := subIt.Clone()
		it1 := buildInOutIterator(obj, ts, subIt, false)
		it2 := buildInOutIterator(obj, ts, clone, true)

		or := iterator.NewOr()
		or.AddSubIterator(it1)
		or.AddSubIterator(it2)
		it = or
	case "out":
		it = buildInOutIterator(obj, ts, subIt, false)
	case "follow":
		// Follow a morphism
		arg, _ := obj.Get("_gremlin_values")
		firstArg, _ := arg.Object().Get("0")
		if isVertexChain(firstArg.Object()) {
			return iterator.NewNull()
		}
		it = buildIteratorTreeHelper(firstArg.Object(), ts, subIt)
	case "followr":
		// Follow a morphism
		arg, _ := obj.Get("_gremlin_followr")
		if isVertexChain(arg.Object()) {
			return iterator.NewNull()
		}
		it = buildIteratorTreeHelper(arg.Object(), ts, subIt)
	case "in":
		it = buildInOutIterator(obj, ts, subIt, true)
	}
	return it
}
Exemple #28
0
func buildIteratorTreeHelper(obj *otto.Object, qs graph.QuadStore, base graph.Iterator) graph.Iterator {
	// TODO: Better error handling
	var (
		it    graph.Iterator
		subIt graph.Iterator
	)

	if prev, _ := obj.Get("_gremlin_prev"); !prev.IsObject() {
		subIt = base
	} else {
		subIt = buildIteratorTreeHelper(prev.Object(), qs, base)
	}

	stringArgs := propertiesOf(obj, "string_args")
	val, _ := obj.Get("_gremlin_type")
	switch val.String() {
	case "vertex":
		if len(stringArgs) == 0 {
			it = qs.NodesAllIterator()
		} else {
			fixed := qs.FixedIterator()
			for _, name := range stringArgs {
				fixed.Add(qs.ValueOf(name))
			}
			it = fixed
		}
	case "tag":
		it = subIt
		for _, tag := range stringArgs {
			it.Tagger().Add(tag)
		}
	case "save":
		all := qs.NodesAllIterator()
		if len(stringArgs) > 2 || len(stringArgs) == 0 {
			return iterator.NewNull()
		}
		if len(stringArgs) == 2 {
			all.Tagger().Add(stringArgs[1])
		} else {
			all.Tagger().Add(stringArgs[0])
		}
		predFixed := qs.FixedIterator()
		predFixed.Add(qs.ValueOf(stringArgs[0]))
		subAnd := iterator.NewAnd(qs)
		subAnd.AddSubIterator(iterator.NewLinksTo(qs, predFixed, quad.Predicate))
		subAnd.AddSubIterator(iterator.NewLinksTo(qs, all, quad.Object))
		hasa := iterator.NewHasA(qs, subAnd, quad.Subject)
		and := iterator.NewAnd(qs)
		and.AddSubIterator(hasa)
		and.AddSubIterator(subIt)
		it = and
	case "saver":
		all := qs.NodesAllIterator()
		if len(stringArgs) > 2 || len(stringArgs) == 0 {
			return iterator.NewNull()
		}
		if len(stringArgs) == 2 {
			all.Tagger().Add(stringArgs[1])
		} else {
			all.Tagger().Add(stringArgs[0])
		}
		predFixed := qs.FixedIterator()
		predFixed.Add(qs.ValueOf(stringArgs[0]))
		subAnd := iterator.NewAnd(qs)
		subAnd.AddSubIterator(iterator.NewLinksTo(qs, predFixed, quad.Predicate))
		subAnd.AddSubIterator(iterator.NewLinksTo(qs, all, quad.Subject))
		hasa := iterator.NewHasA(qs, subAnd, quad.Object)
		and := iterator.NewAnd(qs)
		and.AddSubIterator(hasa)
		and.AddSubIterator(subIt)
		it = and
	case "has":
		fixed := qs.FixedIterator()
		if len(stringArgs) < 2 {
			return iterator.NewNull()
		}
		for _, name := range stringArgs[1:] {
			fixed.Add(qs.ValueOf(name))
		}
		predFixed := qs.FixedIterator()
		predFixed.Add(qs.ValueOf(stringArgs[0]))
		subAnd := iterator.NewAnd(qs)
		subAnd.AddSubIterator(iterator.NewLinksTo(qs, predFixed, quad.Predicate))
		subAnd.AddSubIterator(iterator.NewLinksTo(qs, fixed, quad.Object))
		hasa := iterator.NewHasA(qs, subAnd, quad.Subject)
		and := iterator.NewAnd(qs)
		and.AddSubIterator(hasa)
		and.AddSubIterator(subIt)
		it = and
	case "morphism":
		it = base
	case "and":
		arg, _ := obj.Get("_gremlin_values")
		firstArg, _ := arg.Object().Get("0")
		if !isVertexChain(firstArg.Object()) {
			return iterator.NewNull()
		}
		argIt := buildIteratorTree(firstArg.Object(), qs)

		and := iterator.NewAnd(qs)
		and.AddSubIterator(subIt)
		and.AddSubIterator(argIt)
		it = and
	case "back":
		arg, _ := obj.Get("_gremlin_back_chain")
		argIt := buildIteratorTree(arg.Object(), qs)
		and := iterator.NewAnd(qs)
		and.AddSubIterator(subIt)
		and.AddSubIterator(argIt)
		it = and
	case "is":
		fixed := qs.FixedIterator()
		for _, name := range stringArgs {
			fixed.Add(qs.ValueOf(name))
		}
		and := iterator.NewAnd(qs)
		and.AddSubIterator(fixed)
		and.AddSubIterator(subIt)
		it = and
	case "or":
		arg, _ := obj.Get("_gremlin_values")
		firstArg, _ := arg.Object().Get("0")
		if !isVertexChain(firstArg.Object()) {
			return iterator.NewNull()
		}
		argIt := buildIteratorTree(firstArg.Object(), qs)

		or := iterator.NewOr()
		or.AddSubIterator(subIt)
		or.AddSubIterator(argIt)
		it = or
	case "both":
		// Hardly the most efficient pattern, but the most general.
		// Worth looking into an Optimize() optimization here.
		clone := subIt.Clone()
		it1 := buildInOutIterator(obj, qs, subIt, false)
		it2 := buildInOutIterator(obj, qs, clone, true)

		or := iterator.NewOr()
		or.AddSubIterator(it1)
		or.AddSubIterator(it2)
		it = or
	case "out":
		it = buildInOutIterator(obj, qs, subIt, false)
	case "follow":
		// Follow a morphism
		arg, _ := obj.Get("_gremlin_values")
		firstArg, _ := arg.Object().Get("0")
		if isVertexChain(firstArg.Object()) {
			return iterator.NewNull()
		}
		it = buildIteratorTreeHelper(firstArg.Object(), qs, subIt)
	case "followr":
		// Follow a morphism
		arg, _ := obj.Get("_gremlin_followr")
		if isVertexChain(arg.Object()) {
			return iterator.NewNull()
		}
		it = buildIteratorTreeHelper(arg.Object(), qs, subIt)
	case "in":
		it = buildInOutIterator(obj, qs, subIt, true)
	case "except":
		arg, _ := obj.Get("_gremlin_values")
		firstArg, _ := arg.Object().Get("0")
		if !isVertexChain(firstArg.Object()) {
			return iterator.NewNull()
		}

		allIt := qs.NodesAllIterator()
		toComplementIt := buildIteratorTree(firstArg.Object(), qs)
		notIt := iterator.NewNot(toComplementIt, allIt)

		and := iterator.NewAnd(qs)
		and.AddSubIterator(subIt)
		and.AddSubIterator(notIt)
		it = and
	case "in_predicates":
		it = buildInOutPredicateIterator(obj, qs, subIt, true)
	case "out_predicates":
		it = buildInOutPredicateIterator(obj, qs, subIt, false)
	}
	if it == nil {
		panic("Iterator building does not catch the output iterator in some case.")
	}
	return it
}
Exemple #29
0
func (q *Query) buildIteratorTreeMapInternal(query map[string]interface{}, path Path) (graph.Iterator, error) {
	it := iterator.NewAnd(q.ses.qs)
	it.AddSubIterator(q.ses.qs.NodesAllIterator())
	var err error
	err = nil
	outputStructure := make(map[string]interface{})
	for key, subquery := range query {
		optional := false
		outputStructure[key] = nil
		reverse := false
		pred := key
		if strings.HasPrefix(pred, "@") {
			i := strings.Index(pred, ":")
			if i != -1 {
				pred = pred[(i + 1):]
			}
		}
		if strings.HasPrefix(pred, "!") {
			reverse = true
			pred = strings.TrimPrefix(pred, "!")
		}

		// Other special constructs here
		var subit graph.Iterator
		if key == "id" {
			subit, optional, err = q.buildIteratorTreeInternal(subquery, path.Follow(key))
			if err != nil {
				return nil, err
			}
		} else {
			var builtIt graph.Iterator
			builtIt, optional, err = q.buildIteratorTreeInternal(subquery, path.Follow(key))
			if err != nil {
				return nil, err
			}
			subAnd := iterator.NewAnd(q.ses.qs)
			predFixed := q.ses.qs.FixedIterator()
			predFixed.Add(q.ses.qs.ValueOf(quad.Raw(pred)))
			subAnd.AddSubIterator(iterator.NewLinksTo(q.ses.qs, predFixed, quad.Predicate))
			if reverse {
				lto := iterator.NewLinksTo(q.ses.qs, builtIt, quad.Subject)
				subAnd.AddSubIterator(lto)
				hasa := iterator.NewHasA(q.ses.qs, subAnd, quad.Object)
				subit = hasa
			} else {
				lto := iterator.NewLinksTo(q.ses.qs, builtIt, quad.Object)
				subAnd.AddSubIterator(lto)
				hasa := iterator.NewHasA(q.ses.qs, subAnd, quad.Subject)
				subit = hasa
			}
		}
		if optional {
			it.AddSubIterator(iterator.NewOptional(subit))
		} else {
			it.AddSubIterator(subit)
		}
	}
	if err != nil {
		return nil, err
	}
	q.queryStructure[path] = outputStructure
	return it, nil
}
Exemple #30
0
func buildIteratorTree(tree *peg.ExpressionTree, qs graph.QuadStore) graph.Iterator {
	switch tree.Name {
	case "Start":
		return buildIteratorTree(tree.Children[0], qs)
	case "NodeIdentifier":
		var out graph.Iterator
		nodeID := getIdentString(tree)
		if tree.Children[0].Name == "Variable" {
			allIt := qs.NodesAllIterator()
			allIt.Tagger().Add(nodeID)
			out = allIt
		} else {
			n := nodeID
			if tree.Children[0].Children[0].Name == "ColonIdentifier" {
				n = nodeID[1:]
			}
			fixed := qs.FixedIterator()
			fixed.Add(qs.ValueOf(n))
			out = fixed
		}
		return out
	case "PredIdentifier":
		i := 0
		if tree.Children[0].Name == "Reverse" {
			//Taken care of below
			i++
		}
		it := buildIteratorTree(tree.Children[i], qs)
		lto := iterator.NewLinksTo(qs, it, quad.Predicate)
		return lto
	case "RootConstraint":
		constraintCount := 0
		and := iterator.NewAnd()
		for _, c := range tree.Children {
			switch c.Name {
			case "NodeIdentifier":
				fallthrough
			case "Constraint":
				it := buildIteratorTree(c, qs)
				and.AddSubIterator(it)
				constraintCount++
				continue
			default:
				continue
			}
		}
		return and
	case "Constraint":
		var hasa *iterator.HasA
		topLevelDir := quad.Subject
		subItDir := quad.Object
		subAnd := iterator.NewAnd()
		isOptional := false
		for _, c := range tree.Children {
			switch c.Name {
			case "PredIdentifier":
				if c.Children[0].Name == "Reverse" {
					topLevelDir = quad.Object
					subItDir = quad.Subject
				}
				it := buildIteratorTree(c, qs)
				subAnd.AddSubIterator(it)
				continue
			case "PredicateKeyword":
				switch c.Children[0].Name {
				case "OptionalKeyword":
					isOptional = true
				}
			case "NodeIdentifier":
				fallthrough
			case "RootConstraint":
				it := buildIteratorTree(c, qs)
				l := iterator.NewLinksTo(qs, it, subItDir)
				subAnd.AddSubIterator(l)
				continue
			default:
				continue
			}
		}
		hasa = iterator.NewHasA(qs, subAnd, topLevelDir)
		if isOptional {
			optional := iterator.NewOptional(hasa)
			return optional
		}
		return hasa
	default:
		return &iterator.Null{}
	}
	panic("Not reached")
}