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 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())))) }
// 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 TestCompareTypedValues(t testing.TB, gen DatabaseFunc, conf *Config) { qs, opts, closer := gen(t) defer closer() w := MakeWriter(t, qs, opts) t1 := tzero t2 := t1.Add(time.Hour) t3 := t2.Add(time.Hour * 48) t4 := t1.Add(time.Hour * 24 * 365) err := w.AddQuadSet([]quad.Quad{ {quad.BNode("alice"), quad.BNode("bob"), quad.BNode("charlie"), quad.BNode("dani")}, {quad.IRI("alice"), quad.IRI("bob"), quad.IRI("charlie"), quad.IRI("dani")}, {quad.String("alice"), quad.String("bob"), quad.String("charlie"), quad.String("dani")}, {quad.Int(100), quad.Int(112), quad.Int(110), quad.Int(20)}, {quad.Time(t1), quad.Time(t2), quad.Time(t3), quad.Time(t4)}, }) require.Nil(t, err) for _, c := range casesCompare { it := iterator.NewComparison(qs.NodesAllIterator(), c.op, c.val, qs) ExpectIteratedValues(t, qs, it, c.expect) } for _, c := range casesCompare { it := iterator.NewComparison(qs.NodesAllIterator(), c.op, c.val, qs) nit, ok := qs.OptimizeIterator(it) require.Equal(t, conf.OptimizesComparison, ok) if conf.OptimizesComparison { require.NotEqual(t, it, nit) } else { require.Equal(t, it, nit) } ExpectIteratedValues(t, qs, nit, c.expect) } }
message: "parse crazy escaped quads", input: `"\"this" "\"is" "\"valid" "\"quad thing".`, expect: quad.Quad{ Subject: quad.String(`"this`), Predicate: quad.String(`"is`), Object: quad.String(`"valid`), Label: quad.String(`"quad thing`), }, }, // NTriple official tests. { message: "handle simple case with comments", input: "<http://example/s> <http://example/p> <http://example/o> . # comment", expect: quad.Quad{ Subject: quad.IRI("http://example/s"), Predicate: quad.IRI("http://example/p"), Object: quad.IRI("http://example/o"), Label: nil, }, }, { message: "handle simple case with comments", input: "<http://example/s> <http://example/p> _:o . # comment", expect: quad.Quad{ Subject: quad.IRI("http://example/s"), Predicate: quad.IRI("http://example/p"), Object: quad.BNode("o"), Label: nil, }, },
func (qs *QuadStore) NameOf(v graph.Value) quad.Value { if v == nil { if clog.V(2) { clog.Infof("NameOf was nil") } return nil } hash := v.(NodeHash) if !hash.Valid() { if clog.V(2) { clog.Infof("NameOf was nil") } return nil } if val, ok := qs.ids.Get(hash.String()); ok { return val.(quad.Value) } query := `SELECT value, value_string, datatype, language, iri, bnode, value_int, value_bool, value_float, value_time FROM nodes WHERE hash = $1 LIMIT 1;` c := qs.db.QueryRow(query, hash.toSQL()) var ( data []byte str sql.NullString typ sql.NullString lang sql.NullString iri sql.NullBool bnode sql.NullBool vint sql.NullInt64 vbool sql.NullBool vfloat sql.NullFloat64 vtime pq.NullTime ) if err := c.Scan( &data, &str, &typ, &lang, &iri, &bnode, &vint, &vbool, &vfloat, &vtime, ); err != nil { clog.Errorf("Couldn't execute value lookup: %v", err) return nil } var val quad.Value if str.Valid { if iri.Bool { val = quad.IRI(str.String) } else if bnode.Bool { val = quad.BNode(str.String) } else if lang.Valid { val = quad.LangString{ Value: quad.String(unescapeNullByte(str.String)), Lang: lang.String, } } else if typ.Valid { val = quad.TypedString{ Value: quad.String(unescapeNullByte(str.String)), Type: quad.IRI(typ.String), } } else { val = quad.String(unescapeNullByte(str.String)) } } else if vint.Valid { val = quad.Int(vint.Int64) } else if vbool.Valid { val = quad.Bool(vbool.Bool) } else if vfloat.Valid { val = quad.Float(vfloat.Float64) } else if vtime.Valid { val = quad.Time(vtime.Time) } else { qv, err := proto.UnmarshalValue(data) if err != nil { clog.Errorf("Couldn't unmarshal value: %v", err) return nil } val = qv } if val != nil { qs.ids.Put(hash.String(), val) } return val }
// predicateToValue converts a Predicate to a Cayley value. func predicateToValue(predicate Predicate) quad.Value { return quad.IRI(string(predicate)) }
func unEscape(r []rune, spec int, isQuoted, isEscaped bool) quad.Value { raw := r var sp []rune if spec > 0 { r, sp = r[:spec], r[spec:] isQuoted = true } if isQuoted { r = r[1 : len(r)-1] } else { if len(r) >= 2 && r[0] == '<' && r[len(r)-1] == '>' { return quad.IRI(r[1 : len(r)-1]) } if len(r) >= 2 && r[0] == '_' && r[1] == ':' { return quad.BNode(string(r[2:])) } } var val string if isEscaped { buf := bytes.NewBuffer(make([]byte, 0, len(r))) for i := 0; i < len(r); { switch r[i] { case '\\': i++ var c byte switch r[i] { case 't': c = '\t' case 'b': c = '\b' case 'n': c = '\n' case 'r': c = '\r' case 'f': c = '\f' case '"': c = '"' case '\'': c = '\'' case '\\': c = '\\' case 'u': rc, err := strconv.ParseInt(string(r[i+1:i+5]), 16, 32) if err != nil { panic(fmt.Errorf("internal parser error: %v", err)) } buf.WriteRune(rune(rc)) i += 5 continue case 'U': rc, err := strconv.ParseInt(string(r[i+1:i+9]), 16, 32) if err != nil { panic(fmt.Errorf("internal parser error: %v", err)) } buf.WriteRune(rune(rc)) i += 9 continue } buf.WriteByte(c) default: buf.WriteRune(r[i]) } i++ } val = buf.String() } else { val = string(r) } if len(sp) == 0 { if isQuoted { return quad.String(val) } return quad.Raw(val) } if sp[0] == '@' { return quad.LangString{ Value: quad.String(val), Lang: string(sp[1:]), } } else if len(sp) >= 4 && sp[0] == '^' && sp[1] == '^' && sp[2] == '<' && sp[len(sp)-1] == '>' { v := quad.TypedString{ Value: quad.String(val), Type: quad.IRI(sp[3 : len(sp)-1]), } if AutoConvertTypedString { nv, err := v.ParseValue() if err == nil { return nv } } return v } return quad.Raw(raw) }
func testSet(qs graph.QuadStore) []test { return []test{ { message: "use out", path: StartPath(qs, vAlice).Out(vFollows), expect: []quad.Value{vBob}, }, { message: "use out (raw)", path: StartPath(qs, quad.Raw(vAlice.String())).Out(quad.Raw(vFollows.String())), expect: []quad.Value{vBob}, }, { message: "use in", path: StartPath(qs, vBob).In(vFollows), expect: []quad.Value{vAlice, vCharlie, vDani}, }, { message: "use in with filter", path: StartPath(qs, vBob).In(vFollows).Filter(iterator.CompareGT, quad.IRI("c")), expect: []quad.Value{vCharlie, vDani}, }, { message: "use path Out", path: StartPath(qs, vBob).Out(StartPath(qs, vPredicate).Out(vAre)), expect: []quad.Value{vFred, vCool}, }, { message: "use path Out (raw)", path: StartPath(qs, quad.Raw(vBob.String())).Out(StartPath(qs, quad.Raw(vPredicate.String())).Out(quad.Raw(vAre.String()))), expect: []quad.Value{vFred, vCool}, }, { message: "use And", path: StartPath(qs, vDani).Out(vFollows).And( StartPath(qs, vCharlie).Out(vFollows)), expect: []quad.Value{vBob}, }, { message: "use Or", path: StartPath(qs, vFred).Out(vFollows).Or( StartPath(qs, vAlice).Out(vFollows)), expect: []quad.Value{vBob, vGreg}, }, { message: "implicit All", path: StartPath(qs), expect: []quad.Value{vAlice, vBob, vCharlie, vDani, vEmily, vFred, vGreg, vFollows, vStatus, vCool, vPredicate, vAre, vSmartGraph, vSmart}, }, { message: "follow", path: StartPath(qs, vCharlie).Follow(StartMorphism().Out(vFollows).Out(vFollows)), expect: []quad.Value{vBob, vFred, vGreg}, }, { message: "followR", path: StartPath(qs, vFred).FollowReverse(StartMorphism().Out(vFollows).Out(vFollows)), expect: []quad.Value{vAlice, vCharlie, vDani}, }, { message: "is, tag, instead of FollowR", path: StartPath(qs).Tag("first").Follow(StartMorphism().Out(vFollows).Out(vFollows)).Is(vFred), expect: []quad.Value{vAlice, vCharlie, vDani}, tag: "first", }, { message: "use Except to filter out a single vertex", path: StartPath(qs, vAlice, vBob).Except(StartPath(qs, vAlice)), expect: []quad.Value{vBob}, }, { message: "use chained Except", path: StartPath(qs, vAlice, vBob, vCharlie).Except(StartPath(qs, vBob)).Except(StartPath(qs, vAlice)), expect: []quad.Value{vCharlie}, }, { message: "show a simple save", path: StartPath(qs).Save(vStatus, "somecool"), tag: "somecool", expect: []quad.Value{vCool, vCool, vCool, vSmart, vSmart}, }, { message: "show a simple saveR", path: StartPath(qs, vCool).SaveReverse(vStatus, "who"), tag: "who", expect: []quad.Value{vGreg, vDani, vBob}, }, { message: "show a simple Has", path: StartPath(qs).Has(vStatus, vCool), expect: []quad.Value{vGreg, vDani, vBob}, }, { message: "use Limit", path: StartPath(qs).Has(vStatus, vCool).Limit(2), expect: []quad.Value{vBob, vDani}, }, { message: "use Skip", path: StartPath(qs).Has(vStatus, vCool).Skip(2), expect: []quad.Value{vGreg}, }, { message: "use Skip and Limit", path: StartPath(qs).Has(vStatus, vCool).Skip(1).Limit(1), expect: []quad.Value{vDani}, }, { message: "show a double Has", path: StartPath(qs).Has(vStatus, vCool).Has(vFollows, vFred), expect: []quad.Value{vBob}, }, { message: "show a simple HasReverse", path: StartPath(qs).HasReverse(vStatus, vBob), expect: []quad.Value{vCool}, }, { message: "use .Tag()-.Is()-.Back()", path: StartPath(qs, vBob).In(vFollows).Tag("foo").Out(vStatus).Is(vCool).Back("foo"), expect: []quad.Value{vDani}, }, { message: "do multiple .Back()s", path: StartPath(qs, vEmily).Out(vFollows).Tag("f").Out(vFollows).Out(vStatus).Is(vCool).Back("f").In(vFollows).In(vFollows).Tag("acd").Out(vStatus).Is(vCool).Back("f"), tag: "acd", expect: []quad.Value{vDani}, }, { message: "InPredicates()", path: StartPath(qs, vBob).InPredicates(), expect: []quad.Value{vFollows}, }, { message: "OutPredicates()", path: StartPath(qs, vBob).OutPredicates(), expect: []quad.Value{vFollows, vStatus}, }, // Morphism tests { message: "show simple morphism", path: StartPath(qs, vCharlie).Follow(grandfollows), expect: []quad.Value{vGreg, vFred, vBob}, }, { message: "show reverse morphism", path: StartPath(qs, vFred).FollowReverse(grandfollows), expect: []quad.Value{vAlice, vCharlie, vDani}, }, // Context tests { message: "query without label limitation", path: StartPath(qs, vGreg).Out(vStatus), expect: []quad.Value{vSmart, vCool}, }, { message: "query with label limitation", path: StartPath(qs, vGreg).LabelContext(vSmartGraph).Out(vStatus), expect: []quad.Value{vSmart}, }, { message: "reverse context", path: StartPath(qs, vGreg).Tag("base").LabelContext(vSmartGraph).Out(vStatus).Tag("status").Back("base"), expect: []quad.Value{vGreg}, }, // Optional tests { message: "save limits top level", path: StartPath(qs, vBob, vCharlie).Out(vFollows).Save(vStatus, "statustag"), expect: []quad.Value{vBob, vDani}, }, { message: "optional still returns top level", path: StartPath(qs, vBob, vCharlie).Out(vFollows).SaveOptional(vStatus, "statustag"), expect: []quad.Value{vBob, vFred, vDani}, }, { message: "optional has the appropriate tags", path: StartPath(qs, vBob, vCharlie).Out(vFollows).SaveOptional(vStatus, "statustag"), tag: "statustag", expect: []quad.Value{vCool, vCool}, }, } }
} }) return out } type test struct { message string path *Path expect []quad.Value tag string } // Define morphisms without a QuadStore const ( vFollows = quad.IRI("follows") vAre = quad.IRI("are") vStatus = quad.IRI("status") vPredicate = quad.IRI("predicates") vCool = quad.String("cool_person") vSmart = quad.String("smart_person") vSmartGraph = quad.IRI("smart_graph") vAlice = quad.IRI("alice") vBob = quad.IRI("bob") vCharlie = quad.IRI("charlie") vDani = quad.IRI("dani") vFred = quad.IRI("fred") vGreg = quad.IRI("greg") vEmily = quad.IRI("emily")
func TestLoadTypedQuads(t testing.TB, gen DatabaseFunc, conf *Config) { qs, opts, closer := gen(t) defer closer() w := MakeWriter(t, qs, opts) values := []quad.Value{ quad.BNode("A"), quad.IRI("name"), quad.String("B"), quad.IRI("graph"), quad.IRI("B"), quad.Raw("<type>"), quad.TypedString{Value: "10", Type: "int"}, quad.LangString{Value: "value", Lang: "en"}, quad.Int(-123456789), quad.Float(-12345e-6), quad.Bool(true), quad.Time(time.Now()), } err := w.AddQuadSet([]quad.Quad{ {values[0], values[1], values[2], values[3]}, {values[4], values[5], values[6], nil}, {values[4], values[5], values[7], nil}, {values[0], values[1], values[8], nil}, {values[0], values[1], values[9], nil}, {values[0], values[1], values[10], nil}, {values[0], values[1], values[11], nil}, }) require.Nil(t, err) for _, pq := range values { got := qs.NameOf(qs.ValueOf(pq)) if !conf.UnTyped { if pt, ok := pq.(quad.Time); ok { var trim int64 if conf.TimeInMcs { trim = 1000 } else if conf.TimeInMs { trim = 1000000 } if trim > 0 { tm := time.Time(pt) seconds := tm.Unix() nanos := int64(tm.Sub(time.Unix(seconds, 0))) if conf.TimeRound { nanos = (nanos/trim + ((nanos/(trim/10))%10)/5) * trim } else { nanos = (nanos / trim) * trim } pq = quad.Time(time.Unix(seconds, nanos).UTC()) } } if eq, ok := pq.(quad.Equaler); ok { assert.True(t, eq.Equal(got), "Failed to roundtrip %q (%T), got %q (%T)", pq, pq, got, got) } else { assert.Equal(t, pq, got, "Failed to roundtrip %q (%T)", pq, pq) if !conf.NoHashes { assert.Equal(t, pq, qs.NameOf(qs.ValueOf(quad.Raw(pq.String()))), "Failed to exchange raw value %q (%T)", pq, pq) } } } else { assert.Equal(t, quad.StringOf(pq), quad.StringOf(got), "Failed to roundtrip raw %q (%T)", pq, pq) } } require.Equal(t, int64(7), qs.Size(), "Unexpected quadstore size") }
{lt, quad.BNode("b"), []quad.Value{ quad.BNode("alice"), }}, {lte, quad.BNode("bob"), []quad.Value{ quad.BNode("alice"), quad.BNode("bob"), }}, {lt, quad.String("b"), []quad.Value{ quad.String("alice"), }}, {lte, quad.String("bob"), []quad.Value{ quad.String("alice"), quad.String("bob"), }}, {gte, quad.String("b"), []quad.Value{ quad.String("bob"), quad.String("charlie"), quad.String("dani"), }}, {lt, quad.IRI("b"), []quad.Value{ quad.IRI("alice"), }}, {lte, quad.IRI("bob"), []quad.Value{ quad.IRI("alice"), quad.IRI("bob"), }}, {lte, quad.IRI("bob"), []quad.Value{ quad.IRI("alice"), quad.IRI("bob"), }}, {gte, quad.Int(111), []quad.Value{ quad.Int(112), }}, {gte, quad.Int(110), []quad.Value{ quad.Int(110), quad.Int(112), }}, {lt, quad.Int(20), nil},
} qv, ok := toQuadValue(args[0]) if !ok { return otto.NullValue() } return outObj(call, cmpOperator{op: op, val: qv}) } } type cmpOperator struct { op iterator.Operator val quad.Value } var defaultEnv = map[string]func(call otto.FunctionCall) otto.Value{ "iri": oneStringType(func(s string) quad.Value { return quad.IRI(s) }), "bnode": oneStringType(func(s string) quad.Value { return quad.BNode(s) }), "raw": oneStringType(func(s string) quad.Value { return quad.Raw(s) }), "str": oneStringType(func(s string) quad.Value { return quad.String(s) }), "lang": twoStringType(func(s, lang string) quad.Value { return quad.LangString{Value: quad.String(s), Lang: lang} }), "typed": twoStringType(func(s, typ string) quad.Value { return quad.TypedString{Value: quad.String(s), Type: quad.IRI(typ)} }), "lt": cmpOpType(iterator.CompareLT), "lte": cmpOpType(iterator.CompareLTE), "gt": cmpOpType(iterator.CompareGT), "gte": cmpOpType(iterator.CompareGTE),