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 { glog.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 { glog.Errorf("Error: Couldn't decode value: %v", err) return nil } return p.ToNative() default: panic(fmt.Errorf("unsupported type: %T", v)) } }
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]) }
// 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) } }
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 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 toQuadValue(t gojsonld.Term) quad.Value { if t == nil { return nil } switch v := t.(type) { case *gojsonld.Resource: return quad.IRI(v.URI) case *gojsonld.Literal: val := quad.String(v.Value) if v.Language != "" { return quad.LangString{Value: val, Lang: v.Language} } else if v.Datatype != nil { return quad.TypedString{Value: val, Type: toQuadValue(v.Datatype).(quad.IRI)} } return val case *gojsonld.BlankNode: return quad.BNode(v.ID) default: panic(fmt.Errorf("unknown term type: %T", t)) } }
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.ToNative() if err == nil { return nv } } return v } return quad.Raw(raw) }
func (qs *QuadStore) NameOf(v graph.Value) quad.Value { if v == nil { glog.V(2).Info("NameOf was nil") return nil } hash := v.(NodeHash) if !hash.Valid() { glog.V(2).Info("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 { glog.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 { glog.Errorf("Couldn't unmarshal value: %v", err) return nil } val = qv } if val != nil { qs.ids.Put(hash.String(), val) } return val }
package pquads_test import ( "bytes" "github.com/google/cayley/quad" "github.com/google/cayley/quad/pquads" "io" "reflect" "testing" ) var testData = []quad.Quad{ {quad.BNode("one"), quad.IRI("name"), quad.String("One"), quad.IRI("graph")}, {quad.BNode("one"), quad.IRI("rank"), quad.Int(101), nil}, {quad.BNode("one"), quad.IRI("val"), quad.TypedString{Value: "123", Type: "int"}, nil}, } func TestPQuads(t *testing.T) { buf := bytes.NewBuffer(nil) w := pquads.NewWriter(buf) for _, q := range testData { if err := w.WriteQuad(q); err != nil { t.Fatal(err) } } var got []quad.Quad r := pquads.NewReader(buf) for { q, err := r.ReadQuad() if err == io.EOF { break
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), } func newWorker(qs graph.QuadStore) *worker {
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, }, }, { message: "parse escaped quoted triples", input: `he said "\"That's all folks\"" .`, expect: quad.Quad{ Subject: quad.Raw("he"), Predicate: quad.Raw("said"), Object: quad.String(`"That's all folks"`), Label: nil, }, }, { message: "parse an example real triple",
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") ) var ( grandfollows = StartMorphism().Out(vFollows).Out(vFollows) )
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") }
const lt, lte, gt, gte = iterator.CompareLT, iterator.CompareLTE, iterator.CompareGT, iterator.CompareGTE var tzero = time.Unix(time.Now().Unix(), 0) var casesCompare = []struct { op iterator.Operator val quad.Value expect []quad.Value }{ {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{
operator: CompareGTE, expect: []quad.Value{quad.Int(2), quad.Int(3), quad.Int(4)}, qs: simpleStore, iterator: simpleFixedIterator, }, { message: "successful int64 greater than or equal comparison (mixed)", operand: quad.Int(2), operator: CompareGTE, expect: []quad.Value{quad.Int(2), quad.Int(3), quad.Int(4), quad.Int(5)}, qs: mixedStore, iterator: mixedFixedIterator, }, { message: "successful string less than comparison", operand: quad.String("echo"), operator: CompareLT, expect: []quad.Value{quad.String("bar"), quad.String("baz")}, qs: stringStore, iterator: stringFixedIterator, }, { message: "empty string less than comparison", operand: quad.String(""), operator: CompareLT, expect: nil, qs: stringStore, iterator: stringFixedIterator, }, { message: "successful string greater than comparison",