aboutsummaryrefslogtreecommitdiff
path: root/weed/query/json
diff options
context:
space:
mode:
Diffstat (limited to 'weed/query/json')
-rw-r--r--weed/query/json/query_json.go107
-rw-r--r--weed/query/json/query_json_test.go133
-rw-r--r--weed/query/json/seralize.go17
3 files changed, 257 insertions, 0 deletions
diff --git a/weed/query/json/query_json.go b/weed/query/json/query_json.go
new file mode 100644
index 000000000..46f3b1b56
--- /dev/null
+++ b/weed/query/json/query_json.go
@@ -0,0 +1,107 @@
+package json
+
+import (
+ "strconv"
+
+ "github.com/chrislusf/seaweedfs/weed/query/sqltypes"
+ "github.com/tidwall/gjson"
+ "github.com/tidwall/match"
+)
+
+type Query struct {
+ Field string
+ Op string
+ Value string
+}
+
+func QueryJson(jsonLine string, projections []string, query Query) (passedFilter bool, values []sqltypes.Value) {
+ if filterJson(jsonLine, query) {
+ passedFilter = true
+ fields := gjson.GetMany(jsonLine, projections...)
+ for _, f := range fields {
+ values = append(values, sqltypes.MakeTrusted(sqltypes.Type(f.Type), sqltypes.StringToBytes(f.Raw)))
+ }
+ return
+ }
+ return false, nil
+}
+
+func filterJson(jsonLine string, query Query) bool {
+
+ value := gjson.Get(jsonLine, query.Field)
+
+ // copied from gjson.go queryMatches() function
+ rpv := query.Value
+
+ if !value.Exists() {
+ return false
+ }
+ if query.Op == "" {
+ // the query is only looking for existence, such as:
+ // friends.#(name)
+ // which makes sure that the array "friends" has an element of
+ // "name" that exists
+ return true
+ }
+ switch value.Type {
+ case gjson.String:
+ switch query.Op {
+ case "=":
+ return value.Str == rpv
+ case "!=":
+ return value.Str != rpv
+ case "<":
+ return value.Str < rpv
+ case "<=":
+ return value.Str <= rpv
+ case ">":
+ return value.Str > rpv
+ case ">=":
+ return value.Str >= rpv
+ case "%":
+ return match.Match(value.Str, rpv)
+ case "!%":
+ return !match.Match(value.Str, rpv)
+ }
+ case gjson.Number:
+ rpvn, _ := strconv.ParseFloat(rpv, 64)
+ switch query.Op {
+ case "=":
+ return value.Num == rpvn
+ case "!=":
+ return value.Num != rpvn
+ case "<":
+ return value.Num < rpvn
+ case "<=":
+ return value.Num <= rpvn
+ case ">":
+ return value.Num > rpvn
+ case ">=":
+ return value.Num >= rpvn
+ }
+ case gjson.True:
+ switch query.Op {
+ case "=":
+ return rpv == "true"
+ case "!=":
+ return rpv != "true"
+ case ">":
+ return rpv == "false"
+ case ">=":
+ return true
+ }
+ case gjson.False:
+ switch query.Op {
+ case "=":
+ return rpv == "false"
+ case "!=":
+ return rpv != "false"
+ case "<":
+ return rpv == "true"
+ case "<=":
+ return true
+ }
+ }
+ return false
+
+}
diff --git a/weed/query/json/query_json_test.go b/weed/query/json/query_json_test.go
new file mode 100644
index 000000000..1794bb333
--- /dev/null
+++ b/weed/query/json/query_json_test.go
@@ -0,0 +1,133 @@
+package json
+
+import (
+ "testing"
+
+ "github.com/tidwall/gjson"
+)
+
+func TestGjson(t *testing.T) {
+ data := `
+ {
+ "quiz": {
+ "sport": {
+ "q1": {
+ "question": "Which one is correct team name in NBA?",
+ "options": [
+ "New York Bulls",
+ "Los Angeles Kings",
+ "Golden State Warriros",
+ "Huston Rocket"
+ ],
+ "answer": "Huston Rocket"
+ }
+ },
+ "maths": {
+ "q1": {
+ "question": "5 + 7 = ?",
+ "options": [
+ "10",
+ "11",
+ "12",
+ "13"
+ ],
+ "answer": "12"
+ },
+ "q2": {
+ "question": "12 - 8 = ?",
+ "options": [
+ "1",
+ "2",
+ "3",
+ "4"
+ ],
+ "answer": "4"
+ }
+ }
+ }
+ }
+
+ {
+ "fruit": "Apple",
+ "size": "Large",
+ "quiz": "Red"
+ }
+
+`
+
+ projections := []string{"quiz", "fruit"}
+
+ gjson.ForEachLine(data, func(line gjson.Result) bool {
+ println(line.Raw)
+ println("+++++++++++")
+ results := gjson.GetMany(line.Raw, projections...)
+ for _, result := range results {
+ println(result.Index, result.Type, result.String())
+ }
+ println("-----------")
+ return true
+ })
+
+}
+
+func TestJsonQueryRow(t *testing.T) {
+
+ data := `
+ {
+ "fruit": "Bl\"ue",
+ "size": 6,
+ "quiz": "green"
+ }
+
+`
+ selections := []string{"fruit", "size"}
+
+ isFiltered, values := QueryJson(data, selections, Query{
+ Field: "quiz",
+ Op: "=",
+ Value: "green",
+ })
+
+ if !isFiltered {
+ t.Errorf("should have been filtered")
+ }
+
+ if values == nil {
+ t.Errorf("values should have been returned")
+ }
+
+ buf := ToJson(nil, selections, values)
+ println(string(buf))
+
+}
+
+func TestJsonQueryNumber(t *testing.T) {
+
+ data := `
+ {
+ "fruit": "Bl\"ue",
+ "size": 6,
+ "quiz": "green"
+ }
+
+`
+ selections := []string{"fruit", "quiz"}
+
+ isFiltered, values := QueryJson(data, selections, Query{
+ Field: "size",
+ Op: ">=",
+ Value: "6",
+ })
+
+ if !isFiltered {
+ t.Errorf("should have been filtered")
+ }
+
+ if values == nil {
+ t.Errorf("values should have been returned")
+ }
+
+ buf := ToJson(nil, selections, values)
+ println(string(buf))
+
+}
diff --git a/weed/query/json/seralize.go b/weed/query/json/seralize.go
new file mode 100644
index 000000000..9bbddc2ff
--- /dev/null
+++ b/weed/query/json/seralize.go
@@ -0,0 +1,17 @@
+package json
+
+import "github.com/chrislusf/seaweedfs/weed/query/sqltypes"
+
+func ToJson(buf []byte, selections []string, values []sqltypes.Value) []byte {
+ buf = append(buf, '{')
+ for i, value := range values {
+ if i > 0 {
+ buf = append(buf, ',')
+ }
+ buf = append(buf, selections[i]...)
+ buf = append(buf, ':')
+ buf = append(buf, value.Raw()...)
+ }
+ buf = append(buf, '}')
+ return buf
+}