diff --git a/gql/parser.go b/gql/parser.go index 4d1b2ead212..50febfbe096 100644 --- a/gql/parser.go +++ b/gql/parser.go @@ -366,6 +366,19 @@ func substituteVariables(gq *GraphQuery, vmap varMap) error { if err := substituteVar(v.Value, &gq.Func.Args[idx].Value, vmap); err != nil { return err } + if gq.Func.Name == "regexp" { + // Value should have been populated from the map that the user gave us in the + // GraphQL variable map. Let's parse the expression and flags from the variable + // string. + ra, err := parseRegexArgs(gq.Func.Args[idx].Value) + if err != nil { + return err + } + // We modify the value of this arg and add a new arg for the flags. Regex functions + // should have two args. + gq.Func.Args[idx].Value = ra.expr + gq.Func.Args = append(gq.Func.Args, Arg{Value: ra.flags}) + } } } @@ -1298,6 +1311,25 @@ func validFuncName(name string) bool { return false } +type regexArgs struct { + expr string + flags string +} + +func parseRegexArgs(val string) (regexArgs, error) { + end := strings.LastIndex(val, "/") + if end < 0 { + return regexArgs{}, x.Errorf("Unexpected error while parsing regex arg: %s", val) + } + expr := strings.Replace(val[1:end], "\\/", "/", -1) + flags := "" + if end+1 < len(val) { + flags = val[end+1:] + } + + return regexArgs{expr, flags}, nil +} + func parseFunction(it *lex.ItemIterator, gq *GraphQuery) (*Function, error) { var function *Function var expectArg, seenFuncArg, expectLang, isDollar bool @@ -1390,15 +1422,11 @@ L: isDollar = true continue } else if itemInFunc.Typ == itemRegex { - end := strings.LastIndex(itemInFunc.Val, "/") - x.AssertTrue(end >= 0) - expr := strings.Replace(itemInFunc.Val[1:end], "\\/", "/", -1) - flags := "" - if end+1 < len(itemInFunc.Val) { - flags = itemInFunc.Val[end+1:] + ra, err := parseRegexArgs(itemInFunc.Val) + if err != nil { + return nil, err } - - function.Args = append(function.Args, Arg{Value: expr}, Arg{Value: flags}) + function.Args = append(function.Args, Arg{Value: ra.expr}, Arg{Value: ra.flags}) expectArg = false continue // Lets reassemble the geo tokens. diff --git a/systest/mutations_test.go b/systest/mutations_test.go index ab487d6b0ef..07d9b634af6 100644 --- a/systest/mutations_test.go +++ b/systest/mutations_test.go @@ -64,6 +64,7 @@ func TestSystem(t *testing.T) { t.Run("has with dash", wrap(HasWithDash)) t.Run("list geo filter", wrap(ListGeoFilterTest)) t.Run("list regex filter", wrap(ListRegexFilterTest)) + t.Run("regex query vars", wrap(RegexQueryWithVars)) } func ExpandAllLangTest(t *testing.T, c *dgo.Dgraph) { @@ -1263,3 +1264,51 @@ func ListRegexFilterTest(t *testing.T, c *dgo.Dgraph) { } `, string(resp.GetJson())) } + +func RegexQueryWithVars(t *testing.T, c *dgo.Dgraph) { + ctx := context.Background() + + check(t, c.Alter(ctx, &api.Operation{ + Schema: ` + name: string @index(term) . + per: [string] @index(trigram) . + `, + })) + + txn := c.NewTxn() + defer txn.Discard(ctx) + _, err := txn.Mutate(ctx, &api.Mutation{ + CommitNow: true, + SetNquads: []byte(` + _:a "read" . + _:b "write" . + _:c "admin" . + + _:a "read" . + _:b "write" . + _:c "read" . + _:c "write" . + `), + }) + check(t, err) + + resp, err := c.NewTxn().QueryWithVars(context.Background(), ` + query search($term: string){ + q(func: regexp(per, $term)) { + name + } + }`, map[string]string{"$term": "/^rea.*$/"}) + check(t, err) + CompareJSON(t, ` + { + "q": [ + { + "name": "read" + }, + { + "name": "admin" + } + ] + } + `, string(resp.GetJson())) +}