// ToNative converts protobuf Quad to quad.Quad. func (m *Quad) ToNative() (q quad.Quad) { if m == nil { return } if m.SubjectValue != nil { q.Subject = m.SubjectValue.ToNative() } else if m.Subject != "" { q.Subject = quad.Raw(m.Subject) } if m.PredicateValue != nil { q.Predicate = m.PredicateValue.ToNative() } else if m.Predicate != "" { q.Predicate = quad.Raw(m.Predicate) } if m.ObjectValue != nil { q.Object = m.ObjectValue.ToNative() } else if m.Object != "" { q.Object = quad.Raw(m.Object) } if m.LabelValue != nil { q.Label = m.LabelValue.ToNative() } else if m.Label != "" { q.Label = quad.Raw(m.Label) } return }
func TestRemoveQuad(t *testing.T) { qs, w, _ := makeTestStore(simpleGraph) err := w.RemoveQuad(quad.MakeRaw( "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 newIt.Next() { t.Error("E should not have any followers.") } }
func TestMultipleConstraintParse(t *testing.T) { qs, _ := graph.NewQuadStore("memstore", "", nil) w, _ := graph.NewQuadWriter("single", qs, nil) for _, tv := range []quad.Quad{ quad.MakeRaw("i", "like", "food", ""), quad.MakeRaw("i", "like", "beer", ""), quad.MakeRaw("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 !it.Next() { t.Error("Got no results") } out := it.Result() if out != qs.ValueOf(quad.Raw("i")) { t.Errorf("Got %d, expected %d", out, qs.ValueOf(quad.Raw("i"))) } if it.Next() { 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, quad.Raw("Humphrey Bogart")) for it.Next() { fmt.Println(it.Result()) } it = NewSQLLinkIterator(qs, quad.Subject, quad.Raw("/en/casablanca_1942")) s, v := it.sql.buildSQL(true, nil) t.Log(s, v) c := 0 for it.Next() { fmt.Println(it.Result()) c += 1 } if c != 18 { t.Errorf("Not enough results, got %d expected 18", c) } }
func TestIterators(t *testing.T) { qs, opts, closer := makeGAE(t) defer closer() graphtest.MakeWriter(t, qs, opts, graphtest.MakeQuadSet()...) require.Equal(t, int64(11), qs.Size(), "Incorrect number of quads") var expected = []quad.Quad{ quad.MakeRaw("C", "follows", "B", ""), quad.MakeRaw("C", "follows", "D", ""), } it := qs.QuadIterator(quad.Subject, qs.ValueOf(quad.Raw("C"))) graphtest.ExpectIteratedQuads(t, qs, it, expected) // Test contains it = qs.QuadIterator(quad.Label, qs.ValueOf(quad.Raw("status_graph"))) gqs := qs.(*QuadStore) key := gqs.createKeyForQuad(quad.MakeRaw("G", "status", "cool", "status_graph")) token := &Token{quadKind, key.StringID()} require.True(t, it.Contains(token), "Contains failed") // Test cloning an iterator var it2 graph.Iterator it2 = it.Clone() x := it2.Describe() y := it.Describe() require.Equal(t, y.Name, x.Name, "Iterator Clone was not successful") }
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, quad.Raw("Humphrey Bogart")) b := NewSQLLinkIterator(qs, quad.Predicate, quad.Raw("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, quad.Raw("/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, quad.Raw("/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 it8.Next() { 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) } } }
func TestBuildIntersect(t *testing.T) { a := NewSQLLinkIterator(nil, quad.Subject, quad.Raw("Foo")) b := NewSQLLinkIterator(nil, quad.Predicate, quad.Raw("is_equivalent_to")) it, err := intersect(a.sql, b.sql, nil) if err != nil { t.Error(err) } s, v := it.sql.buildSQL(true, nil) t.Log(s, v) }
func hasaWithTag(qs graph.QuadStore, tag string, target string) *HasA { and := NewAnd(qs) obj := qs.FixedIterator() obj.Add(qs.ValueOf(quad.Raw(target))) obj.Tagger().Add(tag) and.AddSubIterator(NewLinksTo(qs, obj, quad.Object)) pred := qs.FixedIterator() pred.Add(qs.ValueOf(quad.Raw("status"))) and.AddSubIterator(NewLinksTo(qs, pred, quad.Predicate)) return NewHasA(qs, and, quad.Subject) }
func TestBuildHasa(t *testing.T) { a := NewSQLLinkIterator(nil, quad.Subject, quad.Raw("Foo")) a.Tagger().Add("foo") b := NewSQLLinkIterator(nil, quad.Predicate, quad.Raw("is_equivalent_to")) it1, err := intersect(a.sql, b.sql, nil) if err != nil { t.Error(err) } it2, err := hasa(it1.sql, quad.Object, nil) if err != nil { t.Error(err) } s, v := it2.sql.buildSQL(true, nil) t.Log(s, v) }
func TestIteratorsAndNextResultOrderA(t *testing.T) { qs, _, _ := makeTestStore(simpleGraph) 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) if !outerAnd.Next() { t.Error("Expected one matching subtree") } val := outerAnd.Result() if qs.NameOf(val) != quad.Raw("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()).String()) 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 TestLinksToOptimization(t *testing.T) { qs, _, _ := makeTestStore(simpleGraph) fixed := qs.FixedIterator() fixed.Add(qs.ValueOf(quad.Raw("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") } }
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, quad.Raw("/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 it.Next() { t.Log(it.Result()) c += 1 } if c != 56 { t.Errorf("Not enough results, got %d expected 56", c) } }
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?") }
func (m *Quad) Upgrade() { if m.SubjectValue == nil { m.SubjectValue = MakeValue(quad.Raw(m.Subject)) m.Subject = "" } if m.PredicateValue == nil { m.PredicateValue = MakeValue(quad.Raw(m.Predicate)) m.Predicate = "" } if m.ObjectValue == nil { m.ObjectValue = MakeValue(quad.Raw(m.Object)) m.Object = "" } if m.LabelValue == nil && m.Label != "" { m.LabelValue = MakeValue(quad.Raw(m.Label)) m.Label = "" } }
func (qs *store) valueAt(i int) quad.Value { if !qs.parse { return quad.Raw(qs.data[i]) } iv, err := strconv.Atoi(qs.data[i]) if err == nil { return quad.Int(iv) } return quad.String(qs.data[i]) }
func TestTreeConstraintParse(t *testing.T) { qs, _ := graph.NewQuadStore("memstore", "", nil) w, _ := graph.NewQuadWriter("single", qs, nil) w.AddQuad(quad.MakeRaw("i", "like", "food", "")) w.AddQuad(quad.MakeRaw("food", "is", "good", "")) query := "(\"i\"\n" + "(:like\n" + "($a (:is :good))))" it := BuildIteratorTreeForQuery(qs, query) if it.Type() != graph.And { t.Errorf("Odd iterator tree. Got: %#v", it.Describe()) } if !it.Next() { t.Error("Got no results") } out := it.Result() if out != qs.ValueOf(quad.Raw("i")) { t.Errorf("Got %d, expected %d", out, qs.ValueOf(quad.Raw("i"))) } }
// GetNativeValue returns the value stored in Node. func (m *NodeData) GetNativeValue() quad.Value { if m == nil { return nil } else if m.Value == nil { if m.Name == "" { return nil } return quad.Raw(m.Name) } return m.Value.ToNative() }
func toQuadValue(v value) quad.Value { if v == nil { return nil } switch d := v.(type) { case string: return quad.Raw(d) // compatibility case int64: return quad.Int(d) case float64: return quad.Float(d) case bool: return quad.Bool(d) case time.Time: return quad.Time(d) case bson.M: // TODO(dennwc): use raw document instead? so, ok := d["val"] if !ok { clog.Errorf("Error: Empty value in map: %v", v) return nil } s := so.(string) if len(d) == 1 { return quad.String(s) } if o, ok := d["iri"]; ok && o.(bool) { return quad.IRI(s) } else if o, ok := d["bnode"]; ok && o.(bool) { return quad.BNode(s) } else if o, ok := d["lang"]; ok && o.(string) != "" { return quad.LangString{ Value: quad.String(s), Lang: o.(string), } } else if o, ok := d["type"]; ok && o.(string) != "" { return quad.TypedString{ Value: quad.String(s), Type: quad.IRI(o.(string)), } } return quad.String(s) case []byte: var p proto.Value if err := p.Unmarshal(d); err != nil { clog.Errorf("Error: Couldn't decode value: %v", err) return nil } return p.ToNative() default: panic(fmt.Errorf("unsupported type: %T", v)) } }
func TestHorizonInt(t testing.TB, gen DatabaseFunc, conf *Config) { qs, opts, closer := gen(t) defer closer() w := MakeWriter(t, qs, opts) horizon := qs.Horizon() require.Equal(t, int64(0), horizon.Int(), "Unexpected horizon value") err := w.AddQuadSet(MakeQuadSet()) require.Nil(t, err) require.Equal(t, int64(11), qs.Size(), "Unexpected quadstore size") if qss, ok := qs.(ValueSizer); ok { s := qss.SizeOf(qs.ValueOf(quad.Raw("B"))) require.Equal(t, int64(5), s, "Unexpected quadstore value size") } horizon = qs.Horizon() require.Equal(t, int64(11), horizon.Int(), "Unexpected horizon value") err = w.RemoveQuad(quad.MakeRaw( "A", "follows", "B", "", )) require.Nil(t, err) if !conf.SkipSizeCheckAfterDelete { require.Equal(t, int64(10), qs.Size(), "Unexpected quadstore size after RemoveQuad") } else { require.Equal(t, int64(11), qs.Size(), "Unexpected quadstore size") } if qss, ok := qs.(ValueSizer); ok { s := qss.SizeOf(qs.ValueOf(quad.Raw("B"))) require.Equal(t, int64(4), s, "Unexpected quadstore value size") } }
func (qs *store) NameOf(v graph.Value) quad.Value { switch v.(type) { case Int64Node: i := int(v.(Int64Node)) if i < 0 || i >= len(qs.data) { return nil } return qs.valueAt(i) case stringNode: if qs.parse { return quad.String(v.(stringNode)) } return quad.Raw(v.(stringNode)) default: return nil } }
func TestMemstore(t *testing.T) { qs, _, index := makeTestStore(simpleGraph) if size := qs.Size(); size != int64(len(simpleGraph)) { t.Errorf("Quad store has unexpected size, got:%d expected %d", size, len(simpleGraph)) } for _, test := range index { v := qs.ValueOf(quad.Raw(test.query)) switch v := v.(type) { default: t.Errorf("ValueOf(%q) returned unexpected type, got:%T expected int64", test.query, v) case iterator.Int64Node: if int64(v) != test.value { t.Errorf("ValueOf(%q) returned unexpected value, got:%d expected:%d", test.query, v, test.value) } } } }
func TestZeroRune(t *testing.T) { qs, opts, closer := makePostgres(t) defer closer() w := graphtest.MakeWriter(t, qs, opts) obj := quad.String("AB\u0000CD") if !utf8.ValidString(string(obj)) { t.Fatal("invalid utf8") } err := w.AddQuad(quad.Quad{ Subject: quad.IRI("bob"), Predicate: quad.IRI("pred"), Object: obj, }) require.Nil(t, err) require.Equal(t, obj, qs.NameOf(qs.ValueOf(quad.Raw(obj.String())))) }
func TestLoadOneQuad(t testing.TB, gen DatabaseFunc) { qs, opts, closer := gen(t) defer closer() w := MakeWriter(t, qs, opts) err := w.AddQuad(quad.MakeRaw( "Something", "points_to", "Something Else", "context", )) require.Nil(t, err) for _, pq := range []string{"Something", "points_to", "Something Else", "context"} { got := quad.StringOf(qs.NameOf(qs.ValueOf(quad.Raw(pq)))) require.Equal(t, pq, got, "Failed to roundtrip %q", pq) } require.Equal(t, int64(1), qs.Size(), "Unexpected quadstore size") }
func TestDeletedFromIterator(t testing.TB, gen DatabaseFunc) { qs, opts, closer := gen(t) defer closer() w := MakeWriter(t, qs, opts, MakeQuadSet()...) // Subject iterator. it := qs.QuadIterator(quad.Subject, qs.ValueOf(quad.Raw("E"))) ExpectIteratedQuads(t, qs, it, []quad.Quad{ quad.MakeRaw("E", "follows", "F", ""), }) it.Reset() w.RemoveQuad(quad.MakeRaw("E", "follows", "F", "")) ExpectIteratedQuads(t, qs, it, nil) }
// ToNative converts protobuf Value to quad.Value. func (m *Value) ToNative() (qv quad.Value) { if m == nil { return nil } switch v := m.Value.(type) { case *Value_Raw: return quad.Raw(v.Raw) case *Value_Str: return quad.String(v.Str) case *Value_Iri: return quad.IRI(v.Iri) case *Value_Bnode: return quad.BNode(v.Bnode) case *Value_TypedStr: return quad.TypedString{ Value: quad.String(v.TypedStr.Value), Type: quad.IRI(v.TypedStr.Type), } case *Value_LangStr: return quad.LangString{ Value: quad.String(v.LangStr.Value), Lang: v.LangStr.Lang, } case *Value_Int: return quad.Int(v.Int) case *Value_Float_: return quad.Float(v.Float_) case *Value_Boolean: return quad.Bool(v.Boolean) case *Value_Time: var t time.Time if v.Time == nil { t = time.Unix(0, 0).UTC() } else { t = time.Unix(v.Time.Seconds, int64(v.Time.Nanos)).UTC() } return quad.Time(t) default: panic(fmt.Errorf("unsupported type: %T", m.Value)) } }
func TestLinksTo(t *testing.T) { qs := &store{ data: []string{1: "cool"}, iter: NewFixed(Identity), } qs.iter.(*Fixed).Add(Int64Quad(2)) fixed := NewFixed(Identity) val := qs.ValueOf(quad.Raw("cool")) if val.(Int64Node) != 1 { t.Fatalf("Failed to return correct value, got:%v expect:1", val) } fixed.Add(val) lto := NewLinksTo(qs, fixed, quad.Object) if !lto.Next() { t.Error("At least one quad matches the fixed object") } val = lto.Result() if val.(Int64Quad) != 2 { t.Errorf("Quad index 2, such as %s, should match %s", qs.Quad(Int64Quad(2)), qs.Quad(val)) } }
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") } 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) } }
func TestMemstoreBackedSexp(t *testing.T) { qs, _ := graph.NewQuadStore("memstore", "", nil) w, _ := graph.NewQuadWriter("single", qs, nil) emptyIt := BuildIteratorTreeForQuery(qs, "()") if emptyIt.Type() != graph.Null { t.Errorf(`Incorrect type for empty query, got:%q expect: "null"`, emptyIt.Type()) } for _, test := range testQueries { if test.add.IsValid() { w.AddQuad(test.add) } it := BuildIteratorTreeForQuery(qs, test.query) if it.Type() != test.typ { t.Errorf("Incorrect type for %s, got:%q expect %q", test.message, it.Type(), test.expect) } if !it.Next() { t.Errorf("Failed to %s", test.message) } got := it.Result() if expect := qs.ValueOf(quad.Raw(test.expect)); got != expect { t.Errorf("Incorrect result for %s, got:%v expect %v", test.message, got, expect) } } }
func TestQueryShape(t *testing.T) { qs := &store{ data: []string{ 1: "cool", 2: "status", 3: "fun", 4: "name", }, } // Given a single linkage iterator's shape. hasa := hasaWithTag(qs, "tag", "cool") hasa.Tagger().Add("top") shape := make(map[string]interface{}) OutputQueryShapeForIterator(hasa, qs, shape) nodes := shape["nodes"].([]Node) if len(nodes) != 3 { t.Errorf("Failed to get correct number of nodes, got:%d expect:4", len(nodes)) } links := shape["links"].([]Link) if len(nodes) != 3 { t.Errorf("Failed to get correct number of links, got:%d expect:1", len(links)) } // Nodes should be correctly tagged. nodes = shape["nodes"].([]Node) for i, expect := range [][]string{{"tag"}, nil, {"top"}} { if !reflect.DeepEqual(nodes[i].Tags, expect) { t.Errorf("Failed to get correct tag for node[%d], got:%s expect:%s", i, nodes[i].Tags, expect) } } if !nodes[1].IsLinkNode { t.Error("Failed to get node[1] as link node") } // Link should be correctly typed. nodes = shape["nodes"].([]Node) link := shape["links"].([]Link)[0] if link.Source != nodes[2].ID { t.Errorf("Failed to get correct link source, got:%v expect:%v", link.Source, nodes[2].ID) } if link.Target != nodes[0].ID { t.Errorf("Failed to get correct link target, got:%v expect:%v", link.Target, nodes[0].ID) } if link.LinkNode != nodes[1].ID { t.Errorf("Failed to get correct link node, got:%v expect:%v", link.LinkNode, nodes[1].ID) } if link.Pred != 0 { t.Errorf("Failed to get correct number of predecessors:%v expect:0", link.Pred) } // Given a name-of-an-and-iterator's shape. andInternal := NewAnd(qs) hasa1 := hasaWithTag(qs, "tag1", "cool") hasa1.Tagger().Add("hasa1") andInternal.AddSubIterator(hasa1) hasa2 := hasaWithTag(qs, "tag2", "fun") hasa2.Tagger().Add("hasa2") andInternal.AddSubIterator(hasa2) pred := qs.FixedIterator() pred.Add(qs.ValueOf(quad.Raw("name"))) and := NewAnd(qs) and.AddSubIterator(NewLinksTo(qs, andInternal, quad.Subject)) and.AddSubIterator(NewLinksTo(qs, pred, quad.Predicate)) shape = make(map[string]interface{}) OutputQueryShapeForIterator(NewHasA(qs, and, quad.Object), qs, shape) links = shape["links"].([]Link) if len(links) != 3 { t.Errorf("Failed to find the correct number of links, got:%d expect:3", len(links)) } nodes = shape["nodes"].([]Node) if len(nodes) != 7 { t.Errorf("Failed to find the correct number of nodes, got:%d expect:7", len(nodes)) } var n int for _, node := range nodes { if node.IsLinkNode { n++ } } if n != 3 { t.Errorf("Failed to find the correct number of link nodes, got:%d expect:3", n) } }
) var testNQuads = []struct { message string input string expect quad.Quad err error }{ // Tests from original nquads. // NTriple tests. { message: "parse simple triples", input: "this is valid .", expect: quad.Quad{ Subject: quad.Raw("this"), Predicate: quad.Raw("is"), Object: quad.Raw("valid"), Label: nil, }, }, { message: "parse quoted triples", input: `this is "valid too" .`, expect: quad.Quad{ Subject: quad.Raw("this"), Predicate: quad.Raw("is"), Object: quad.String("valid too"), Label: nil, }, },