Skip to content

Commit

Permalink
add direct equal comparator
Browse files Browse the repository at this point in the history
  • Loading branch information
AsaiYusuke committed Oct 26, 2023
1 parent bf6c344 commit b5fd772
Show file tree
Hide file tree
Showing 17 changed files with 147 additions and 35 deletions.
58 changes: 56 additions & 2 deletions jsonpath_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -555,13 +555,67 @@ func (p *jsonPathParser) _createBasicCompareQuery(

func (p *jsonPathParser) pushCompareEQ(
leftParam, rightParam *syntaxBasicCompareParameter) {
p.push(p._createBasicCompareQuery(leftParam, rightParam, &syntaxCompareEQ{}))
if rightLiteralParam, ok := rightParam.param.(*syntaxQueryParamLiteral); ok {
switch rightLiteralParam.literal[0].(type) {
case float64:
p.push(p._createBasicCompareQuery(leftParam, rightParam, &syntaxCompareDirectEQ{
syntaxTypeValidator: &syntaxBasicNumericTypeValidator{},
}))
case bool:
p.push(p._createBasicCompareQuery(leftParam, rightParam, &syntaxCompareDirectEQ{
syntaxTypeValidator: &syntaxBasicBoolTypeValidator{},
}))
case string:
p.push(p._createBasicCompareQuery(leftParam, rightParam, &syntaxCompareDirectEQ{
syntaxTypeValidator: &syntaxBasicStringTypeValidator{},
}))
case nil:
p.push(p._createBasicCompareQuery(leftParam, rightParam, &syntaxCompareDirectEQ{
syntaxTypeValidator: &syntaxBasicNilTypeValidator{},
}))
}

return
}

p.push(p._createBasicCompareQuery(leftParam, rightParam, &syntaxCompareDeepEQ{}))
}

func (p *jsonPathParser) pushCompareNE(
leftParam, rightParam *syntaxBasicCompareParameter) {
if rightLiteralParam, ok := rightParam.param.(*syntaxQueryParamLiteral); ok {
switch rightLiteralParam.literal[0].(type) {
case float64:
p.push(&syntaxLogicalNot{
query: p._createBasicCompareQuery(leftParam, rightParam, &syntaxCompareDirectEQ{
syntaxTypeValidator: &syntaxBasicNumericTypeValidator{},
}),
})
case bool:
p.push(&syntaxLogicalNot{
query: p._createBasicCompareQuery(leftParam, rightParam, &syntaxCompareDirectEQ{
syntaxTypeValidator: &syntaxBasicBoolTypeValidator{},
}),
})
case string:
p.push(&syntaxLogicalNot{
query: p._createBasicCompareQuery(leftParam, rightParam, &syntaxCompareDirectEQ{
syntaxTypeValidator: &syntaxBasicStringTypeValidator{},
}),
})
case nil:
p.push(&syntaxLogicalNot{
query: p._createBasicCompareQuery(leftParam, rightParam, &syntaxCompareDirectEQ{
syntaxTypeValidator: &syntaxBasicNilTypeValidator{},
}),
})
}

return
}

p.push(&syntaxLogicalNot{
query: p._createBasicCompareQuery(leftParam, rightParam, &syntaxCompareEQ{}),
query: p._createBasicCompareQuery(leftParam, rightParam, &syntaxCompareDeepEQ{}),
})
}

Expand Down
6 changes: 3 additions & 3 deletions syntax_basic_compare_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ func (q *syntaxBasicCompareQuery) compute(
root interface{}, currentList []interface{}) []interface{} {

leftValues := q.leftParam.compute(root, currentList)
leftFound := q.comparator.typeCast(leftValues)
leftFound := q.comparator.validate(leftValues)

rightValues := q.rightParam.compute(root, currentList)
rightFound := q.comparator.typeCast(rightValues)
rightFound := q.comparator.validate(rightValues)

if leftFound && rightFound {
// The syntax parser always results in a literal value on the right side as input.
Expand All @@ -25,7 +25,7 @@ func (q *syntaxBasicCompareQuery) compute(

// leftFound == false && rightFound == false
if leftFound == rightFound {
if _, ok := q.comparator.(*syntaxCompareEQ); ok {
if _, ok := q.comparator.(*syntaxCompareDeepEQ); ok {
return currentList
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package jsonpath

import "encoding/json"

type syntaxBasicAnyValueComparator struct {
type syntaxBasicAnyValueTypeValidator struct {
}

func (c *syntaxBasicAnyValueComparator) typeCast(values []interface{}) bool {
func (c *syntaxBasicAnyValueTypeValidator) validate(values []interface{}) bool {
var foundValue bool
for index := range values {
switch typedValue := values[index].(type) {
Expand Down
18 changes: 18 additions & 0 deletions syntax_basic_type_validator_bool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package jsonpath

type syntaxBasicBoolTypeValidator struct {
}

func (c *syntaxBasicBoolTypeValidator) validate(values []interface{}) bool {
var foundValue bool
for index := range values {
switch values[index].(type) {
case bool:
foundValue = true
case struct{}:
default:
values[index] = emptyEntity
}
}
return foundValue
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package jsonpath

type syntaxBasicStringComparator struct {
type syntaxBasicNilTypeValidator struct {
}

func (c *syntaxBasicStringComparator) typeCast(values []interface{}) bool {
func (c *syntaxBasicNilTypeValidator) validate(values []interface{}) bool {
var foundValue bool
for index := range values {
switch values[index].(type) {
case string:
case nil:
foundValue = true
case struct{}:
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package jsonpath

import "encoding/json"

type syntaxBasicNumericComparator struct {
type syntaxBasicNumericTypeValidator struct {
}

func (c *syntaxBasicNumericComparator) typeCast(values []interface{}) bool {
func (c *syntaxBasicNumericTypeValidator) validate(values []interface{}) bool {
var foundValue bool
for index := range values {
switch typedValue := values[index].(type) {
Expand Down
18 changes: 18 additions & 0 deletions syntax_basic_type_validator_string.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package jsonpath

type syntaxBasicStringTypeValidator struct {
}

func (c *syntaxBasicStringTypeValidator) validate(values []interface{}) bool {
var foundValue bool
for index := range values {
switch values[index].(type) {
case string:
foundValue = true
case struct{}:
default:
values[index] = emptyEntity
}
}
return foundValue
}
2 changes: 1 addition & 1 deletion syntax_if_comparator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ package jsonpath

type syntaxComparator interface {
comparator(left []interface{}, right interface{}) bool
typeCast(values []interface{}) bool
validate(values []interface{}) bool
}
5 changes: 5 additions & 0 deletions syntax_if_type_validater.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package jsonpath

type syntaxTypeValidator interface {
validate(values []interface{}) bool
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ package jsonpath

import "reflect"

type syntaxCompareEQ struct {
*syntaxBasicAnyValueComparator
type syntaxCompareDeepEQ struct {
*syntaxBasicAnyValueTypeValidator
}

func (c *syntaxCompareEQ) comparator(left []interface{}, right interface{}) bool {
func (c *syntaxCompareDeepEQ) comparator(left []interface{}, right interface{}) bool {
var hasValue bool
for leftIndex := range left {
if left[leftIndex] == emptyEntity {
Expand Down
17 changes: 17 additions & 0 deletions syntax_query_compare_comparator_direct_eq.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package jsonpath

type syntaxCompareDirectEQ struct {
syntaxTypeValidator
}

func (c *syntaxCompareDirectEQ) comparator(left []interface{}, right interface{}) bool {
var hasValue bool
for leftIndex := range left {
if left[leftIndex] == right {
hasValue = true
} else {
left[leftIndex] = emptyEntity
}
}
return hasValue
}
2 changes: 1 addition & 1 deletion syntax_query_compare_comparator_ge.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package jsonpath

type syntaxCompareGE struct {
*syntaxBasicNumericComparator
*syntaxBasicNumericTypeValidator
}

func (c *syntaxCompareGE) comparator(left []interface{}, right interface{}) bool {
Expand Down
2 changes: 1 addition & 1 deletion syntax_query_compare_comparator_gt.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package jsonpath

type syntaxCompareGT struct {
*syntaxBasicNumericComparator
*syntaxBasicNumericTypeValidator
}

func (c *syntaxCompareGT) comparator(left []interface{}, right interface{}) bool {
Expand Down
2 changes: 1 addition & 1 deletion syntax_query_compare_comparator_le.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package jsonpath

type syntaxCompareLE struct {
*syntaxBasicNumericComparator
*syntaxBasicNumericTypeValidator
}

func (c *syntaxCompareLE) comparator(left []interface{}, right interface{}) bool {
Expand Down
2 changes: 1 addition & 1 deletion syntax_query_compare_comparator_lt.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package jsonpath

type syntaxCompareLT struct {
*syntaxBasicNumericComparator
*syntaxBasicNumericTypeValidator
}

func (c *syntaxCompareLT) comparator(left []interface{}, right interface{}) bool {
Expand Down
2 changes: 1 addition & 1 deletion syntax_query_compare_comparator_regex.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package jsonpath
import "regexp"

type syntaxCompareRegex struct {
*syntaxBasicStringComparator
*syntaxBasicStringTypeValidator

regex *regexp.Regexp
}
Expand Down
28 changes: 14 additions & 14 deletions test_jsonpath_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func createErrorFunctionFailed(text string, errorString string) ErrorFunctionFai
}
}

func execTestRetrieve(t *testing.T, inputJSON interface{}, testCase TestCase, fileline string) ([]interface{}, error) {
func execTestRetrieve(t *testing.T, inputJSON interface{}, testCase TestCase, fileLine string) ([]interface{}, error) {
jsonPath := testCase.jsonpath
hasConfig := false
config := Config{}
Expand Down Expand Up @@ -90,19 +90,19 @@ func execTestRetrieve(t *testing.T, inputJSON interface{}, testCase TestCase, fi
fmt.Sprintf(`%s`, expectedError) == fmt.Sprintf(`%s`, err) {
return nil, err
}
t.Errorf("%s: expected error<%s> != actual error<%s>\n", fileline, expectedError, err)
t.Errorf("%s: expected error<%s> != actual error<%s>\n", fileLine, expectedError, err)
return nil, err
}
if expectedError != nil {
t.Errorf("%s: expected error<%s> != actual error<none>\n",
fileline, expectedError)
fileLine, expectedError)
return nil, err
}

return actualObject, err
}

func runTestCase(t *testing.T, testCase TestCase, fileline string) {
func runTestCase(t *testing.T, testCase TestCase, fileLine string) {
srcJSON := testCase.inputJSON
var src interface{}
var err error
Expand All @@ -113,11 +113,11 @@ func runTestCase(t *testing.T, testCase TestCase, fileline string) {
err = json.Unmarshal([]byte(srcJSON), &src)
}
if err != nil {
t.Errorf("%s: Error: %v", fileline, err)
t.Errorf("%s: Error: %v", fileLine, err)
return
}

actualObject, err := execTestRetrieve(t, src, testCase, fileline)
actualObject, err := execTestRetrieve(t, src, testCase, fileLine)
if t.Failed() {
return
}
Expand All @@ -128,20 +128,20 @@ func runTestCase(t *testing.T, testCase TestCase, fileline string) {
if testCase.resultValidator != nil {
err := testCase.resultValidator(src, actualObject)
if err != nil {
t.Errorf("%s: Error: %v", fileline, err)
t.Errorf("%s: Error: %v", fileLine, err)
}
return
}

actualOutputJSON, err := json.Marshal(actualObject)
if err != nil {
t.Errorf("%s: Error: %v", fileline, err)
t.Errorf("%s: Error: %v", fileLine, err)
return
}

if string(actualOutputJSON) != testCase.expectedJSON {
t.Errorf("%s: expectedOutputJSON<%s> != actualOutputJSON<%s>\n",
fileline, testCase.expectedJSON, actualOutputJSON)
fileLine, testCase.expectedJSON, actualOutputJSON)
return
}
}
Expand All @@ -150,12 +150,12 @@ func runTestCases(t *testing.T, testGroupName string, testCases []TestCase) {
for _, testCase := range testCases {
testCase := testCase
if _, file, line, ok := runtime.Caller(2); ok {
fileline := fmt.Sprintf(`%s:%d`, file, line)
fileLine := fmt.Sprintf(`%s:%d`, file, line)
t.Run(
fmt.Sprintf(`%s_<%s>_<%s>`, testGroupName, testCase.jsonpath, testCase.inputJSON),
func(t *testing.T) {
t.Parallel()
runTestCase(t, testCase, fileline)
runTestCase(t, testCase, fileLine)
})
}
}
Expand Down Expand Up @@ -3963,7 +3963,7 @@ func TestRetrieve_filterCompare(t *testing.T) {
expectedErr: createErrorMemberNotExist(`[?(@[1]>1)]`),
},
},
`found-path-and-not-found-literal`: []TestCase{
`found-path-and-not-found-root-path`: []TestCase{
{
jsonpath: `$[?(@.a == $.b)]`,
inputJSON: `[{"a":0},{"a":1}]`,
Expand Down Expand Up @@ -4024,7 +4024,7 @@ func TestRetrieve_filterCompare(t *testing.T) {
expectedErr: createErrorMemberNotExist(`[?($.b >= @.a)]`),
},
},
`not-found-path-and-found-literal`: []TestCase{
`not-found-path-and-found-root-path`: []TestCase{
{
jsonpath: `$[?(@.b == $[0].a)]`,
inputJSON: `[{"a":0},{"a":1}]`,
Expand Down Expand Up @@ -4085,7 +4085,7 @@ func TestRetrieve_filterCompare(t *testing.T) {
expectedErr: createErrorMemberNotExist(`[?($[0].a >= @.b)]`),
},
},
`not-found-path-and-not-found-literal`: []TestCase{
`not-found-path-and-not-found-root-path`: []TestCase{
{
jsonpath: `$[?(@.b == $.b)]`,
inputJSON: `[{"a":0},{"a":1}]`,
Expand Down

0 comments on commit b5fd772

Please sign in to comment.