@@ -82,9 +82,9 @@ func (ctx *jsonpathCtx) evalBoolean(
8282 case jsonpath .OpCompEqual , jsonpath .OpCompNotEqual ,
8383 jsonpath .OpCompLess , jsonpath .OpCompLessEqual ,
8484 jsonpath .OpCompGreater , jsonpath .OpCompGreaterEqual :
85- return ctx .evalComparison (op , jsonValue )
85+ return ctx .evalPredicate (op , jsonValue , evalComparisonFunc , true /* evalRight */ , true /* unwrapRight */ )
8686 case jsonpath .OpLikeRegex :
87- return ctx .evalRegex (op , jsonValue )
87+ return ctx .evalPredicate (op , jsonValue , evalRegexFunc , false /* evalRight */ , false /* unwrapRight */ )
8888 case jsonpath .OpExists :
8989 return ctx .evalExists (op , jsonValue )
9090 case jsonpath .OpIsUnknown :
@@ -126,17 +126,13 @@ func (ctx *jsonpathCtx) evalExists(
126126 return jsonpathBoolTrue , nil
127127}
128128
129- func (ctx * jsonpathCtx ) evalRegex (
130- op jsonpath.Operation , jsonValue json.JSON ,
131- ) (jsonpathBool , error ) {
132- l , err := ctx .evalAndUnwrapResult (op .Left , jsonValue , true /* unwrap */ )
133- if err != nil {
134- return jsonpathBoolUnknown , err
135- }
136- if len (l ) != 1 {
137- return jsonpathBoolUnknown , errors .AssertionFailedf ("left is not a single string" )
129+ func evalRegexFunc (op jsonpath.Operation , l , _ json.JSON ) (jsonpathBool , error ) {
130+ regexOp , ok := op .Right .(jsonpath.Regex )
131+ if ! ok {
132+ return jsonpathBoolUnknown , errors .AssertionFailedf ("op.Right is not a regex" )
138133 }
139- if l [0 ].Type () != json .StringJSONType {
134+
135+ if l .Type () != json .StringJSONType {
140136 return jsonpathBoolUnknown , nil
141137 }
142138 // AsText() provides the correct string representation for regex pattern
@@ -150,16 +146,16 @@ func (ctx *jsonpathCtx) evalRegex(
150146 // - For a JSON string with a newline ("\n"): AsText() returns an actual
151147 // newline character ("\n"), while String() returns "\"\\n\"" (an escaped
152148 // backslash and 'n' enclosed in quotes)
153- text , err := l [ 0 ] .AsText ()
149+ text , err := l .AsText ()
154150 if err != nil {
155151 return jsonpathBoolUnknown , err
156152 }
157153
158- regexOp := op .Right .(jsonpath.Regex )
159154 r , err := parser .ReCache .GetRegexp (regexOp )
160155 if err != nil {
161156 return jsonpathBoolUnknown , err
162157 }
158+
163159 res := r .MatchString (* text )
164160 if ! res {
165161 return jsonpathBoolFalse , nil
@@ -223,28 +219,40 @@ func (ctx *jsonpathCtx) evalLogical(
223219 }
224220}
225221
226- // evalComparison evaluates a comparison operation predicate. Predicates have
227- // existence semantics. True is returned if any pair of items from the left and
228- // right paths satisfy the condition. In strict mode, even if a pair has been
229- // found, all pairs need to be checked for errors.
230- func (ctx * jsonpathCtx ) evalComparison (
231- op jsonpath.Operation , jsonValue json.JSON ,
222+ // evalPredicate evaluates a predicate operation. Predicates have existence
223+ // semantics. True is returned if any pair of items from the left and right
224+ // paths satisfy the condition. In strict mode, even if a pair has been found,
225+ // all pairs need to be checked for errors.
226+ func (ctx * jsonpathCtx ) evalPredicate (
227+ op jsonpath.Operation ,
228+ jsonValue json.JSON ,
229+ exec func (op jsonpath.Operation , l , r json.JSON ) (jsonpathBool , error ),
230+ evalRight , unwrapRight bool ,
232231) (jsonpathBool , error ) {
233- // The left and right argument results are always auto-unwrapped.
232+ // The left argument results are always auto-unwrapped.
234233 left , err := ctx .evalAndUnwrapResult (op .Left , jsonValue , true /* unwrap */ )
235234 if err != nil {
236235 return jsonpathBoolUnknown , err
237236 }
238- right , err := ctx .evalAndUnwrapResult (op .Right , jsonValue , true /* unwrap */ )
239- if err != nil {
240- return jsonpathBoolUnknown , err
237+ var right []json.JSON
238+ if evalRight {
239+ // The right argument results are conditionally evaluated and unwrapped.
240+ right , err = ctx .evalAndUnwrapResult (op .Right , jsonValue , unwrapRight )
241+ if err != nil {
242+ return jsonpathBoolUnknown , err
243+ }
244+ } else {
245+ // If we don't want to evaluate the right argument, we need to call
246+ // the exec function once for each item in the left argument. Currently,
247+ // this only includes OpLikeRegex.
248+ right = append (right , nil )
241249 }
242250
243251 errored := false
244252 found := false
245253 for _ , l := range left {
246254 for _ , r := range right {
247- res , err := execComparison ( l , r , op . Type )
255+ res , err := exec ( op , l , r )
248256 if err != nil {
249257 return jsonpathBoolUnknown , err
250258 }
@@ -271,7 +279,8 @@ func (ctx *jsonpathCtx) evalComparison(
271279 return jsonpathBoolFalse , nil
272280}
273281
274- func execComparison (l , r json.JSON , op jsonpath.OperationType ) (jsonpathBool , error ) {
282+ func evalComparisonFunc (operation jsonpath.Operation , l , r json.JSON ) (jsonpathBool , error ) {
283+ op := operation .Type
275284 if l .Type () != r .Type () && ! (isBool (l ) && isBool (r )) {
276285 // Inequality comparison of nulls to non-nulls is true. Everything else
277286 // is false.
0 commit comments