func TestMultipleConstraintParse(t *testing.T) { ts, _ := graph.NewTripleStore("memstore", "", nil) for _, tv := range []*quad.Quad{ {"i", "like", "food", ""}, {"i", "like", "beer", ""}, {"you", "like", "beer", ""}, } { ts.AddTriple(tv) } query := `( $a (:like :beer) (:like "food") )` it := BuildIteratorTreeForQuery(ts, query) if it.Type() != graph.And { t.Error("Odd iterator tree. Got: %s", it.DebugString(0)) } out, ok := graph.Next(it) if !ok { t.Error("Got no results") } if out != ts.ValueOf("i") { t.Errorf("Got %d, expected %d", out, ts.ValueOf("i")) } _, ok = graph.Next(it) if ok { t.Error("Too many results") } }
func TestMultipleConstraintParse(t *testing.T) { qs, _ := graph.NewQuadStore("memstore", "", nil) w, _ := graph.NewQuadWriter("single", qs, nil) for _, tv := range []quad.Quad{ {"i", "like", "food", ""}, {"i", "like", "beer", ""}, {"you", "like", "beer", ""}, } { w.AddQuad(tv) } query := `( $a (:like :beer) (:like "food") )` it := BuildIteratorTreeForQuery(qs, query) if it.Type() != graph.And { t.Errorf("Odd iterator tree. Got: %#v", it.Describe()) } if !graph.Next(it) { t.Error("Got no results") } out := it.Result() if out != qs.ValueOf("i") { t.Errorf("Got %d, expected %d", out, qs.ValueOf("i")) } if graph.Next(it) { t.Error("Too many results") } }
func TestSQLLinkIteration(t *testing.T) { if *postgres_path == "" { t.SkipNow() } db, err := newQuadStore(*postgres_path, nil) qs := db.(*QuadStore) if err != nil { t.Fatal(err) } it := NewSQLLinkIterator(qs, quad.Object, "Humphrey Bogart") for graph.Next(it) { fmt.Println(it.Result()) } it = NewSQLLinkIterator(qs, quad.Subject, "/en/casablanca_1942") s, v := it.sql.buildSQL(true, nil) t.Log(s, v) c := 0 for graph.Next(it) { fmt.Println(it.Result()) c += 1 } if c != 18 { t.Errorf("Not enough results, got %d expected 18", c) } }
// Next()ing a LinksTo operates as described above. func (it *LinksTo) Next() bool { graph.NextLogIn(it) it.runstats.Next += 1 if graph.Next(it.nextIt) { it.runstats.ContainsNext += 1 it.result = it.nextIt.Result() return graph.NextLogOut(it, it.result, true) } // If there's an error in the 'next' iterator, we save it and we're done. it.err = it.nextIt.Err() if it.err != nil { return false } // Subiterator is empty, get another one if !graph.Next(it.primaryIt) { // Possibly save error it.err = it.primaryIt.Err() // We're out of nodes in our subiterator, so we're done as well. return graph.NextLogOut(it, nil, false) } it.nextIt.Close() it.nextIt = it.qs.QuadIterator(it.dir, it.primaryIt.Result()) // Recurse -- return the first in the next set. return it.Next() }
// Next advances the Or graph.iterator. Because the Or is the union of its // subiterators, it must produce from all subiterators -- unless it it // shortcircuiting, in which case, it is the first one that returns anything. func (it *Or) Next() bool { graph.NextLogIn(it) var first bool for { if it.currentIterator == -1 { it.currentIterator = 0 first = true } curIt := it.internalIterators[it.currentIterator] if graph.Next(curIt) { it.result = curIt.Result() return graph.NextLogOut(it, it.result, true) } if it.isShortCircuiting && !first { break } it.currentIterator++ if it.currentIterator == it.itCount { break } } return graph.NextLogOut(it, nil, false) }
func runIteratorWithCallback(it graph.Iterator, ses *Session, callback otto.Value, this otto.FunctionCall, limit int) { count := 0 it, _ = it.Optimize() for { if ses.doHalt { return } _, ok := graph.Next(it) if !ok { break } tags := make(map[string]graph.Value) it.TagResults(tags) val, _ := this.Otto.ToValue(tagsToValueMap(tags, ses)) val, _ = callback.Call(this.This, val) count++ if limit >= 0 && count >= limit { break } for it.NextResult() == true { if ses.doHalt { return } tags := make(map[string]graph.Value) it.TagResults(tags) val, _ := this.Otto.ToValue(tagsToValueMap(tags, ses)) val, _ = callback.Call(this.This, val) count++ if limit >= 0 && count >= limit { break } } } it.Close() }
func runIteratorToArray(it graph.Iterator, ses *Session, limit int) []map[string]string { output := make([]map[string]string, 0) count := 0 it, _ = it.Optimize() for { if ses.doHalt { return nil } _, ok := graph.Next(it) if !ok { break } tags := make(map[string]graph.Value) it.TagResults(tags) output = append(output, tagsToValueMap(tags, ses)) count++ if limit >= 0 && count >= limit { break } for it.NextResult() == true { if ses.doHalt { return nil } tags := make(map[string]graph.Value) it.TagResults(tags) output = append(output, tagsToValueMap(tags, ses)) count++ if limit >= 0 && count >= limit { break } } } it.Close() return output }
func main() { store, err := cayley.NewGraph("bolt", dbPath, nil) if err != nil { fmt.Println("error in creating database", err) } path := cayley.StartPath(store, "Article"). In(). Tag("link"). Save("has_image", "image"). Save("has_title", "title"). Save("has_description", "description") it := path.BuildIterator() it, _ = it.Optimize() for graph.Next(it) { tags := make(map[string]graph.Value) it.TagResults(tags) fmt.Println(store.NameOf(tags["image"])) fmt.Println(store.NameOf(tags["title"])) fmt.Println(store.NameOf(tags["description"])) fmt.Println(store.NameOf(tags["link"])) } }
// TestQuadStoreQuadsAllIterator iterates the nodes in a fixture and asserts // the result. func TestQuadStoreQuadsAllIterator(t *testing.T, ctx context.Context) { qs := ContextQuadStore(ctx) _, err := WriteFixtureQuadStore(qs, "simple") if err != nil { t.Errorf("Unexpected error writing fixures: %v", err) } it := qs.QuadsAllIterator() defer it.Reset() graph.Next(it) t.Logf("%#v\n", it.Result()) q := qs.Quad(it.Result()) t.Log(q) set := Fixtures.QuadSet("simple").Quads var ok bool for _, e := range set { if e.String() == q.String() { ok = true break } } if !ok { t.Errorf("Failed to find %q during iteration, got:%q", q, set) } }
func (ts *TripleStore) optimizeLinksTo(it *iterator.LinksTo) (graph.Iterator, bool) { subs := it.SubIterators() if len(subs) != 1 { return it, false } primary := subs[0] if primary.Type() == graph.Fixed { size, _ := primary.Size() if size == 1 { val, ok := graph.Next(primary) if !ok { panic("Sizes lie") } newIt := ts.TripleIterator(it.Direction(), val) nt := newIt.Tagger() nt.CopyFrom(it) for _, tag := range primary.Tagger().Tags() { nt.AddFixed(tag, val) } return newIt, true } } it.Close() return it, false }
// Returns the Next value from the Or graph.iterator. Because the Or is the // union of its subiterators, it must produce from all subiterators -- unless // it's shortcircuiting, in which case, it's the first one that returns anything. func (it *Or) Next() (graph.Value, bool) { graph.NextLogIn(it) var curr graph.Value var exists bool firstTime := false for { if it.currentIterator == -1 { it.currentIterator = 0 firstTime = true } curIt := it.internalIterators[it.currentIterator] curr, exists = graph.Next(curIt) if !exists { if it.isShortCircuiting && !firstTime { return graph.NextLogOut(it, nil, false) } it.currentIterator++ if it.currentIterator == it.itCount { return graph.NextLogOut(it, nil, false) } } else { it.result = curr return graph.NextLogOut(it, curr, true) } } panic("unreachable") }
func (it *Materialize) materializeSet() { i := 0 for graph.Next(it.subIt) { i++ if i > abortMaterializeAt { it.aborted = true break } id := it.subIt.Result() val := id if h, ok := id.(Keyer); ok { val = h.Key() } if _, ok := it.containsMap[val]; !ok { it.containsMap[val] = len(it.values) it.values = append(it.values, nil) } index := it.containsMap[val] tags := make(map[string]graph.Value) it.subIt.TagResults(tags) it.values[index] = append(it.values[index], result{id: id, tags: tags}) for it.subIt.NextPath() { tags := make(map[string]graph.Value) it.subIt.TagResults(tags) it.values[index] = append(it.values[index], result{id: id, tags: tags}) } } if it.aborted { it.values = nil it.containsMap = nil it.subIt.Reset() } glog.Infof("Materialization List %d: %#v", it.values) it.hasRun = true }
func iterated(it graph.Iterator) []int { var res []int for graph.Next(it) { res = append(res, it.Result().(int)) } return res }
func (ts *QuadStore) optimizeLinksTo(it *iterator.LinksTo) (graph.Iterator, bool) { subs := it.SubIterators() if len(subs) != 1 { return it, false } primary := subs[0] if primary.Type() == graph.Fixed { size, _ := primary.Size() if size == 1 { if !graph.Next(primary) { panic("unexpected size during optimize") } val := primary.Result() newIt := ts.TripleIterator(it.Direction(), val) nt := newIt.Tagger() nt.CopyFrom(it) for _, tag := range primary.Tagger().Tags() { nt.AddFixed(tag, val) } it.Close() return newIt, true } } return it, false }
func (s *Session) ExecInput(input string, c chan interface{}, _ int) { defer close(c) var mqlQuery interface{} err := json.Unmarshal([]byte(input), &mqlQuery) if err != nil { return } s.currentQuery = NewQuery(s) s.currentQuery.BuildIteratorTree(mqlQuery) if s.currentQuery.isError() { return } it, _ := s.currentQuery.it.Optimize() if glog.V(2) { b, err := json.MarshalIndent(it.Describe(), "", " ") if err != nil { glog.Infof("failed to format description: %v", err) } else { glog.Infof("%s", b) } } for graph.Next(it) { tags := make(map[string]graph.Value) it.TagResults(tags) c <- tags for it.NextPath() == true { tags := make(map[string]graph.Value) it.TagResults(tags) c <- tags } } }
func (s *Session) ExecInput(input string, out chan interface{}, limit int) { it := BuildIteratorTreeForQuery(s.qs, input) newIt, changed := it.Optimize() if changed { it = newIt } if s.debug { fmt.Println(it.DebugString(0)) } nResults := 0 for graph.Next(it) { tags := make(map[string]graph.Value) it.TagResults(tags) out <- &tags nResults++ if nResults > limit && limit != -1 { break } for it.NextPath() == true { tags := make(map[string]graph.Value) it.TagResults(tags) out <- &tags nResults++ if nResults > limit && limit != -1 { break } } } close(out) }
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 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 (s *Session) ExecInput(input string, c chan interface{}, limit int) { defer close(c) var mqlQuery interface{} err := json.Unmarshal([]byte(input), &mqlQuery) if err != nil { return } s.currentQuery = NewQuery(s) s.currentQuery.BuildIteratorTree(mqlQuery) if s.currentQuery.isError() { return } it, _ := s.currentQuery.it.Optimize() if glog.V(2) { glog.V(2).Infoln(it.DebugString(0)) } for { _, ok := graph.Next(it) if !ok { break } tags := make(map[string]graph.Value) it.TagResults(tags) c <- tags for it.NextResult() == true { tags := make(map[string]graph.Value) it.TagResults(tags) c <- tags } } }
func TestSQLNodeIteration(t *testing.T) { if *postgres_path == "" { t.SkipNow() } db, err := newQuadStore(*postgres_path, nil) if err != nil { t.Fatal(err) } link := NewSQLLinkIterator(db.(*QuadStore), quad.Object, "/en/humphrey_bogart") it := &SQLIterator{ uid: iterator.NextUID(), qs: db.(*QuadStore), sql: &SQLNodeIterator{ tableName: newTableName(), linkIt: sqlItDir{ it: link.sql, dir: quad.Subject, }, }, } s, v := it.sql.buildSQL(true, nil) t.Log(s, v) c := 0 for graph.Next(it) { t.Log(it.Result()) c += 1 } if c != 56 { t.Errorf("Not enough results, got %d expected 56", c) } }
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) } }
func iteratedNames(qs graph.QuadStore, it graph.Iterator) []string { var res []string for graph.Next(it) { res = append(res, qs.NameOf(it.Result())) } sort.Strings(res) return res }
func iteratedQuads(qs graph.QuadStore, it graph.Iterator) []quad.Quad { var res ordered for graph.Next(it) { res = append(res, qs.Quad(it.Result())) } sort.Sort(res) return res }
func TestInterestingQuery(t *testing.T) { if *postgres_path == "" { t.SkipNow() } db, err := newQuadStore(*postgres_path, nil) if err != nil { t.Fatal(err) } qs := db.(*QuadStore) a := NewSQLLinkIterator(qs, quad.Object, "Humphrey Bogart") b := NewSQLLinkIterator(qs, quad.Predicate, "name") it1, err := intersect(a.sql, b.sql, qs) if err != nil { t.Error(err) } it2, err := hasa(it1.sql, quad.Subject, qs) if err != nil { t.Error(err) } it2.Tagger().Add("hb") it3, err := linksto(it2.sql, quad.Object, qs) if err != nil { t.Error(err) } b = NewSQLLinkIterator(db.(*QuadStore), quad.Predicate, "/film/performance/actor") it4, err := intersect(it3.sql, b.sql, qs) if err != nil { t.Error(err) } it5, err := hasa(it4.sql, quad.Subject, qs) if err != nil { t.Error(err) } it6, err := linksto(it5.sql, quad.Object, qs) if err != nil { t.Error(err) } b = NewSQLLinkIterator(db.(*QuadStore), quad.Predicate, "/film/film/starring") it7, err := intersect(it6.sql, b.sql, qs) if err != nil { t.Error(err) } it8, err := hasa(it7.sql, quad.Subject, qs) if err != nil { t.Error(err) } s, v := it8.sql.buildSQL(true, nil) it8.Tagger().Add("id") t.Log(s, v) for graph.Next(it8) { t.Log(it8.Result()) out := make(map[string]graph.Value) it8.TagResults(out) for k, v := range out { t.Log("%s: %v\n", k, v.(string)) } } }
//experimental func (exp *Exporter) ExportGml() { var seen map[string]int32 // todo eliminate this for large dbs var id int32 exp.Write("Creator Cayley\ngraph\n[\n") seen = make(map[string]int32) exp.qi.Reset() for it := exp.qi; graph.Next(it); { cur := exp.qstore.Quad(it.Result()) if _, ok := seen[cur.Subject]; !ok { exp.Write(" node\n [\n id ") seen[cur.Subject] = id exp.Write(strconv.FormatInt(int64(id), 10)) exp.Write("\n label ") exp.WriteEscString(cur.Subject) exp.Write("\n ]\n") id++ } if _, ok := seen[cur.Object]; !ok { exp.Write(" node\n [\n id ") seen[cur.Object] = id exp.Write(strconv.FormatInt(int64(id), 10)) exp.Write("\n label ") exp.WriteEscString(cur.Object) exp.Write("\n ]\n") id++ } exp.count++ } exp.qi.Reset() for it := exp.qi; graph.Next(it); { cur := exp.qstore.Quad(it.Result()) exp.Write(" edge\n [\n source ") exp.Write(strconv.FormatInt(int64(seen[cur.Subject]), 10)) exp.Write("\n target ") exp.Write(strconv.FormatInt(int64(seen[cur.Object]), 10)) exp.Write("\n label ") exp.WriteEscString(cur.Predicate) exp.Write("\n ]\n") exp.count++ } exp.Write("]\n") }
func IteratedValues(t testing.TB, qs graph.QuadStore, it graph.Iterator) []quad.Value { var res []quad.Value for graph.Next(it) { res = append(res, qs.NameOf(it.Result())) } require.Nil(t, it.Err()) sort.Sort(quad.ByValueString(res)) return res }
// Next()ing a LinksTo operates as described above. func (it *LinksTo) Next() bool { graph.NextLogIn(it) if graph.Next(it.nextIt) { it.result = it.nextIt.Result() return graph.NextLogOut(it, it.nextIt, true) } // Subiterator is empty, get another one if !graph.Next(it.primaryIt) { // We're out of nodes in our subiterator, so we're done as well. return graph.NextLogOut(it, 0, false) } it.nextIt.Close() it.nextIt = it.ts.TripleIterator(it.dir, it.primaryIt.Result()) // Recurse -- return the first in the next set. return it.Next() }
// Next()ing a LinksTo operates as described above. func (it *LinksTo) Next() (graph.Value, bool) { graph.NextLogIn(it) val, ok := graph.Next(it.nextIt) if !ok { // Subiterator is empty, get another one candidate, ok := graph.Next(it.primaryIt) if !ok { // We're out of nodes in our subiterator, so we're done as well. return graph.NextLogOut(it, 0, false) } it.nextIt.Close() it.nextIt = it.ts.TripleIterator(it.dir, candidate) // Recurse -- return the first in the next set. return it.Next() } it.result = val return graph.NextLogOut(it, val, ok) }
func IteratedRawStrings(t testing.TB, qs graph.QuadStore, it graph.Iterator) []string { var res []string for graph.Next(it) { res = append(res, qs.NameOf(it.Result()).String()) } require.Nil(t, it.Err()) sort.Strings(res) return res }
func IteratedQuads(t testing.TB, qs graph.QuadStore, it graph.Iterator) []quad.Quad { var res quad.ByQuadString for graph.Next(it) { res = append(res, qs.Quad(it.Result())) } require.Nil(t, it.Err()) sort.Sort(res) return res }