jsonpath 0.9.3 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +33 -0
- data/.gitignore +5 -0
- data/.rubocop_todo.yml +33 -18
- data/Gemfile +1 -1
- data/README.md +173 -32
- data/jsonpath.gemspec +2 -9
- data/lib/jsonpath/dig.rb +57 -0
- data/lib/jsonpath/enumerable.rb +53 -20
- data/lib/jsonpath/parser.rb +176 -40
- data/lib/jsonpath/proxy.rb +12 -2
- data/lib/jsonpath/version.rb +1 -1
- data/lib/jsonpath.rb +79 -16
- data/test/test_jsonpath.rb +666 -9
- data/test/test_readme.rb +117 -0
- metadata +25 -25
- data/.travis.yml +0 -6
data/test/test_jsonpath.rb
CHANGED
@@ -48,13 +48,18 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def test_recognize_array_splices
|
51
|
-
assert_equal [@object['store']['book'][0]
|
51
|
+
assert_equal [@object['store']['book'][0]], JsonPath.new('$..book[0:1:1]').on(@object)
|
52
|
+
assert_equal [@object['store']['book'][0], @object['store']['book'][1]], JsonPath.new('$..book[0:2:1]').on(@object)
|
52
53
|
assert_equal [@object['store']['book'][1], @object['store']['book'][3], @object['store']['book'][5]], JsonPath.new('$..book[1::2]').on(@object)
|
53
54
|
assert_equal [@object['store']['book'][0], @object['store']['book'][2], @object['store']['book'][4], @object['store']['book'][6]], JsonPath.new('$..book[::2]').on(@object)
|
54
55
|
assert_equal [@object['store']['book'][0], @object['store']['book'][2]], JsonPath.new('$..book[:-5:2]').on(@object)
|
55
56
|
assert_equal [@object['store']['book'][5], @object['store']['book'][6]], JsonPath.new('$..book[5::]').on(@object)
|
56
57
|
end
|
57
58
|
|
59
|
+
def test_slice_array_with_exclusive_end_correctly
|
60
|
+
assert_equal [@object['store']['book'][0], @object['store']['book'][1]], JsonPath.new('$..book[:2]').on(@object)
|
61
|
+
end
|
62
|
+
|
58
63
|
def test_recognize_array_comma
|
59
64
|
assert_equal [@object['store']['book'][0], @object['store']['book'][1]], JsonPath.new('$..book[0,1]').on(@object)
|
60
65
|
assert_equal [@object['store']['book'][2], @object['store']['book'][6]], JsonPath.new('$..book[2,-1::]').on(@object)
|
@@ -67,16 +72,63 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
67
72
|
assert_equal [@object['store']['book'][3]], JsonPath.new("$..book[?(@['price'] > 20)]").on(@object)
|
68
73
|
end
|
69
74
|
|
75
|
+
def test_not_equals_operator
|
76
|
+
expected =
|
77
|
+
[
|
78
|
+
@object['store']['book'][0],
|
79
|
+
@object['store']['book'][4],
|
80
|
+
@object['store']['book'][5],
|
81
|
+
@object['store']['book'][6]
|
82
|
+
]
|
83
|
+
assert_equal(expected, JsonPath.new("$..book[?(@['category'] != 'fiction')]").on(@object))
|
84
|
+
assert_equal(expected, JsonPath.new("$..book[?(@['category']!=fiction)]").on(@object))
|
85
|
+
assert_equal(expected, JsonPath.new("$..book[?(@.category!=fiction)]").on(@object))
|
86
|
+
assert_equal(expected, JsonPath.new("$..book[?(@.category != 'fiction')]").on(@object))
|
87
|
+
end
|
88
|
+
|
70
89
|
def test_or_operator
|
71
90
|
assert_equal [@object['store']['book'][1], @object['store']['book'][3]], JsonPath.new("$..book[?(@['price'] == 13 || @['price'] == 23)]").on(@object)
|
91
|
+
result = ["Sayings of the Century", "Sword of Honour", "Moby Dick", "The Lord of the Rings"]
|
92
|
+
assert_equal result, JsonPath.new("$..book[?(@.price==13 || @.price==9 || @.price==23)].title").on(@object)
|
93
|
+
assert_equal result, JsonPath.new("$..book[?(@.price==9 || @.price==23 || @.price==13)].title").on(@object)
|
94
|
+
assert_equal result, JsonPath.new("$..book[?(@.price==23 || @.price==13 || @.price==9)].title").on(@object)
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_or_operator_with_not_equals
|
98
|
+
# Should be the same regardless of key style ( @.key vs @['key'] )
|
99
|
+
result = ['Nigel Rees', 'Evelyn Waugh', 'Herman Melville', 'J. R. R. Tolkien', 'Lukyanenko']
|
100
|
+
assert_equal result, JsonPath.new("$..book[?(@['title']=='Osennie Vizity' || @['author']!='Lukyanenko')].author").on(@object)
|
101
|
+
assert_equal result, JsonPath.new("$..book[?(@.title=='Osennie Vizity' || @.author != Lukyanenko )].author").on(@object)
|
102
|
+
assert_equal result, JsonPath.new("$..book[?(@.title=='Osennie Vizity' || @.author!=Lukyanenko )].author").on(@object)
|
72
103
|
end
|
73
104
|
|
74
105
|
def test_and_operator
|
75
106
|
assert_equal [], JsonPath.new("$..book[?(@['price'] == 13 && @['price'] == 23)]").on(@object)
|
107
|
+
assert_equal [], JsonPath.new("$..book[?(@.price>=13 && @.category==fiction && @.title==no_match)]").on(@object)
|
108
|
+
assert_equal [], JsonPath.new("$..book[?(@.title==no_match && @.category==fiction && @.price==13)]").on(@object)
|
109
|
+
assert_equal [], JsonPath.new("$..book[?(@.price==13 && @.title==no_match && @.category==fiction)]").on(@object)
|
110
|
+
assert_equal [], JsonPath.new("$..book[?(@.price==13 && @.bad_key_name==true && @.category==fiction)]").on(@object)
|
111
|
+
|
112
|
+
expected = [@object['store']['book'][1]]
|
113
|
+
assert_equal expected, JsonPath.new("$..book[?(@['price'] < 23 && @['price'] > 9)]").on(@object)
|
114
|
+
assert_equal expected, JsonPath.new("$..book[?(@.price < 23 && @.price > 9)]").on(@object)
|
115
|
+
|
116
|
+
expected = ['Sword of Honour', 'The Lord of the Rings']
|
117
|
+
assert_equal expected, JsonPath.new("$..book[?(@.price>=13 && @.category==fiction)].title").on(@object)
|
118
|
+
assert_equal ['The Lord of the Rings'], JsonPath.new("$..book[?(@.category==fiction && @.isbn && @.price>9)].title").on(@object)
|
119
|
+
assert_equal ['Sayings of the Century'], JsonPath.new("$..book[?(@['price'] == 9 && @.author=='Nigel Rees')].title").on(@object)
|
120
|
+
assert_equal ['Sayings of the Century'], JsonPath.new("$..book[?(@['price'] == 9 && @.tags..asdf)].title").on(@object)
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_and_operator_with_not_equals
|
124
|
+
expected = ['Nigel Rees']
|
125
|
+
assert_equal expected, JsonPath.new("$..book[?(@['price']==9 && @['category']!=fiction)].author").on(@object)
|
126
|
+
assert_equal expected, JsonPath.new("$..book[?(@.price==9 && @.category!=fiction)].author").on(@object)
|
76
127
|
end
|
77
128
|
|
78
|
-
def
|
79
|
-
|
129
|
+
def test_nested_grouping
|
130
|
+
path = "$..book[?((@['price'] == 19 && @['author'] == 'Herman Melville') || @['price'] == 23)]"
|
131
|
+
assert_equal [@object['store']['book'][3]], JsonPath.new(path).on(@object)
|
80
132
|
end
|
81
133
|
|
82
134
|
def test_eval_with_floating_point_and_and
|
@@ -103,6 +155,87 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
103
155
|
assert_equal [@object['store']['bicycle']['2seater']], JsonPath.new('$.store.bicycle.2seater').on(@object)
|
104
156
|
end
|
105
157
|
|
158
|
+
def test_recognized_dot_notation_in_filters
|
159
|
+
assert_equal [@object['store']['book'][2], @object['store']['book'][3]], JsonPath.new('$..book[?(@.isbn)]').on(@object)
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_works_on_non_hash
|
163
|
+
klass = Struct.new(:a, :b)
|
164
|
+
object = klass.new('some', 'value')
|
165
|
+
|
166
|
+
assert_equal ['value'], JsonPath.new('$.b').on(object)
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_works_on_object
|
170
|
+
klass = Class.new{
|
171
|
+
attr_reader :b
|
172
|
+
def initialize(b)
|
173
|
+
@b = b
|
174
|
+
end
|
175
|
+
}
|
176
|
+
object = klass.new("value")
|
177
|
+
|
178
|
+
assert_equal ["value"], JsonPath.new('$.b').on(object)
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_works_on_object_can_be_disabled
|
182
|
+
klass = Class.new{
|
183
|
+
attr_reader :b
|
184
|
+
def initialize(b)
|
185
|
+
@b = b
|
186
|
+
end
|
187
|
+
}
|
188
|
+
object = klass.new("value")
|
189
|
+
|
190
|
+
assert_equal [], JsonPath.new('$.b', allow_send: false).on(object)
|
191
|
+
end
|
192
|
+
|
193
|
+
def test_works_on_diggable
|
194
|
+
klass = Class.new{
|
195
|
+
attr_reader :h
|
196
|
+
def initialize(h)
|
197
|
+
@h = h
|
198
|
+
end
|
199
|
+
def dig(*keys)
|
200
|
+
@h.dig(*keys)
|
201
|
+
end
|
202
|
+
}
|
203
|
+
|
204
|
+
object = klass.new('a' => 'some', 'b' => 'value')
|
205
|
+
assert_equal ['value'], JsonPath.new('$.b').on(object)
|
206
|
+
|
207
|
+
object = {
|
208
|
+
"foo" => klass.new('a' => 'some', 'b' => 'value')
|
209
|
+
}
|
210
|
+
assert_equal ['value'], JsonPath.new('$.foo.b').on(object)
|
211
|
+
end
|
212
|
+
|
213
|
+
def test_works_on_non_hash_with_filters
|
214
|
+
klass = Struct.new(:a, :b)
|
215
|
+
first_object = klass.new('some', 'value')
|
216
|
+
second_object = klass.new('next', 'other value')
|
217
|
+
|
218
|
+
assert_equal ['other value'], JsonPath.new('$[?(@.a == "next")].b').on([first_object, second_object])
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_works_on_hash_with_summary
|
222
|
+
object = {
|
223
|
+
"foo" => [{
|
224
|
+
"a" => "some",
|
225
|
+
"b" => "value"
|
226
|
+
}]
|
227
|
+
}
|
228
|
+
assert_equal [{ "b" => "value" }], JsonPath.new("$.foo[*](b)").on(object)
|
229
|
+
end
|
230
|
+
|
231
|
+
def test_works_on_non_hash_with_summary
|
232
|
+
klass = Struct.new(:a, :b)
|
233
|
+
object = {
|
234
|
+
"foo" => [klass.new("some", "value")]
|
235
|
+
}
|
236
|
+
assert_equal [{ "b" => "value" }], JsonPath.new("$.foo[*](b)").on(object)
|
237
|
+
end
|
238
|
+
|
106
239
|
def test_recognize_array_with_evald_index
|
107
240
|
assert_equal [@object['store']['book'][2]], JsonPath.new('$..book[(@.length-5)]').on(@object)
|
108
241
|
end
|
@@ -112,7 +245,7 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
112
245
|
end
|
113
246
|
|
114
247
|
def test_counting
|
115
|
-
assert_equal
|
248
|
+
assert_equal 59, JsonPath.new('$..*').on(@object).to_a.size
|
116
249
|
end
|
117
250
|
|
118
251
|
def test_space_in_path
|
@@ -173,6 +306,83 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
173
306
|
assert_equal({ 'you' => nil }, h)
|
174
307
|
end
|
175
308
|
|
309
|
+
def test_delete_2
|
310
|
+
json = { 'store' => {
|
311
|
+
'book' => [
|
312
|
+
{ 'category' => 'reference',
|
313
|
+
'author' => 'Nigel Rees',
|
314
|
+
'title' => 'Sayings of the Century',
|
315
|
+
'price' => 9,
|
316
|
+
'tags' => %w[asdf asdf2] },
|
317
|
+
{ 'category' => 'fiction',
|
318
|
+
'author' => 'Evelyn Waugh',
|
319
|
+
'title' => 'Sword of Honour',
|
320
|
+
'price' => 13 },
|
321
|
+
{ 'category' => 'fiction',
|
322
|
+
'author' => 'Aasdf',
|
323
|
+
'title' => 'Aaasdf2',
|
324
|
+
'price' => 1 }
|
325
|
+
]
|
326
|
+
} }
|
327
|
+
json_deleted = { 'store' => {
|
328
|
+
'book' => [
|
329
|
+
{ 'category' => 'fiction',
|
330
|
+
'author' => 'Evelyn Waugh',
|
331
|
+
'title' => 'Sword of Honour',
|
332
|
+
'price' => 13 },
|
333
|
+
{ 'category' => 'fiction',
|
334
|
+
'author' => 'Aasdf',
|
335
|
+
'title' => 'Aaasdf2',
|
336
|
+
'price' => 1 }
|
337
|
+
]
|
338
|
+
} }
|
339
|
+
assert_equal(json_deleted, JsonPath.for(json).delete("$..store.book[?(@.category == 'reference')]").obj)
|
340
|
+
end
|
341
|
+
|
342
|
+
def test_delete_3
|
343
|
+
json = { 'store' => {
|
344
|
+
'book' => [
|
345
|
+
{ 'category' => 'reference',
|
346
|
+
'author' => 'Nigel Rees',
|
347
|
+
'title' => 'Sayings of the Century',
|
348
|
+
'price' => 9,
|
349
|
+
'tags' => %w[asdf asdf2],
|
350
|
+
'this' => {
|
351
|
+
'delete_me' => [
|
352
|
+
'no' => 'do not'
|
353
|
+
]
|
354
|
+
} },
|
355
|
+
{ 'category' => 'fiction',
|
356
|
+
'author' => 'Evelyn Waugh',
|
357
|
+
'title' => 'Sword of Honour',
|
358
|
+
'price' => 13 },
|
359
|
+
{ 'category' => 'fiction',
|
360
|
+
'author' => 'Aasdf',
|
361
|
+
'title' => 'Aaasdf2',
|
362
|
+
'price' => 1 }
|
363
|
+
]
|
364
|
+
} }
|
365
|
+
json_deleted = { 'store' => {
|
366
|
+
'book' => [
|
367
|
+
{ 'category' => 'reference',
|
368
|
+
'author' => 'Nigel Rees',
|
369
|
+
'title' => 'Sayings of the Century',
|
370
|
+
'price' => 9,
|
371
|
+
'tags' => %w[asdf asdf2],
|
372
|
+
'this' => {} },
|
373
|
+
{ 'category' => 'fiction',
|
374
|
+
'author' => 'Evelyn Waugh',
|
375
|
+
'title' => 'Sword of Honour',
|
376
|
+
'price' => 13 },
|
377
|
+
{ 'category' => 'fiction',
|
378
|
+
'author' => 'Aasdf',
|
379
|
+
'title' => 'Aaasdf2',
|
380
|
+
'price' => 1 }
|
381
|
+
]
|
382
|
+
} }
|
383
|
+
assert_equal(json_deleted, JsonPath.for(json).delete('$..store.book..delete_me').obj)
|
384
|
+
end
|
385
|
+
|
176
386
|
def test_delete_for_array
|
177
387
|
before = JsonPath.on(@object, '$..store.book[1]')
|
178
388
|
JsonPath.for(@object).delete!('$..store.book[0]')
|
@@ -265,6 +475,16 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
265
475
|
JsonPath.new('$.store._links').on(@object)
|
266
476
|
end
|
267
477
|
|
478
|
+
def test_support_for_umlauts_in_member_names
|
479
|
+
assert_equal [@object['store']['Übermorgen']],
|
480
|
+
JsonPath.new('$.store.Übermorgen').on(@object)
|
481
|
+
end
|
482
|
+
|
483
|
+
def test_support_for_spaces_in_member_name
|
484
|
+
assert_equal [@object['store']['Title Case']],
|
485
|
+
JsonPath.new('$.store.Title Case').on(@object)
|
486
|
+
end
|
487
|
+
|
268
488
|
def test_dig_return_string
|
269
489
|
assert_equal ['asdf'], JsonPath.new("$.store.book..tags[?(@ == 'asdf')]").on(@object)
|
270
490
|
assert_equal [], JsonPath.new("$.store.book..tags[?(@ == 'not_asdf')]").on(@object)
|
@@ -396,18 +616,65 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
396
616
|
'name' => 'testname2'
|
397
617
|
}]
|
398
618
|
}
|
399
|
-
|
619
|
+
|
620
|
+
# These queries should be equivalent
|
621
|
+
expected = [{ 'isTrue' => true, 'name' => 'testname1' }]
|
622
|
+
assert_equal expected, JsonPath.new('$.data[?(@.isTrue)]').on(data)
|
623
|
+
assert_equal expected, JsonPath.new('$.data[?(@.isTrue==true)]').on(data)
|
624
|
+
assert_equal expected, JsonPath.new('$.data[?(@.isTrue == true)]').on(data)
|
625
|
+
|
626
|
+
# These queries should be equivalent
|
627
|
+
expected = [{ 'isTrue' => false, 'name' => 'testname2' }]
|
628
|
+
assert_equal expected, JsonPath.new('$.data[?(@.isTrue != true)]').on(data)
|
629
|
+
assert_equal expected, JsonPath.new('$.data[?(@.isTrue!=true)]').on(data)
|
630
|
+
assert_equal expected, JsonPath.new('$.data[?(@.isTrue==false)]').on(data)
|
631
|
+
end
|
632
|
+
|
633
|
+
def test_and_operator_with_boolean_parameter_value
|
634
|
+
data = {
|
635
|
+
'data' => [{
|
636
|
+
'hasProperty1' => true,
|
637
|
+
'hasProperty2' => false,
|
638
|
+
'name' => 'testname1'
|
639
|
+
}, {
|
640
|
+
'hasProperty1' => false,
|
641
|
+
'hasProperty2' => true,
|
642
|
+
'name' => 'testname2'
|
643
|
+
}, {
|
644
|
+
'hasProperty1' => true,
|
645
|
+
'hasProperty2' => true,
|
646
|
+
'name' => 'testname3'
|
647
|
+
}]
|
648
|
+
}
|
649
|
+
assert_equal ['testname3'], JsonPath.new('$.data[?(@.hasProperty1 && @.hasProperty2)].name').on(data)
|
650
|
+
end
|
651
|
+
|
652
|
+
def test_regex_simple
|
653
|
+
assert_equal %w[asdf asdf2], JsonPath.new('$.store.book..tags[?(@ =~ /asdf/)]').on(@object)
|
654
|
+
assert_equal %w[asdf asdf2], JsonPath.new('$.store.book..tags[?(@=~/asdf/)]').on(@object)
|
655
|
+
end
|
656
|
+
|
657
|
+
def test_regex_simple_miss
|
658
|
+
assert_equal [], JsonPath.new('$.store.book..tags[?(@ =~ /wut/)]').on(@object)
|
659
|
+
end
|
660
|
+
|
661
|
+
def test_regex_r
|
662
|
+
assert_equal %w[asdf asdf2], JsonPath.new('$.store.book..tags[?(@ =~ %r{asdf})]').on(@object)
|
400
663
|
end
|
401
664
|
|
402
|
-
def
|
403
|
-
assert_equal [], JsonPath.new('$..book[?(@.author =~ /herman/)]').on(@object)
|
665
|
+
def test_regex_flags
|
404
666
|
assert_equal [
|
405
667
|
@object['store']['book'][2],
|
406
668
|
@object['store']['book'][4],
|
407
669
|
@object['store']['book'][5],
|
408
670
|
@object['store']['book'][6]
|
409
671
|
], JsonPath.new('$..book[?(@.author =~ /herman|lukyanenko/i)]').on(@object)
|
410
|
-
|
672
|
+
end
|
673
|
+
|
674
|
+
def test_regex_error
|
675
|
+
assert_raises ArgumentError do
|
676
|
+
JsonPath.new('$.store.book..tags[?(@ =~ asdf)]').on(@object)
|
677
|
+
end
|
411
678
|
end
|
412
679
|
|
413
680
|
def test_regression_1
|
@@ -508,6 +775,68 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
508
775
|
assert_equal 'C09C5GYHF', JsonPath.on(json, "$..channels[?(@.is_archived == 'false')].id")[0]
|
509
776
|
end
|
510
777
|
|
778
|
+
def test_quote
|
779
|
+
json = {
|
780
|
+
channels: [
|
781
|
+
{
|
782
|
+
name: "King's Speech"
|
783
|
+
}
|
784
|
+
]
|
785
|
+
}.to_json
|
786
|
+
|
787
|
+
assert_equal [{ 'name' => "King\'s Speech" }], JsonPath.on(json, "$..channels[?(@.name == 'King\'s Speech')]")
|
788
|
+
end
|
789
|
+
|
790
|
+
def test_curly_brackets
|
791
|
+
data = {
|
792
|
+
'{data}' => 'data'
|
793
|
+
}
|
794
|
+
assert_equal ['data'], JsonPath.new('$.{data}').on(data)
|
795
|
+
end
|
796
|
+
|
797
|
+
def test_symbolize
|
798
|
+
data = '
|
799
|
+
{
|
800
|
+
"store": {
|
801
|
+
"bicycle": {
|
802
|
+
"price": 19.95,
|
803
|
+
"color": "red"
|
804
|
+
},
|
805
|
+
"book": [
|
806
|
+
{
|
807
|
+
"price": 8.95,
|
808
|
+
"category": "reference",
|
809
|
+
"title": "Sayings of the Century",
|
810
|
+
"author": "Nigel Rees"
|
811
|
+
},
|
812
|
+
{
|
813
|
+
"price": 12.99,
|
814
|
+
"category": "fiction",
|
815
|
+
"title": "Sword of Honour",
|
816
|
+
"author": "Evelyn Waugh"
|
817
|
+
},
|
818
|
+
{
|
819
|
+
"price": 8.99,
|
820
|
+
"category": "fiction",
|
821
|
+
"isbn": "0-553-21311-3",
|
822
|
+
"title": "Moby Dick",
|
823
|
+
"author": "Herman Melville",
|
824
|
+
"color": "blue"
|
825
|
+
},
|
826
|
+
{
|
827
|
+
"price": 22.99,
|
828
|
+
"category": "fiction",
|
829
|
+
"isbn": "0-395-19395-8",
|
830
|
+
"title": "The Lord of the Rings",
|
831
|
+
"author": "Tolkien"
|
832
|
+
}
|
833
|
+
]
|
834
|
+
}
|
835
|
+
}
|
836
|
+
'
|
837
|
+
assert_equal [{ price: 8.95, category: 'reference', title: 'Sayings of the Century', author: 'Nigel Rees' }, { price: 8.99, category: 'fiction', isbn: '0-553-21311-3', title: 'Moby Dick', author: 'Herman Melville', color: 'blue' }], JsonPath.new('$..book[::2]').on(data, symbolize_keys: true)
|
838
|
+
end
|
839
|
+
|
511
840
|
def test_changed
|
512
841
|
json =
|
513
842
|
{
|
@@ -562,6 +891,33 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
562
891
|
assert_equal [true], JsonPath.on(json, broken_path)
|
563
892
|
end
|
564
893
|
|
894
|
+
def test_complex_nested_grouping
|
895
|
+
path = "$..book[?((@['author'] == 'Evelyn Waugh' || @['author'] == 'Herman Melville') && (@['price'] == 33 || @['price'] == 9))]"
|
896
|
+
assert_equal [@object['store']['book'][2]], JsonPath.new(path).on(@object)
|
897
|
+
end
|
898
|
+
|
899
|
+
def test_nested_with_unknown_key
|
900
|
+
path = "$..[?(@.price == 9 || @.price == 33)].title"
|
901
|
+
assert_equal ["Sayings of the Century", "Moby Dick", "Sayings of the Century", "Moby Dick"], JsonPath.new(path).on(@object)
|
902
|
+
end
|
903
|
+
|
904
|
+
def test_nested_with_unknown_key_filtered_array
|
905
|
+
path = "$..[?(@['price'] == 9 || @['price'] == 33)].title"
|
906
|
+
assert_equal ["Sayings of the Century", "Moby Dick", "Sayings of the Century", "Moby Dick"], JsonPath.new(path).on(@object)
|
907
|
+
end
|
908
|
+
|
909
|
+
def test_runtime_error_frozen_string
|
910
|
+
skip('in ruby version below 2.2.0 this error is not raised') if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.2.0') || Gem::Version.new(RUBY_VERSION) > Gem::Version::new('2.6')
|
911
|
+
json = '
|
912
|
+
{
|
913
|
+
"test": "something"
|
914
|
+
}
|
915
|
+
'.to_json
|
916
|
+
assert_raises(ArgumentError, "RuntimeError: character '|' not supported in query") do
|
917
|
+
JsonPath.on(json, '$.description|title')
|
918
|
+
end
|
919
|
+
end
|
920
|
+
|
565
921
|
def test_delete_more_items
|
566
922
|
a = { 'itemList' =>
|
567
923
|
[{ 'alfa' => 'beta1' },
|
@@ -577,7 +933,7 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
577
933
|
{ 'alfa' => 'beta11' },
|
578
934
|
{ 'alfa' => 'beta12' }] }
|
579
935
|
expected = { 'itemList' => [{ 'alfa' => 'beta1' }] }
|
580
|
-
assert_equal expected, JsonPath.for(a.to_json).delete('$.itemList[1:
|
936
|
+
assert_equal expected, JsonPath.for(a.to_json).delete('$.itemList[1:12:1]').to_hash
|
581
937
|
end
|
582
938
|
|
583
939
|
def test_delete_more_items_with_stepping
|
@@ -607,6 +963,277 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
607
963
|
assert_equal expected, JsonPath.for(a.to_json).delete('$.itemList[1:6:2]').to_hash
|
608
964
|
end
|
609
965
|
|
966
|
+
def test_nested_values
|
967
|
+
json = '
|
968
|
+
{
|
969
|
+
"phoneNumbers": [
|
970
|
+
[{
|
971
|
+
"type" : "iPhone",
|
972
|
+
"number": "0123-4567-8888"
|
973
|
+
}],
|
974
|
+
[{
|
975
|
+
"type" : "home",
|
976
|
+
"number": "0123-4567-8910"
|
977
|
+
}]
|
978
|
+
]
|
979
|
+
}
|
980
|
+
'.to_json
|
981
|
+
assert_equal [[{ 'type' => 'home', 'number' => '0123-4567-8910' }]], JsonPath.on(json, "$.phoneNumbers[?(@[0].type == 'home')]")
|
982
|
+
assert_equal [], JsonPath.on(json, "$.phoneNumbers[?(@[2].type == 'home')]")
|
983
|
+
json = '
|
984
|
+
{
|
985
|
+
"phoneNumbers":
|
986
|
+
{
|
987
|
+
"type" : "iPhone",
|
988
|
+
"number": "0123-4567-8888"
|
989
|
+
}
|
990
|
+
}
|
991
|
+
'.to_json
|
992
|
+
assert_equal [], JsonPath.on(json, "$.phoneNumbers[?(@[0].type == 'home')]")
|
993
|
+
end
|
994
|
+
|
995
|
+
def test_selecting_multiple_keys_on_hash
|
996
|
+
json = '
|
997
|
+
{
|
998
|
+
"category": "reference",
|
999
|
+
"author": "Nigel Rees",
|
1000
|
+
"title": "Sayings of the Century",
|
1001
|
+
"price": 8.95
|
1002
|
+
}
|
1003
|
+
'.to_json
|
1004
|
+
assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, '$.(category,author)')
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
def test_selecting_multiple_keys_on_sub_hash
|
1008
|
+
skip("Failing as the semantics of .(x,y) is unclear")
|
1009
|
+
json = '
|
1010
|
+
{
|
1011
|
+
"book": {
|
1012
|
+
"category": "reference",
|
1013
|
+
"author": "Nigel Rees",
|
1014
|
+
"title": "Sayings of the Century",
|
1015
|
+
"price": 8.95
|
1016
|
+
}
|
1017
|
+
}
|
1018
|
+
'.to_json
|
1019
|
+
assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, '$.book.(category,author)')
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
def test_selecting_multiple_keys_on_array
|
1023
|
+
json = '
|
1024
|
+
{
|
1025
|
+
"store": {
|
1026
|
+
"book": [
|
1027
|
+
{
|
1028
|
+
"category": "reference",
|
1029
|
+
"author": "Nigel Rees",
|
1030
|
+
"title": "Sayings of the Century",
|
1031
|
+
"price": 8.95
|
1032
|
+
},
|
1033
|
+
{
|
1034
|
+
"category": "fiction",
|
1035
|
+
"author": "Evelyn Waugh",
|
1036
|
+
"title": "Sword of Honour",
|
1037
|
+
"price": 12.99
|
1038
|
+
}
|
1039
|
+
]
|
1040
|
+
}
|
1041
|
+
}
|
1042
|
+
'.to_json
|
1043
|
+
|
1044
|
+
assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }, { 'category' => 'fiction', 'author' => 'Evelyn Waugh' }], JsonPath.on(json, '$.store.book[*](category,author)')
|
1045
|
+
end
|
1046
|
+
|
1047
|
+
def test_selecting_multiple_keys_on_array_with_filter
|
1048
|
+
json = '
|
1049
|
+
{
|
1050
|
+
"store": {
|
1051
|
+
"book": [
|
1052
|
+
{
|
1053
|
+
"category": "reference",
|
1054
|
+
"author": "Nigel Rees",
|
1055
|
+
"title": "Sayings of the Century",
|
1056
|
+
"price": 8.95
|
1057
|
+
},
|
1058
|
+
{
|
1059
|
+
"category": "fiction",
|
1060
|
+
"author": "Evelyn Waugh",
|
1061
|
+
"title": "Sword of Honour",
|
1062
|
+
"price": 12.99
|
1063
|
+
}
|
1064
|
+
]
|
1065
|
+
}
|
1066
|
+
}
|
1067
|
+
'.to_json
|
1068
|
+
|
1069
|
+
assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, "$.store.book[?(@['price'] == 8.95)](category,author)")
|
1070
|
+
assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, "$.store.book[?(@['price'] == 8.95)]( category, author )")
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
def test_selecting_multiple_keys_with_filter_with_space_in_catergory
|
1074
|
+
json = '
|
1075
|
+
{
|
1076
|
+
"store": {
|
1077
|
+
"book": [
|
1078
|
+
{
|
1079
|
+
"cate gory": "reference",
|
1080
|
+
"author": "Nigel Rees",
|
1081
|
+
"title": "Sayings of the Century",
|
1082
|
+
"price": 8.95
|
1083
|
+
},
|
1084
|
+
{
|
1085
|
+
"cate gory": "fiction",
|
1086
|
+
"author": "Evelyn Waugh",
|
1087
|
+
"title": "Sword of Honour",
|
1088
|
+
"price": 12.99
|
1089
|
+
}
|
1090
|
+
]
|
1091
|
+
}
|
1092
|
+
}
|
1093
|
+
'.to_json
|
1094
|
+
|
1095
|
+
assert_equal [{ 'cate gory' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, "$.store.book[?(@['price'] == 8.95)]( cate gory, author )")
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
def test_use_symbol_opt
|
1099
|
+
json = {
|
1100
|
+
store: {
|
1101
|
+
book: [
|
1102
|
+
{
|
1103
|
+
category: "reference",
|
1104
|
+
author: "Nigel Rees",
|
1105
|
+
title: "Sayings of the Century",
|
1106
|
+
price: 8.95
|
1107
|
+
},
|
1108
|
+
{
|
1109
|
+
category: "fiction",
|
1110
|
+
author: "Evelyn Waugh",
|
1111
|
+
title: "Sword of Honour",
|
1112
|
+
price: 12.99
|
1113
|
+
}
|
1114
|
+
]
|
1115
|
+
}
|
1116
|
+
}
|
1117
|
+
on = ->(path){ JsonPath.on(json, path, use_symbols: true) }
|
1118
|
+
assert_equal ['reference', 'fiction'], on.("$.store.book[*].category")
|
1119
|
+
assert_equal ['reference', 'fiction'], on.("$..category")
|
1120
|
+
assert_equal ['reference'], on.("$.store.book[?(@['price'] == 8.95)].category")
|
1121
|
+
assert_equal [{'category' => 'reference'}], on.("$.store.book[?(@['price'] == 8.95)](category)")
|
1122
|
+
end
|
1123
|
+
|
1124
|
+
def test_object_method_send
|
1125
|
+
j = {height: 5, hash: "some_hash"}.to_json
|
1126
|
+
hs = JsonPath.new "$..send"
|
1127
|
+
assert_equal([], hs.on(j))
|
1128
|
+
hs = JsonPath.new "$..hash"
|
1129
|
+
assert_equal(["some_hash"], hs.on(j))
|
1130
|
+
hs = JsonPath.new "$..send"
|
1131
|
+
assert_equal([], hs.on(j))
|
1132
|
+
j = {height: 5, send: "should_still_work"}.to_json
|
1133
|
+
hs = JsonPath.new "$..send"
|
1134
|
+
assert_equal(['should_still_work'], hs.on(j))
|
1135
|
+
end
|
1136
|
+
|
1137
|
+
def test_index_access_by_number
|
1138
|
+
data = {
|
1139
|
+
'1': 'foo'
|
1140
|
+
}
|
1141
|
+
assert_equal ['foo'], JsonPath.new('$.1').on(data.to_json)
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
def test_behavior_on_null_and_missing
|
1145
|
+
data = {
|
1146
|
+
"foo" => nil,
|
1147
|
+
"bar" => {
|
1148
|
+
"baz" => nil
|
1149
|
+
},
|
1150
|
+
"bars" => [
|
1151
|
+
{ "foo" => 12 },
|
1152
|
+
{ "foo" => nil },
|
1153
|
+
{ }
|
1154
|
+
]
|
1155
|
+
}
|
1156
|
+
assert_equal [nil], JsonPath.new('$.foo').on(data)
|
1157
|
+
assert_equal [nil], JsonPath.new('$.bar.baz').on(data)
|
1158
|
+
assert_equal [], JsonPath.new('$.baz').on(data)
|
1159
|
+
assert_equal [], JsonPath.new('$.bar.foo').on(data)
|
1160
|
+
assert_equal [12, nil], JsonPath.new('$.bars[*].foo').on(data)
|
1161
|
+
end
|
1162
|
+
|
1163
|
+
def test_default_path_leaf_to_null_opt
|
1164
|
+
data = {
|
1165
|
+
"foo" => nil,
|
1166
|
+
"bar" => {
|
1167
|
+
"baz" => nil
|
1168
|
+
},
|
1169
|
+
"bars" => [
|
1170
|
+
{ "foo" => 12 },
|
1171
|
+
{ "foo" => nil },
|
1172
|
+
{ }
|
1173
|
+
]
|
1174
|
+
}
|
1175
|
+
assert_equal [nil], JsonPath.new('$.foo', default_path_leaf_to_null: true).on(data)
|
1176
|
+
assert_equal [nil], JsonPath.new('$.bar.baz', default_path_leaf_to_null: true).on(data)
|
1177
|
+
assert_equal [nil], JsonPath.new('$.baz', default_path_leaf_to_null: true).on(data)
|
1178
|
+
assert_equal [nil], JsonPath.new('$.bar.foo', default_path_leaf_to_null: true).on(data)
|
1179
|
+
assert_equal [12, nil, nil], JsonPath.new('$.bars[*].foo', default_path_leaf_to_null: true).on(data)
|
1180
|
+
end
|
1181
|
+
|
1182
|
+
def test_raise_max_nesting_error
|
1183
|
+
json = {
|
1184
|
+
a: {
|
1185
|
+
b: {
|
1186
|
+
c: {
|
1187
|
+
}
|
1188
|
+
}
|
1189
|
+
}
|
1190
|
+
}.to_json
|
1191
|
+
|
1192
|
+
assert_raises(MultiJson::ParseError) { JsonPath.new('$.a', max_nesting: 1).on(json) }
|
1193
|
+
end
|
1194
|
+
|
1195
|
+
def test_linefeed_in_path_error
|
1196
|
+
assert_raises(ArgumentError) { JsonPath.new("$.store\n.book") }
|
1197
|
+
end
|
1198
|
+
|
1199
|
+
def test_with_max_nesting_false
|
1200
|
+
json = {
|
1201
|
+
a: {
|
1202
|
+
b: {
|
1203
|
+
c: {
|
1204
|
+
}
|
1205
|
+
}
|
1206
|
+
}
|
1207
|
+
}.to_json
|
1208
|
+
|
1209
|
+
assert_equal [{}], JsonPath.new('$.a.b.c', max_nesting: false).on(json)
|
1210
|
+
end
|
1211
|
+
|
1212
|
+
def test_initialize_with_max_nesting_exceeding_limit
|
1213
|
+
json = {
|
1214
|
+
a: {
|
1215
|
+
b: {
|
1216
|
+
c: {
|
1217
|
+
}
|
1218
|
+
}
|
1219
|
+
}
|
1220
|
+
}.to_json
|
1221
|
+
|
1222
|
+
json_obj = JsonPath.new('$.a.b.c', max_nesting: 105)
|
1223
|
+
assert_equal [{}], json_obj.on(json)
|
1224
|
+
assert_equal false, json_obj.instance_variable_get(:@opts)[:max_nesting]
|
1225
|
+
end
|
1226
|
+
|
1227
|
+
def test_initialize_without_max_nesting_exceeding_limit
|
1228
|
+
json_obj = JsonPath.new('$.a.b.c', max_nesting: 90)
|
1229
|
+
assert_equal 90, json_obj.instance_variable_get(:@opts)[:max_nesting]
|
1230
|
+
end
|
1231
|
+
|
1232
|
+
def test_initialize_with_max_nesting_false_limit
|
1233
|
+
json_obj = JsonPath.new('$.a.b.c', max_nesting: false)
|
1234
|
+
assert_equal false, json_obj.instance_variable_get(:@opts)[:max_nesting]
|
1235
|
+
end
|
1236
|
+
|
610
1237
|
def example_object
|
611
1238
|
{ 'store' => {
|
612
1239
|
'book' => [
|
@@ -658,7 +1285,37 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
658
1285
|
},
|
659
1286
|
'@id' => 'http://example.org/store/42',
|
660
1287
|
'$meta-data' => 'whatevs',
|
1288
|
+
'Übermorgen' => 'The day after tomorrow',
|
1289
|
+
'Title Case' => 'A title case string',
|
661
1290
|
'_links' => { 'self' => {} }
|
662
1291
|
} }
|
663
1292
|
end
|
1293
|
+
|
1294
|
+
def test_fetch_all_path
|
1295
|
+
data = {
|
1296
|
+
"foo" => nil,
|
1297
|
+
"bar" => {
|
1298
|
+
"baz" => nil
|
1299
|
+
},
|
1300
|
+
"bars" => [
|
1301
|
+
{ "foo" => 12 },
|
1302
|
+
{ "foo" => nil },
|
1303
|
+
{ }
|
1304
|
+
]
|
1305
|
+
}
|
1306
|
+
assert_equal ["$", "$.foo", "$.bar", "$.bar.baz", "$.bars", "$.bars[0].foo", "$.bars[0]", "$.bars[1].foo", "$.bars[1]", "$.bars[2]"], JsonPath.fetch_all_path(data)
|
1307
|
+
end
|
1308
|
+
|
1309
|
+
|
1310
|
+
def test_extractore_with_dollar_key
|
1311
|
+
json = {"test" => {"$" =>"success", "a" => "123"}}
|
1312
|
+
assert_equal ["success"], JsonPath.on(json, "$.test.$")
|
1313
|
+
assert_equal ["123"], JsonPath.on(json, "$.test.a")
|
1314
|
+
end
|
1315
|
+
|
1316
|
+
def test_symbolize_key
|
1317
|
+
data = { "store" => { "book" => [{"category" => "reference"}]}}
|
1318
|
+
assert_equal [{"category": "reference"}], JsonPath.new('$..book[0]', symbolize_keys: true).on(data)
|
1319
|
+
assert_equal [{"category": "reference"}], JsonPath.new('$..book[0]').on(data, symbolize_keys: true)
|
1320
|
+
end
|
664
1321
|
end
|