diff --git a/README.md b/README.md index b0f49e6..827a771 100644 --- a/README.md +++ b/README.md @@ -6,25 +6,14 @@ This library enables query against JSON. Currently supported operators are: (pre ``` || && -= != > < >= <= ~= !~= is isnot += != > < >= <= ~= !~= is isnot contains + - * / % ^ ( ) ``` -## Changes - -The following operators are added: (Credit goes to Ahmad Baitalmal) -* is defined -* isnot defined -* is null -* isnot null - -Previously I was hoping to make the query as similar to SQL `WHERE` clause as possible. Later I found a problem parsing the term `PRIORITY>5`. The tokenizer split it as `PRI`, `OR`, `ITY`, `>`, `5`, since `OR` was then an operator, which is terribly wrong. At that point, I thought of two choices: -1. to force the query expression to contain at least one white space between tokens, thus `PRIORITY>5` should be written as `PRIORITY > 5`; -2. to replace operators as follows: - +The following are the operators maping to SQL: * `AND` to `&&` * `OR` to `||` * `RLIKE` to `~=` @@ -127,6 +116,9 @@ func main() { // [map[hobby: skills:[IC Electric design Verification] name:enny gender:f age:36]] fmt.Println(parser.Query("hobby isnot null")) - // [map[name:sam gender:m age:1 hobby:dancing skills:[Eating Sleeping Crawling]]] + // [map[name:sam gender:m age:1 hobby:dancing skills:[Eating Sleeping Crawling]]] + + fmt.Println(parser.Query("skills contains 'Eating'")) + // [map[age:1 gender:m hobby:dancing name:sam skills:[Eating Sleeping Crawling]]] } ``` diff --git a/exparser_test.go b/exparser_test.go index e4cfa0e..e2722dd 100644 --- a/exparser_test.go +++ b/exparser_test.go @@ -18,6 +18,7 @@ func TestTokenize(t *testing.T) { {"'123 456' 789", []string{"'123 456'", "789"}}, {`123 "456 789"`, []string{"123", "\"456 789\""}}, {`123 "456 '''789"`, []string{"123", "\"456 '''789\""}}, + {`2*x+y is null`, []string{"2", "*", "x", "+", "y", "is", "null"}}, } var fail = []struct { in string diff --git a/jsonql_test.go b/jsonql_test.go index 054cb2b..e02d327 100644 --- a/jsonql_test.go +++ b/jsonql_test.go @@ -45,11 +45,11 @@ func TestParse(t *testing.T) { var pass = []struct { in string - ex int }{ - {"name='elgs'", 1}, - {"gender='f'", 1}, - {"skills.[1]='Sleeping'", 1}, + {"name='elgs'"}, + {"gender='f'"}, + {"skills.[1]='Sleeping'"}, + {"skills contains 'Verification'"}, } var fail = []struct { in string diff --git a/sql_operators.go b/sql_operators.go index 38fd524..106f309 100644 --- a/sql_operators.go +++ b/sql_operators.go @@ -110,6 +110,27 @@ var sqlOperators = map[string]*Operator{ return "false", nil }, }, + "contains": { + Precedence: 5, + Eval: func(symbolTable interface{}, left string, right string) (string, error) { + l, err := evalToken(symbolTable, left) + if err != nil { + return "false", err + } + r, err := evalToken(symbolTable, right) + if err != nil { + return "false", err + } + if al, ok := l.([]interface{}); ok { + for _, item := range al { + if item == r { + return "true", nil + } + } + } + return "false", nil + }, + }, "=": { Precedence: 5, Eval: func(symbolTable interface{}, left string, right string) (string, error) {