Skip to content
Snippets Groups Projects
Unverified Commit c3f44526 authored by Ashish Negi's avatar Ashish Negi
Browse files

Facet values in strings should be in quotes.

tests: Spaces inside quotes in string values. Backup tests for facet string quotes.
parent 7726b940
Branches
No related tags found
No related merge requests found
......@@ -49,14 +49,14 @@ func populateGraphWithFacets(t *testing.T) {
addEdgeToUID(t, "friend", 23, 1, friendFacets1)
friendFacets5 := map[string]string{
"games": "football basketball chess tennis", "close": "false", "age": "35"}
"games": `"football basketball chess tennis"`, "close": "false", "age": "35"}
friendFacets6 := map[string]string{
"games": "football basketball hockey", "close": "false"}
"games": `"football basketball hockey"`, "close": "false"}
addEdgeToUID(t, "friend", 31, 1, friendFacets5)
addEdgeToUID(t, "friend", 31, 25, friendFacets6)
nameFacets := map[string]string{"origin": "french"}
nameFacets := map[string]string{"origin": `"french"`}
// Now let's add a few properties for the main user.
addEdgeToValue(t, "name", 1, "Michonne", nameFacets)
addEdgeToValue(t, "gender", 1, "female", nil)
......@@ -257,7 +257,7 @@ func TestFacetsMutation(t *testing.T) {
populateGraphWithFacets(t)
defer teardownGraphWithFacets(t)
delEdgeToUID(t, "friend", 1, 24) // Delete friendship between Michonne and Glenn
friendFacets := map[string]string{"since": "11-10-2001", "close": "false", "family": "false"}
friendFacets := map[string]string{"since": "2001-11-10", "close": "false", "family": "false"}
addEdgeToUID(t, "friend", 1, 101, friendFacets) // and 101 is not close friend now.
query := `
{
......@@ -272,7 +272,7 @@ func TestFacetsMutation(t *testing.T) {
js := processToFastJSON(t, query)
require.JSONEq(t,
`{"me":[{"friend":[{"@facets":{"_":{"since":"2006-01-02T15:04:05Z"}},"name":"Rick Grimes"},{"@facets":{"_":{"close":false,"family":true,"since":"2007-05-02T15:04:05Z"}},"name":"Daryl Dixon"},{"@facets":{"_":{"since":"2006-01-02T15:04:05Z"}},"name":"Andrea"},{"@facets":{"_":{"close":false,"family":false,"since":"11-10-2001"}}}],"name":"Michonne"}]}`,
`{"me":[{"friend":[{"@facets":{"_":{"since":"2006-01-02T15:04:05Z"}},"name":"Rick Grimes"},{"@facets":{"_":{"close":false,"family":true,"since":"2007-05-02T15:04:05Z"}},"name":"Daryl Dixon"},{"@facets":{"_":{"since":"2006-01-02T15:04:05Z"}},"name":"Andrea"},{"@facets":{"_":{"close":false,"family":false,"since":"2001-11-10T00:00:00Z"}}}],"name":"Michonne"}]}`,
js)
}
......@@ -897,7 +897,7 @@ func TestFacetsFilterAtValueFail(t *testing.T) {
{
me(id:1) {
friend {
name @facets(eq(origin, french))
name @facets(eq(origin, "french"))
}
}
}
......
......@@ -520,7 +520,7 @@ var testNQuads = []struct {
// Edge Facets test.
{
input: `_:alice <knows> "stuff" _:label (key1=val1,key2=13) .`,
input: `_:alice <knows> "stuff" _:label (key1="val1",key2=13) .`,
nq: graphp.NQuad{
Subject: "_:alice",
Predicate: "knows",
......@@ -590,7 +590,7 @@ var testNQuads = []struct {
},
// Should not fail parsing with unnecessary spaces
{
input: `_:alice <knows> "stuff" ( key1 = 12 , key2=value2, key3=, key4 =val4 ) .`,
input: `_:alice <knows> "stuff" ( key1 = 12 , key2="value2", key3=, key4 ="val4" ) .`,
nq: graphp.NQuad{
Subject: "_:alice",
Predicate: "knows",
......@@ -619,7 +619,7 @@ var testNQuads = []struct {
},
// Should parse all types
{
input: `_:alice <knows> "stuff" (key1=12,key2=value2,key3=1.2,key4=2006-01-02T15:04:05,key5=true,key6=false) .`,
input: `_:alice <knows> "stuff" (key1=12,key2="value2",key3=1.2,key4=2006-01-02T15:04:05,key5=true,key6=false) .`,
nq: graphp.NQuad{
Subject: "_:alice",
Predicate: "knows",
......@@ -649,10 +649,9 @@ var testNQuads = []struct {
},
expectedErr: false,
},
// Should parse bools for only "true" and "false"
// Should parse dates
{
// True, 1 , t are some valid true values in go strconv.ParseBool
input: `_:alice <knows> "stuff" (key1=true,key2=false,key3=True,key4=False,key5=1, key6=t) .`,
input: `_:alice <knows> "stuff" (key1=2002-10-02T15:00:00.05Z, key2=2006-01-02T15:04:05, key3=2006-01-02) .`,
nq: graphp.NQuad{
Subject: "_:alice",
Predicate: "knows",
......@@ -660,32 +659,21 @@ var testNQuads = []struct {
ObjectValue: &graphp.Value{&graphp.Value_DefaultVal{"stuff"}},
ObjectType: 0,
Facets: []*facetsp.Facet{
{"key1", []byte("\001"),
facets.ValTypeForTypeID(facets.BoolID),
{"key1", []byte("\001\000\000\000\016\265-\000\360\002\372\360\200\377\377"),
facets.ValTypeForTypeID(facets.DateTimeID),
nil},
{"key2", []byte("\000"),
facets.ValTypeForTypeID(facets.BoolID),
{"key2", []byte("\001\000\000\000\016\273K7\345\000\000\000\000\377\377"),
facets.ValTypeForTypeID(facets.DateTimeID),
nil},
{"key3", []byte("True"),
facets.ValTypeForTypeID(facets.StringID),
[]string{"\001true"}},
{"key4", []byte("False"),
facets.ValTypeForTypeID(facets.StringID),
[]string{"\001false"}},
{"key5", []byte("\001\000\000\000\000\000\000\000"),
facets.ValTypeForTypeID(facets.IntID),
{"key3", []byte("\001\000\000\000\016\273Jd\000\000\000\000\000\377\377"),
facets.ValTypeForTypeID(facets.DateTimeID),
nil},
{"key6", []byte("t"),
facets.ValTypeForTypeID(facets.StringID),
[]string{"\001t"}},
},
},
expectedErr: false,
},
// Should parse to string even if value start with ints if it has alphabets.
// Only support decimal format for ints.
{
input: `_:alice <knows> "stuff" (key1=11adsf234,key2=11111111111111111111132333uasfk333) .`,
// integer can be in any valid format.
input: `_:alice <knows> "stuff" (k=0x0D) .`,
nq: graphp.NQuad{
Subject: "_:alice",
Predicate: "knows",
......@@ -693,19 +681,15 @@ var testNQuads = []struct {
ObjectValue: &graphp.Value{&graphp.Value_DefaultVal{"stuff"}},
ObjectType: 0,
Facets: []*facetsp.Facet{
{"key1", []byte("11adsf234"),
facets.ValTypeForTypeID(facets.StringID),
[]string{"\00111adsf234"}},
{"key2", []byte("11111111111111111111132333uasfk333"),
facets.ValTypeForTypeID(facets.StringID),
[]string{"\00111111111111111111111132333uasfk333"}},
{"k", []byte("\r\000\000\000\000\000\000\000"),
facets.ValTypeForTypeID(facets.IntID),
nil},
},
},
},
// Should parse dates
{
input: `_:alice <knows> "stuff" (key1=2002-10-02T15:00:00.05Z, key2=2006-01-02T15:04:05, key3=2006-01-02) .`,
// That what can not fit in integer fits in float.
input: `_:alice <knows> "stuff" (k=111111111111111111888888.23) .`,
nq: graphp.NQuad{
Subject: "_:alice",
Predicate: "knows",
......@@ -713,45 +697,56 @@ var testNQuads = []struct {
ObjectValue: &graphp.Value{&graphp.Value_DefaultVal{"stuff"}},
ObjectType: 0,
Facets: []*facetsp.Facet{
{"key1", []byte("\001\000\000\000\016\265-\000\360\002\372\360\200\377\377"),
facets.ValTypeForTypeID(facets.DateTimeID),
nil},
{"key2", []byte("\001\000\000\000\016\273K7\345\000\000\000\000\377\377"),
facets.ValTypeForTypeID(facets.DateTimeID),
nil},
{"key3", []byte("\001\000\000\000\016\273Jd\000\000\000\000\000\377\377"),
facets.ValTypeForTypeID(facets.DateTimeID),
{"k", []byte("\240\250OlX\207\267D"),
facets.ValTypeForTypeID(facets.FloatID),
nil},
},
},
},
{
// Quotes inside facet string values.
input: `_:alice <knows> "stuff" (key1="\"hello world\"") .`,
nq: graphp.NQuad{
Subject: "_:alice",
Predicate: "knows",
ObjectId: "",
ObjectValue: &graphp.Value{&graphp.Value_DefaultVal{"stuff"}},
ObjectType: 0,
Facets: []*facetsp.Facet{
{"key1", []byte(`\"hello world\"`),
facets.ValTypeForTypeID(facets.StringID),
[]string{"\001hello", "\001world"},
},
},
},
},
// failing tests for facets
{
input: `_:alice <knows> "stuff" (key1=val1,key2) .`,
input: `_:alice <knows> "stuff" (key1="val1",key2) .`,
expectedErr: true, // should fail because of no '=' after key2
},
{
input: `_:alice <knows> "stuff" (key1=val1,=) .`,
input: `_:alice <knows> "stuff" (key1="val1",=) .`,
expectedErr: true, // key can not be empty
},
{
input: `_:alice <knows> "stuff" (key1=val1,=val1) .`,
input: `_:alice <knows> "stuff" (key1="val1",="val1") .`,
expectedErr: true, // key can not be empty
},
{
input: `_:alice <knows> "stuff" (key1=val1,key1 val1) .`,
input: `_:alice <knows> "stuff" (key1="val1",key1 "val1") .`,
expectedErr: true, // '=' should separate key and val
},
{
input: `_:alice <knows> "stuff" (key1=val1,key1= val1 .`,
input: `_:alice <knows> "stuff" (key1="val1",key1= "val1" .`,
expectedErr: true, // facets should end by ')'
},
{
input: `_:alice <knows> "stuff" (key1=val1,key1= .`,
input: `_:alice <knows> "stuff" (key1="val1",key1= .`,
expectedErr: true, // facets should end by ')'
},
{
input: `_:alice <knows> "stuff" (key1=val1,key1=`,
input: `_:alice <knows> "stuff" (key1="val1",key1=`,
expectedErr: true, // facets should end by ')'
},
{
......@@ -778,6 +773,10 @@ var testNQuads = []struct {
input: `_:alice <knows> "stuff" (k=111111111111111111888888) .`,
expectedErr: true, // integer can not fit in int64.
},
{
input: `_:alice <knows> "stuff" (k=0x1787586C4FA8A0284FF8) .`,
expectedErr: true, // integer can not fit in int32 and also does not become float.
},
// Facet tests end
{
input: `<alice> <password> "guess"^^<pwd:password> .`,
......
......@@ -23,6 +23,7 @@ import (
"strconv"
"github.com/dgraph-io/dgraph/lex"
"github.com/dgraph-io/dgraph/x"
)
// The constants represent different types of lexed Items possible for an rdf N-Quad.
......@@ -388,6 +389,11 @@ forLoop:
case r == lex.EOF:
l.Emit(lex.ItemEOF)
return nil
case r == quote:
if err := lexQuotedString(l); err != nil {
return l.Errorf(err.Error())
}
l.Emit(itemText)
default:
l.AcceptRun(func(r rune) bool {
return r != equal && !isSpace(r) && r != rightRound && r != comma
......@@ -412,6 +418,31 @@ func lexComment(l *lex.Lexer) lex.StateFn {
return nil // Stop the run loop.
}
func lexQuotedString(l *lex.Lexer) error {
l.Backup()
r := l.Next()
if r != quote {
return x.Errorf("String should start with quote.")
}
for {
r := l.Next()
if r == lex.EOF {
return x.Errorf("Unexpected end of input.")
}
if r == '\\' {
r := l.Next()
if !isEscChar(r) {
return x.Errorf("Not a valid escape char: %v", r)
}
continue // eat the next char
}
if r == quote {
break
}
}
return nil
}
func isClosingBracket(r rune) bool {
return r == grThan
}
......
......@@ -66,21 +66,26 @@ func CopyFacets(fcs []*facetsp.Facet, param *facetsp.Param) (fs []*facetsp.Facet
// valAndValType returns interface val and valtype for facet.
func valAndValType(val string) (interface{}, facetsp.Facet_ValType, error) {
// TODO(ashish) : strings should be in quotes.. \"\"
// No need to check for nonNumChar then.
if len(val) == 0 { // empty string case
return "", facetsp.Facet_STRING, nil
}
// strings should be in quotes.
if len(val) >= 2 && val[0] == '"' && val[len(val)-1] == '"' {
return val[1 : len(val)-1], facetsp.Facet_STRING, nil
}
if intVal, err := strconv.ParseInt(val, 0, 64); err == nil {
return int64(intVal), facetsp.Facet_INT, nil
} else if numErr := err.(*strconv.NumError); numErr.Err == strconv.ErrRange {
// check if whole string is only of nums or not.
// comes here for : 11111111111111111111132333uasfk333 ; see test.
nonNumChar := false
// if we have only digits in val, then val is a big integer : return error
// otherwise try to parse as float.
allNumChars := true
for _, v := range val {
if !unicode.IsDigit(v) {
nonNumChar = true
allNumChars = false
break
}
}
if !nonNumChar { // return error
if allNumChars {
return nil, facetsp.Facet_INT, err
}
}
......@@ -95,7 +100,7 @@ func valAndValType(val string) (interface{}, facetsp.Facet_ValType, error) {
if t, err := parseTime(val); err == nil {
return t, facetsp.Facet_DATETIME, nil
}
return val, facetsp.Facet_STRING, nil
return nil, facetsp.Facet_STRING, x.Errorf("Could not parse the facet value : [%s]", val)
}
// FacetFor returns Facet for given key and val.
......
......@@ -106,7 +106,13 @@ func toRDF(buf *bytes.Buffer, item kv) {
buf.WriteByte('=')
fVal := &types.Val{Tid: types.StringID}
x.Check(types.Marshal(facets.ValFor(f), fVal))
buf.WriteString(fVal.Value.(string))
if facets.TypeIDFor(f) == types.StringID {
buf.WriteByte('"')
buf.WriteString(fVal.Value.(string))
buf.WriteByte('"')
} else {
buf.WriteString(fVal.Value.(string))
}
}
buf.WriteByte(')')
}
......
......@@ -51,7 +51,7 @@ func populateGraphBackup(t *testing.T) {
"<1> <friend> <5> <author0> .",
"<2> <friend> <5> <author0> .",
"<3> <friend> <5> .",
"<4> <friend> <5> <author0> (since=2005-05-02T15:04:05,close=true,age=33) .",
"<4> <friend> <5> <author0> (since=2005-05-02T15:04:05,close=true,age=33,game=\"football\") .",
"<1> <name> \"pho\\ton\" <author0> .",
"<2> <name> \"pho\\ton\"@en <author0> .",
}
......@@ -173,16 +173,19 @@ func TestBackup(t *testing.T) {
if nq.Subject == "0x4" {
require.Equal(t, "age", nq.Facets[0].Key)
require.Equal(t, "close", nq.Facets[1].Key)
require.Equal(t, "since", nq.Facets[2].Key)
require.Equal(t, "game", nq.Facets[2].Key)
require.Equal(t, "since", nq.Facets[3].Key)
// byte representation for facets.
require.Equal(t, []byte{0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, nq.Facets[0].Value)
require.Equal(t, []byte{0x1}, nq.Facets[1].Value)
require.Equal(t, []byte("football"), nq.Facets[2].Value)
require.Equal(t, "\x01\x00\x00\x00\x0e\xba\b8e\x00\x00\x00\x00\xff\xff",
string(nq.Facets[2].Value))
string(nq.Facets[3].Value))
// valtype for facets.
require.Equal(t, 1, int(nq.Facets[0].ValType))
require.Equal(t, 3, int(nq.Facets[1].ValType))
require.Equal(t, 4, int(nq.Facets[2].ValType))
require.Equal(t, 0, int(nq.Facets[2].ValType))
require.Equal(t, 4, int(nq.Facets[3].ValType))
}
// Test label
if nq.Subject != "0x3" {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment