joshbuddy / jsonpath

Ruby implementation of http://goessner.net/articles/JsonPath/
MIT License
447 stars 72 forks source link

Compound queries that test boolean values do not work #144

Closed gongfarmer closed 2 years ago

gongfarmer commented 2 years ago

Here is a test case:

  def test_and_operator_with_boolean_parameter_value
    data = {
      'data' => [{
        'hasProperty1' => true,
        'hasProperty2' => false,
        'name' => 'testname1'
      }, {
        'hasProperty1' => false,
        'hasProperty2' => true,
        'name' => 'testname2'
      }, {
        'hasProperty1' => true,
        'hasProperty2' => true,
        'name' => 'testname3'
      }]
    }
    assert_equal ['testname3'], JsonPath.new('$.data[?(@.hasProperty1 && @.hasProperty2)].name').on(data)
  end

Expected: find "testname3" Actual: finds "testname2" and "testname3"

gongfarmer commented 2 years ago

Strangely, it is fixed by removing a few lines. All tests pass afterward including the one I added. I don't understand the purpose of the lines I removed.


diff --git a/lib/jsonpath/enumerable.rb b/lib/jsonpath/enumerable.rb
index 7a6f270..62dd71f 100644
--- a/lib/jsonpath/enumerable.rb
+++ b/lib/jsonpath/enumerable.rb
@@ -151,9 +151,6 @@ class JsonPath
       identifiers = /@?((?<!\d)\.(?!\d)(\w+))+/.match(exp)
       if !identifiers.nil? && !@_current_node.methods.include?(identifiers[2].to_sym)
         exp_to_eval = exp.dup
-        exp_to_eval[identifiers[0]] = identifiers[0].split('.').map do |el|
-          el == '@' ? '@' : "['#{el}']"
-        end.join
         begin
           return JsonPath::Parser.new(@_current_node, @options).parse(exp_to_eval)
         rescue StandardError
diff --git a/test/test_jsonpath.rb b/test/test_jsonpath.rb
index 849e976..5bd18b6 100644
--- a/test/test_jsonpath.rb
+++ b/test/test_jsonpath.rb
@@ -573,6 +573,25 @@ class TestJsonpath < MiniTest::Unit::TestCase
     assert_equal [{ 'isTrue' => true, 'name' => 'testname1' }], JsonPath.new('$.data[?(@.isTrue)]').on(data)
   end

+  def test_and_operator_with_boolean_parameter_value
+    data = {
+      'data' => [{
+        'hasProperty1' => true,
+        'hasProperty2' => false,
+        'name' => 'testname1'
+      }, {
+        'hasProperty1' => false,
+        'hasProperty2' => true,
+        'name' => 'testname2'
+      }, {
+        'hasProperty1' => true,
+        'hasProperty2' => true,
+        'name' => 'testname3'
+      }]
+    }
+    assert_equal ['testname3'], JsonPath.new('$.data[?(@.hasProperty1 && @.hasProperty2)].name').on(data)
+  end
+
   def test_regex_simple
     assert_equal %w[asdf asdf2], JsonPath.new('$.store.book..tags[?(@ =~ /asdf/)]').on(@object)
   end```
joshbuddy commented 2 years ago

I'm also having a hard time understanding why this was splitting the first part like this. This could be a vestigial bit of code from some previous feature.

gongfarmer commented 2 years ago

Oops... removing that weird code caused a regression in v1.1.1.

$ cat data.json
{
  "data": [
    {
        "hasProperty1": false,
        "hasProperty2": true,
        "name": "testname1"
    },
    {
        "hasProperty1": false,
        "hasProperty2": true,
        "name": "testname2"
    }
  ]
}

$ cat data.json | ruby  -rjsonpath -rjson -e 'data=JSON.parse(ARGF.read); pp JsonPath.new("$.data[?(@.name != testname2)].name").on(data)'
["testname1"]

$ cat data.json | ruby  -rjsonpath -rjson -e 'data=JSON.parse(ARGF.read); pp JsonPath.new("$.data[?(@.name!=testname2)].name").on(data)'
[]

The output from both of the above queries is expected to match, the only difference is whitespace surrounding "!=". This test is running on JsonPath v1.1.1.
This bug was not present in v1.1.0.

PR is coming.

joshbuddy commented 2 years ago

Thank you for spotting this. I'll yank and re-publish once you've got a PR up.