Skip to content

Commit bd681f3

Browse files
author
rhtang
committed
bugfix: cmp_any string equal ...
1 parent fb37af1 commit bd681f3

3 files changed

Lines changed: 170 additions & 9 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ _testmain.go
2323
*.exe
2424
*.test
2525
*.prof
26+
.idea

jsonpath.go

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"reflect"
1010
"strconv"
1111
"strings"
12+
"errors"
1213
)
1314

1415
func JsonPathLookup(obj interface{}, jpath string) (interface{}, error) {
@@ -278,6 +279,7 @@ func get_key(obj interface{}, key string) (interface{}, error) {
278279
switch reflect.TypeOf(obj).Kind() {
279280
case reflect.Map:
280281
for _, kv := range reflect.ValueOf(obj).MapKeys() {
282+
//fmt.Println(kv.String())
281283
if kv.String() == key {
282284
return reflect.ValueOf(obj).MapIndex(kv).Interface(), nil
283285
}
@@ -400,6 +402,57 @@ func get_filtered(obj, root interface{}, filter string) ([]interface{}, error) {
400402

401403
func parse_filter(filter string) (lp string, op string, rp string, err error) {
402404
tmp := ""
405+
406+
stage := 0
407+
str_embrace := false
408+
for idx, c := range filter {
409+
switch c {
410+
case '\'':
411+
if str_embrace == false {
412+
str_embrace = true
413+
} else {
414+
switch stage {
415+
case 0: lp = tmp
416+
case 1: op = tmp
417+
case 2: rp = tmp
418+
}
419+
tmp = ""
420+
}
421+
case ' ':
422+
if str_embrace == true {
423+
tmp += string(c)
424+
continue
425+
}
426+
switch stage {
427+
case 0: lp = tmp
428+
case 1: op = tmp
429+
case 2: rp = tmp
430+
}
431+
tmp = ""
432+
433+
stage += 1
434+
if stage > 2 {
435+
return "", "", "", errors.New(fmt.Sprintf("invalid char at %d: `%s`", idx, c))
436+
}
437+
default:
438+
tmp += string(c)
439+
}
440+
}
441+
if tmp != "" {
442+
switch stage {
443+
case 0:
444+
lp = tmp
445+
op = "exists"
446+
case 1: op = tmp
447+
case 2: rp = tmp
448+
}
449+
tmp = ""
450+
}
451+
return lp, op, rp, err
452+
}
453+
454+
func parse_filter_v1(filter string) (lp string, op string, rp string, err error) {
455+
tmp := ""
403456
istoken := false
404457
for _, c := range filter {
405458
if istoken == false && c != ' ' {
@@ -468,14 +521,37 @@ func eval_filter(obj, root interface{}, lp, op, rp string) (res bool, err error)
468521
}
469522
}
470523

524+
func isNumber(s string) bool {
525+
dot_cnt := 0
526+
for _, c := range s {
527+
if c == '.' {
528+
dot_cnt += 1
529+
if dot_cnt > 1 {
530+
return false
531+
}
532+
} else if ( c >= '0' && c <= '9') {
533+
continue
534+
} else {
535+
return false
536+
}
537+
}
538+
return true
539+
}
540+
471541
func cmp_any(obj1, obj2 interface{}, op string) (bool, error) {
472542
switch op {
473543
case "<", "<=", "==", ">=", ">":
474544
default:
475545
return false, fmt.Errorf("op should only be <, <=, ==, >= and >")
476546
}
477-
//fmt.Println("cmp_any: ", obj1, obj2)
478-
exp := fmt.Sprintf("%v %s %v", obj1, op, obj2)
547+
548+
549+
var exp string
550+
if isNumber(fmt.Sprintf("%s", obj1)) && isNumber(fmt.Sprintf("%s", obj2)) {
551+
exp = fmt.Sprintf(`%v %s %v`, obj1, op, obj2)
552+
} else {
553+
exp = fmt.Sprintf(`"%v" %s "%v"`, obj1, op, obj2)
554+
}
479555
//fmt.Println("exp: ", exp)
480556
fset := token.NewFileSet()
481557
res, err := types.Eval(fset, nil, 0, exp)

jsonpath_test.go

Lines changed: 91 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -611,10 +611,19 @@ var tcase_parse_filter = []map[string]interface{}{
611611
"exp_rp": "/.*REES/i",
612612
"exp_err": nil,
613613
},
614+
615+
// 4
616+
{
617+
"filter": "@.author == 'Nigel Rees'",
618+
"exp_lp": "@.author",
619+
"exp_op": "==",
620+
"exp_rp": "Nigel Rees",
621+
},
614622
}
615623

616624
func Test_jsonpath_parse_filter(t *testing.T) {
617625

626+
//for _, tcase := range tcase_parse_filter[4:] {
618627
for _, tcase := range tcase_parse_filter {
619628
lp, op, rp, _ := parse_filter(tcase["filter"].(string))
620629
t.Log(tcase)
@@ -794,7 +803,12 @@ func Test_jsonpath_eval_filter(t *testing.T) {
794803
}
795804
}
796805

806+
var (
807+
ifc1 interface{} = "haha"
808+
ifc2 interface{} = "ha ha"
809+
)
797810
var tcase_cmp_any = []map[string]interface{}{
811+
798812
map[string]interface{}{
799813
"obj1": 1,
800814
"obj2": 1,
@@ -836,26 +850,96 @@ var tcase_cmp_any = []map[string]interface{}{
836850
"op": "=~",
837851
"exp": false,
838852
"err": "op should only be <, <=, ==, >= and >",
853+
},{
854+
"obj1": ifc1,
855+
"obj2": ifc1,
856+
"op": "==",
857+
"exp": true,
858+
"err": nil,
859+
},{
860+
"obj1": ifc2,
861+
"obj2": ifc2,
862+
"op": "==",
863+
"exp": true,
864+
"err": nil,
839865
},
840866
}
841867

842868
func Test_jsonpath_cmp_any(t *testing.T) {
843869
for idx, tcase := range tcase_cmp_any {
870+
//for idx, tcase := range tcase_cmp_any[6:] {
844871
t.Logf("idx: %v, %v %v %v, exp: %v", idx, tcase["obj1"], tcase["op"], tcase["obj2"], tcase["exp"])
845872
res, err := cmp_any(tcase["obj1"], tcase["obj2"], tcase["op"].(string))
846873
exp := tcase["exp"].(bool)
847874
exp_err := tcase["err"]
848-
if exp_err != nil && err == nil {
849-
t.Errorf("idx: error not raised: %v(exp)", idx, exp_err)
850-
return
875+
if exp_err != nil {
876+
if err == nil {
877+
t.Errorf("idx: error not raised: %v(exp)", idx, exp_err)
878+
break
879+
}
851880
} else {
852-
continue
853-
}
854-
if err != nil {
855-
t.Errorf("idx: %v, error: %v", idx, err)
881+
if err != nil {
882+
t.Errorf("idx: %v, error: %v", idx, err)
883+
break
884+
}
856885
}
857886
if res != exp {
858887
t.Errorf("idx: %v, %v(got) != %v(exp)", idx, res, exp)
888+
break
859889
}
860890
}
861891
}
892+
893+
func Test_jsonpath_string_equal(t *testing.T) {
894+
data := `{
895+
"store": {
896+
"book": [
897+
{
898+
"category": "reference",
899+
"author": "Nigel Rees",
900+
"title": "Sayings of the Century",
901+
"price": 8.95
902+
},
903+
{
904+
"category": "fiction",
905+
"author": "Evelyn Waugh",
906+
"title": "Sword of Honour",
907+
"price": 12.99
908+
},
909+
{
910+
"category": "fiction",
911+
"author": "Herman Melville",
912+
"title": "Moby Dick",
913+
"isbn": "0-553-21311-3",
914+
"price": 8.99
915+
},
916+
{
917+
"category": "fiction",
918+
"author": "J. R. R. Tolkien",
919+
"title": "The Lord of the Rings",
920+
"isbn": "0-395-19395-8",
921+
"price": 22.99
922+
}
923+
],
924+
"bicycle": {
925+
"color": "red",
926+
"price": 19.95
927+
}
928+
},
929+
"expensive": 10
930+
}`
931+
932+
933+
var j interface{}
934+
935+
json.Unmarshal([]byte(data), &j)
936+
937+
res, err := JsonPathLookup(j, "$.store.book[?(@.author == 'Nigel Rees')].price")
938+
t.Log(res, err)
939+
if err != nil {
940+
t.Fatalf("err: %v", err)
941+
}
942+
if fmt.Sprintf("%v", res) != "[8.95]" {
943+
t.Fatalf("not the same: %v", res)
944+
}
945+
}

0 commit comments

Comments
 (0)