iso-jsonpath 1.1.6
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 +7 -0
- data/.gemtest +0 -0
- data/.github/workflows/test.yml +33 -0
- data/.gitignore +10 -0
- data/.rspec +3 -0
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +127 -0
- data/Gemfile +6 -0
- data/LICENSE.md +21 -0
- data/README.md +301 -0
- data/Rakefile +23 -0
- data/bin/jsonpath +23 -0
- data/jsonpath.gemspec +28 -0
- data/lib/jsonpath/dig.rb +57 -0
- data/lib/jsonpath/enumerable.rb +170 -0
- data/lib/jsonpath/parser.rb +221 -0
- data/lib/jsonpath/proxy.rb +67 -0
- data/lib/jsonpath/version.rb +5 -0
- data/lib/jsonpath.rb +160 -0
- data/test/test_jsonpath.rb +1334 -0
- data/test/test_jsonpath_bin.rb +23 -0
- data/test/test_readme.rb +117 -0
- metadata +166 -0
@@ -0,0 +1,1334 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'phocus'
|
5
|
+
require 'jsonpath'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
class TestJsonpath < MiniTest::Unit::TestCase
|
9
|
+
def setup
|
10
|
+
@object = example_object
|
11
|
+
@object2 = example_object
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_bracket_matching
|
15
|
+
assert_raises(ArgumentError) { JsonPath.new('$.store.book[0') }
|
16
|
+
assert_raises(ArgumentError) { JsonPath.new('$.store.book[0]]') }
|
17
|
+
assert_equal [9], JsonPath.new('$.store.book[0].price').on(@object)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_lookup_direct_path
|
21
|
+
assert_equal 7, JsonPath.new('$.store.*').on(@object).first['book'].size
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_lookup_missing_element
|
25
|
+
assert_equal [], JsonPath.new('$.store.book[99].price').on(@object)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_retrieve_all_authors
|
29
|
+
assert_equal [
|
30
|
+
@object['store']['book'][0]['author'],
|
31
|
+
@object['store']['book'][1]['author'],
|
32
|
+
@object['store']['book'][2]['author'],
|
33
|
+
@object['store']['book'][3]['author'],
|
34
|
+
@object['store']['book'][4]['author'],
|
35
|
+
@object['store']['book'][5]['author'],
|
36
|
+
@object['store']['book'][6]['author']
|
37
|
+
], JsonPath.new('$..author').on(@object)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_retrieve_all_prices
|
41
|
+
assert_equal [
|
42
|
+
@object['store']['bicycle']['price'],
|
43
|
+
@object['store']['book'][0]['price'],
|
44
|
+
@object['store']['book'][1]['price'],
|
45
|
+
@object['store']['book'][2]['price'],
|
46
|
+
@object['store']['book'][3]['price']
|
47
|
+
].sort, JsonPath.new('$..price').on(@object).sort
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_recognize_array_splices
|
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)
|
53
|
+
assert_equal [@object['store']['book'][1], @object['store']['book'][3], @object['store']['book'][5]], JsonPath.new('$..book[1::2]').on(@object)
|
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)
|
55
|
+
assert_equal [@object['store']['book'][0], @object['store']['book'][2]], JsonPath.new('$..book[:-5:2]').on(@object)
|
56
|
+
assert_equal [@object['store']['book'][5], @object['store']['book'][6]], JsonPath.new('$..book[5::]').on(@object)
|
57
|
+
end
|
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
|
+
|
63
|
+
def test_recognize_array_comma
|
64
|
+
assert_equal [@object['store']['book'][0], @object['store']['book'][1]], JsonPath.new('$..book[0,1]').on(@object)
|
65
|
+
assert_equal [@object['store']['book'][2], @object['store']['book'][6]], JsonPath.new('$..book[2,-1::]').on(@object)
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_recognize_filters
|
69
|
+
assert_equal [@object['store']['book'][2], @object['store']['book'][3]], JsonPath.new("$..book[?(@['isbn'])]").on(@object)
|
70
|
+
assert_equal [@object['store']['book'][0], @object['store']['book'][1]], JsonPath.new("$..book[?(@['year published'])]").on(@object)
|
71
|
+
assert_equal [@object['store']['book'][0], @object['store']['book'][2]], JsonPath.new("$..book[?(@['price'] < 10)]").on(@object)
|
72
|
+
assert_equal [@object['store']['book'][0], @object['store']['book'][2]], JsonPath.new("$..book[?(@['price'] == 9)]").on(@object)
|
73
|
+
assert_equal [@object['store']['book'][3]], JsonPath.new("$..book[?(@['price'] > 20)]").on(@object)
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_not_equals_operator
|
77
|
+
expected =
|
78
|
+
[
|
79
|
+
@object['store']['book'][0],
|
80
|
+
@object['store']['book'][4],
|
81
|
+
@object['store']['book'][5],
|
82
|
+
@object['store']['book'][6]
|
83
|
+
]
|
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
|
+
assert_equal(expected, JsonPath.new("$..book[?(@.category != 'fiction')]").on(@object))
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_or_operator
|
91
|
+
assert_equal [@object['store']['book'][1], @object['store']['book'][3]], JsonPath.new("$..book[?(@['price'] == 13 || @['price'] == 23)]").on(@object)
|
92
|
+
result = ["Sayings of the Century", "Sword of Honour", "Moby Dick", "The Lord of the Rings"]
|
93
|
+
assert_equal result, JsonPath.new("$..book[?(@.price==13 || @.price==9 || @.price==23)].title").on(@object)
|
94
|
+
assert_equal result, JsonPath.new("$..book[?(@.price==9 || @.price==23 || @.price==13)].title").on(@object)
|
95
|
+
assert_equal result, JsonPath.new("$..book[?(@.price==23 || @.price==13 || @.price==9)].title").on(@object)
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_or_operator_with_not_equals
|
99
|
+
# Should be the same regardless of key style ( @.key vs @['key'] )
|
100
|
+
result = ['Nigel Rees', 'Evelyn Waugh', 'Herman Melville', 'J. R. R. Tolkien', 'Lukyanenko']
|
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)
|
103
|
+
assert_equal result, JsonPath.new("$..book[?(@.title=='Osennie Vizity' || @.author!=Lukyanenko )].author").on(@object)
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_and_operator
|
107
|
+
assert_equal [], JsonPath.new("$..book[?(@['price'] == 13 && @['price'] == 23)]").on(@object)
|
108
|
+
assert_equal [], JsonPath.new("$..book[?(@.price>=13 && @.category==fiction && @.title==no_match)]").on(@object)
|
109
|
+
assert_equal [], JsonPath.new("$..book[?(@.title==no_match && @.category==fiction && @.price==13)]").on(@object)
|
110
|
+
assert_equal [], JsonPath.new("$..book[?(@.price==13 && @.title==no_match && @.category==fiction)]").on(@object)
|
111
|
+
assert_equal [], JsonPath.new("$..book[?(@.price==13 && @.bad_key_name==true && @.category==fiction)]").on(@object)
|
112
|
+
|
113
|
+
expected = [@object['store']['book'][1]]
|
114
|
+
assert_equal expected, JsonPath.new("$..book[?(@['price'] < 23 && @['price'] > 9)]").on(@object)
|
115
|
+
assert_equal expected, JsonPath.new("$..book[?(@.price < 23 && @.price > 9)]").on(@object)
|
116
|
+
|
117
|
+
expected = ['Sword of Honour', 'The Lord of the Rings']
|
118
|
+
assert_equal expected, JsonPath.new("$..book[?(@.price>=13 && @.category==fiction)].title").on(@object)
|
119
|
+
assert_equal ['The Lord of the Rings'], JsonPath.new("$..book[?(@.category==fiction && @.isbn && @.price>9)].title").on(@object)
|
120
|
+
assert_equal ['Sayings of the Century'], JsonPath.new("$..book[?(@['price'] == 9 && @.author=='Nigel Rees')].title").on(@object)
|
121
|
+
assert_equal ['Sayings of the Century'], JsonPath.new("$..book[?(@['price'] == 9 && @.tags..asdf)].title").on(@object)
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_and_operator_with_not_equals
|
125
|
+
expected = ['Nigel Rees']
|
126
|
+
assert_equal expected, JsonPath.new("$..book[?(@['price']==9 && @['category']!=fiction)].author").on(@object)
|
127
|
+
assert_equal expected, JsonPath.new("$..book[?(@.price==9 && @.category!=fiction)].author").on(@object)
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_nested_grouping
|
131
|
+
path = "$..book[?((@['price'] == 19 && @['author'] == 'Herman Melville') || @['price'] == 23)]"
|
132
|
+
assert_equal [@object['store']['book'][3]], JsonPath.new(path).on(@object)
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_eval_with_floating_point_and_and
|
136
|
+
assert_equal [@object['store']['book'][1]], JsonPath.new("$..book[?(@['price'] < 23.0 && @['price'] > 9.0)]").on(@object)
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_eval_with_floating_point
|
140
|
+
assert_equal [@object['store']['book'][1]], JsonPath.new("$..book[?(@['price'] == 13.0)]").on(@object)
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_paths_with_underscores
|
144
|
+
assert_equal [@object['store']['bicycle']['catalogue_number']], JsonPath.new('$.store.bicycle.catalogue_number').on(@object)
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_path_with_hyphens
|
148
|
+
assert_equal [@object['store']['bicycle']['single-speed']], JsonPath.new('$.store.bicycle.single-speed').on(@object)
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_path_with_colon
|
152
|
+
assert_equal [@object['store']['bicycle']['make:model']], JsonPath.new('$.store.bicycle.make:model').on(@object)
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_paths_with_numbers
|
156
|
+
assert_equal [@object['store']['bicycle']['2seater']], JsonPath.new('$.store.bicycle.2seater').on(@object)
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_recognized_dot_notation_in_filters
|
160
|
+
assert_equal [@object['store']['book'][2], @object['store']['book'][3]], JsonPath.new('$..book[?(@.isbn)]').on(@object)
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_works_on_non_hash
|
164
|
+
klass = Struct.new(:a, :b)
|
165
|
+
object = klass.new('some', 'value')
|
166
|
+
|
167
|
+
assert_equal ['value'], JsonPath.new('$.b').on(object)
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_works_on_object
|
171
|
+
klass = Class.new{
|
172
|
+
attr_reader :b
|
173
|
+
def initialize(b)
|
174
|
+
@b = b
|
175
|
+
end
|
176
|
+
}
|
177
|
+
object = klass.new("value")
|
178
|
+
|
179
|
+
assert_equal ["value"], JsonPath.new('$.b').on(object)
|
180
|
+
end
|
181
|
+
|
182
|
+
def test_works_on_object_can_be_disabled
|
183
|
+
klass = Class.new{
|
184
|
+
attr_reader :b
|
185
|
+
def initialize(b)
|
186
|
+
@b = b
|
187
|
+
end
|
188
|
+
}
|
189
|
+
object = klass.new("value")
|
190
|
+
|
191
|
+
assert_equal [], JsonPath.new('$.b', allow_send: false).on(object)
|
192
|
+
end
|
193
|
+
|
194
|
+
def test_works_on_diggable
|
195
|
+
klass = Class.new{
|
196
|
+
attr_reader :h
|
197
|
+
def initialize(h)
|
198
|
+
@h = h
|
199
|
+
end
|
200
|
+
def dig(*keys)
|
201
|
+
@h.dig(*keys)
|
202
|
+
end
|
203
|
+
}
|
204
|
+
|
205
|
+
object = klass.new('a' => 'some', 'b' => 'value')
|
206
|
+
assert_equal ['value'], JsonPath.new('$.b').on(object)
|
207
|
+
|
208
|
+
object = {
|
209
|
+
"foo" => klass.new('a' => 'some', 'b' => 'value')
|
210
|
+
}
|
211
|
+
assert_equal ['value'], JsonPath.new('$.foo.b').on(object)
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_works_on_non_hash_with_filters
|
215
|
+
klass = Struct.new(:a, :b)
|
216
|
+
first_object = klass.new('some', 'value')
|
217
|
+
second_object = klass.new('next', 'other value')
|
218
|
+
|
219
|
+
assert_equal ['other value'], JsonPath.new('$[?(@.a == "next")].b').on([first_object, second_object])
|
220
|
+
end
|
221
|
+
|
222
|
+
def test_works_on_hash_with_summary
|
223
|
+
object = {
|
224
|
+
"foo" => [{
|
225
|
+
"a" => "some",
|
226
|
+
"b" => "value"
|
227
|
+
}]
|
228
|
+
}
|
229
|
+
assert_equal [{ "b" => "value" }], JsonPath.new("$.foo[*](b)").on(object)
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_works_on_non_hash_with_summary
|
233
|
+
klass = Struct.new(:a, :b)
|
234
|
+
object = {
|
235
|
+
"foo" => [klass.new("some", "value")]
|
236
|
+
}
|
237
|
+
assert_equal [{ "b" => "value" }], JsonPath.new("$.foo[*](b)").on(object)
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_recognize_array_with_evald_index
|
241
|
+
assert_equal [@object['store']['book'][2]], JsonPath.new('$..book[(@.length-5)]').on(@object)
|
242
|
+
end
|
243
|
+
|
244
|
+
def test_use_first
|
245
|
+
assert_equal @object['store']['book'][2], JsonPath.new('$..book[(@.length-5)]').first(@object)
|
246
|
+
end
|
247
|
+
|
248
|
+
def test_counting
|
249
|
+
assert_equal 61, JsonPath.new('$..*').on(@object).to_a.size
|
250
|
+
end
|
251
|
+
|
252
|
+
def test_space_in_path
|
253
|
+
assert_equal ['e'], JsonPath.new("$.'c d'").on('a' => 'a', 'b' => 'b', 'c d' => 'e')
|
254
|
+
end
|
255
|
+
|
256
|
+
def test_class_method
|
257
|
+
assert_equal JsonPath.new('$..author').on(@object), JsonPath.on(@object, '$..author')
|
258
|
+
end
|
259
|
+
|
260
|
+
def test_join
|
261
|
+
assert_equal JsonPath.new('$.store.book..author').on(@object), JsonPath.new('$.store').join('book..author').on(@object)
|
262
|
+
end
|
263
|
+
|
264
|
+
def test_gsub
|
265
|
+
@object2['store']['bicycle']['price'] += 10
|
266
|
+
@object2['store']['book'][0]['price'] += 10
|
267
|
+
@object2['store']['book'][1]['price'] += 10
|
268
|
+
@object2['store']['book'][2]['price'] += 10
|
269
|
+
@object2['store']['book'][3]['price'] += 10
|
270
|
+
assert_equal @object2, JsonPath.for(@object).gsub('$..price') { |p| p + 10 }.to_hash
|
271
|
+
end
|
272
|
+
|
273
|
+
def test_gsub!
|
274
|
+
JsonPath.for(@object).gsub!('$..price') { |p| p + 10 }
|
275
|
+
assert_equal 30, @object['store']['bicycle']['price']
|
276
|
+
assert_equal 19, @object['store']['book'][0]['price']
|
277
|
+
assert_equal 23, @object['store']['book'][1]['price']
|
278
|
+
assert_equal 19, @object['store']['book'][2]['price']
|
279
|
+
assert_equal 33, @object['store']['book'][3]['price']
|
280
|
+
end
|
281
|
+
|
282
|
+
def test_weird_gsub!
|
283
|
+
h = { 'hi' => 'there' }
|
284
|
+
JsonPath.for(@object).gsub!('$.*') { |_| h }
|
285
|
+
assert_equal h, @object
|
286
|
+
end
|
287
|
+
|
288
|
+
def test_gsub_to_false!
|
289
|
+
h = { 'hi' => 'there' }
|
290
|
+
h2 = { 'hi' => false }
|
291
|
+
assert_equal h2, JsonPath.for(h).gsub!('$.hi') { |_| false }.to_hash
|
292
|
+
end
|
293
|
+
|
294
|
+
def test_where_selector
|
295
|
+
JsonPath.for(@object).gsub!('$..book.price[?(@ > 20)]') { |p| p + 10 }
|
296
|
+
end
|
297
|
+
|
298
|
+
def test_compact
|
299
|
+
h = { 'hi' => 'there', 'you' => nil }
|
300
|
+
JsonPath.for(h).compact!
|
301
|
+
assert_equal({ 'hi' => 'there' }, h)
|
302
|
+
end
|
303
|
+
|
304
|
+
def test_delete
|
305
|
+
h = { 'hi' => 'there', 'you' => nil }
|
306
|
+
JsonPath.for(h).delete!('*.hi')
|
307
|
+
assert_equal({ 'you' => nil }, h)
|
308
|
+
end
|
309
|
+
|
310
|
+
def test_delete_2
|
311
|
+
json = { 'store' => {
|
312
|
+
'book' => [
|
313
|
+
{ 'category' => 'reference',
|
314
|
+
'author' => 'Nigel Rees',
|
315
|
+
'title' => 'Sayings of the Century',
|
316
|
+
'price' => 9,
|
317
|
+
'tags' => %w[asdf asdf2] },
|
318
|
+
{ 'category' => 'fiction',
|
319
|
+
'author' => 'Evelyn Waugh',
|
320
|
+
'title' => 'Sword of Honour',
|
321
|
+
'price' => 13 },
|
322
|
+
{ 'category' => 'fiction',
|
323
|
+
'author' => 'Aasdf',
|
324
|
+
'title' => 'Aaasdf2',
|
325
|
+
'price' => 1 }
|
326
|
+
]
|
327
|
+
} }
|
328
|
+
json_deleted = { 'store' => {
|
329
|
+
'book' => [
|
330
|
+
{ 'category' => 'fiction',
|
331
|
+
'author' => 'Evelyn Waugh',
|
332
|
+
'title' => 'Sword of Honour',
|
333
|
+
'price' => 13 },
|
334
|
+
{ 'category' => 'fiction',
|
335
|
+
'author' => 'Aasdf',
|
336
|
+
'title' => 'Aaasdf2',
|
337
|
+
'price' => 1 }
|
338
|
+
]
|
339
|
+
} }
|
340
|
+
assert_equal(json_deleted, JsonPath.for(json).delete("$..store.book[?(@.category == 'reference')]").obj)
|
341
|
+
end
|
342
|
+
|
343
|
+
def test_delete_3
|
344
|
+
json = { 'store' => {
|
345
|
+
'book' => [
|
346
|
+
{ 'category' => 'reference',
|
347
|
+
'author' => 'Nigel Rees',
|
348
|
+
'title' => 'Sayings of the Century',
|
349
|
+
'price' => 9,
|
350
|
+
'tags' => %w[asdf asdf2],
|
351
|
+
'this' => {
|
352
|
+
'delete_me' => [
|
353
|
+
'no' => 'do not'
|
354
|
+
]
|
355
|
+
} },
|
356
|
+
{ 'category' => 'fiction',
|
357
|
+
'author' => 'Evelyn Waugh',
|
358
|
+
'title' => 'Sword of Honour',
|
359
|
+
'price' => 13 },
|
360
|
+
{ 'category' => 'fiction',
|
361
|
+
'author' => 'Aasdf',
|
362
|
+
'title' => 'Aaasdf2',
|
363
|
+
'price' => 1 }
|
364
|
+
]
|
365
|
+
} }
|
366
|
+
json_deleted = { 'store' => {
|
367
|
+
'book' => [
|
368
|
+
{ 'category' => 'reference',
|
369
|
+
'author' => 'Nigel Rees',
|
370
|
+
'title' => 'Sayings of the Century',
|
371
|
+
'price' => 9,
|
372
|
+
'tags' => %w[asdf asdf2],
|
373
|
+
'this' => {} },
|
374
|
+
{ 'category' => 'fiction',
|
375
|
+
'author' => 'Evelyn Waugh',
|
376
|
+
'title' => 'Sword of Honour',
|
377
|
+
'price' => 13 },
|
378
|
+
{ 'category' => 'fiction',
|
379
|
+
'author' => 'Aasdf',
|
380
|
+
'title' => 'Aaasdf2',
|
381
|
+
'price' => 1 }
|
382
|
+
]
|
383
|
+
} }
|
384
|
+
assert_equal(json_deleted, JsonPath.for(json).delete('$..store.book..delete_me').obj)
|
385
|
+
end
|
386
|
+
|
387
|
+
def test_delete_for_array
|
388
|
+
before = JsonPath.on(@object, '$..store.book[1]')
|
389
|
+
JsonPath.for(@object).delete!('$..store.book[0]')
|
390
|
+
after = JsonPath.on(@object, '$..store.book[0]')
|
391
|
+
assert_equal(after, before, 'Before is the second element. After should have been equal to the next element after delete.')
|
392
|
+
end
|
393
|
+
|
394
|
+
def test_at_sign_in_json_element
|
395
|
+
data =
|
396
|
+
{ '@colors' =>
|
397
|
+
[{ '@r' => 255, '@g' => 0, '@b' => 0 },
|
398
|
+
{ '@r' => 0, '@g' => 255, '@b' => 0 },
|
399
|
+
{ '@r' => 0, '@g' => 0, '@b' => 255 }] }
|
400
|
+
|
401
|
+
assert_equal [255, 0, 0], JsonPath.on(data, '$..@r')
|
402
|
+
end
|
403
|
+
|
404
|
+
def test_wildcard
|
405
|
+
assert_equal @object['store']['book'].collect { |e| e['price'] }.compact, JsonPath.on(@object, '$..book[*].price')
|
406
|
+
end
|
407
|
+
|
408
|
+
def test_wildcard_on_intermediary_element
|
409
|
+
assert_equal [1], JsonPath.on({ 'a' => { 'b' => { 'c' => 1 } } }, '$.a..c')
|
410
|
+
end
|
411
|
+
|
412
|
+
def test_wildcard_on_intermediary_element_v2
|
413
|
+
assert_equal [1], JsonPath.on({ 'a' => { 'b' => { 'd' => { 'c' => 1 } } } }, '$.a..c')
|
414
|
+
end
|
415
|
+
|
416
|
+
def test_wildcard_on_intermediary_element_v3
|
417
|
+
assert_equal [1], JsonPath.on({ 'a' => { 'b' => { 'd' => { 'c' => 1 } } } }, '$.a.*..c')
|
418
|
+
end
|
419
|
+
|
420
|
+
def test_wildcard_on_intermediary_element_v4
|
421
|
+
assert_equal [1], JsonPath.on({ 'a' => { 'b' => { 'd' => { 'c' => 1 } } } }, '$.a.*..c')
|
422
|
+
end
|
423
|
+
|
424
|
+
def test_wildcard_on_intermediary_element_v5
|
425
|
+
assert_equal [1], JsonPath.on({ 'a' => { 'b' => { 'c' => 1 } } }, '$.a.*.c')
|
426
|
+
end
|
427
|
+
|
428
|
+
def test_wildcard_on_intermediary_element_v6
|
429
|
+
assert_equal ['red'], JsonPath.new('$.store.*.color').on(@object)
|
430
|
+
end
|
431
|
+
|
432
|
+
def test_wildcard_empty_array
|
433
|
+
object = @object.merge('bicycle' => { 'tire' => [] })
|
434
|
+
assert_equal [], JsonPath.on(object, '$..bicycle.tire[*]')
|
435
|
+
end
|
436
|
+
|
437
|
+
def test_support_filter_by_array_childnode_value
|
438
|
+
assert_equal [@object['store']['book'][3]], JsonPath.new('$..book[?(@.price > 20)]').on(@object)
|
439
|
+
end
|
440
|
+
|
441
|
+
def test_support_filter_by_childnode_value_with_inconsistent_children
|
442
|
+
@object['store']['book'][0] = 'string_instead_of_object'
|
443
|
+
assert_equal [@object['store']['book'][3]], JsonPath.new('$..book[?(@.price > 20)]').on(@object)
|
444
|
+
end
|
445
|
+
|
446
|
+
def test_support_filter_by_childnode_value_and_select_child_key
|
447
|
+
assert_equal [23], JsonPath.new('$..book[?(@.price > 20)].price').on(@object)
|
448
|
+
end
|
449
|
+
|
450
|
+
def test_support_filter_by_childnode_value_over_childnode_and_select_child_key
|
451
|
+
assert_equal ['Osennie Vizity'], JsonPath.new('$..book[?(@.written.year == 1996)].title').on(@object)
|
452
|
+
end
|
453
|
+
|
454
|
+
def test_support_filter_by_object_childnode_value
|
455
|
+
data = {
|
456
|
+
'data' => {
|
457
|
+
'type' => 'users',
|
458
|
+
'id' => '123'
|
459
|
+
}
|
460
|
+
}
|
461
|
+
assert_equal [{ 'type' => 'users', 'id' => '123' }], JsonPath.new("$.data[?(@.type == 'users')]").on(data)
|
462
|
+
assert_equal [], JsonPath.new("$.[?(@.type == 'admins')]").on(data)
|
463
|
+
end
|
464
|
+
|
465
|
+
def test_support_at_sign_in_member_names
|
466
|
+
assert_equal [@object['store']['@id']], JsonPath.new('$.store.@id').on(@object)
|
467
|
+
end
|
468
|
+
|
469
|
+
def test_support_dollar_sign_in_member_names
|
470
|
+
assert_equal [@object['store']['$meta-data']],
|
471
|
+
JsonPath.new('$.store.$meta-data').on(@object)
|
472
|
+
end
|
473
|
+
|
474
|
+
def test_support_underscore_in_member_names
|
475
|
+
assert_equal [@object['store']['_links']],
|
476
|
+
JsonPath.new('$.store._links').on(@object)
|
477
|
+
end
|
478
|
+
|
479
|
+
def test_support_for_umlauts_in_member_names
|
480
|
+
assert_equal [@object['store']['Übermorgen']],
|
481
|
+
JsonPath.new('$.store.Übermorgen').on(@object)
|
482
|
+
end
|
483
|
+
|
484
|
+
def test_support_for_spaces_in_member_name
|
485
|
+
assert_equal [@object['store']['Title Case']],
|
486
|
+
JsonPath.new('$.store.Title Case').on(@object)
|
487
|
+
end
|
488
|
+
|
489
|
+
def test_dig_return_string
|
490
|
+
assert_equal ['asdf'], JsonPath.new("$.store.book..tags[?(@ == 'asdf')]").on(@object)
|
491
|
+
assert_equal [], JsonPath.new("$.store.book..tags[?(@ == 'not_asdf')]").on(@object)
|
492
|
+
end
|
493
|
+
|
494
|
+
def test_slash_in_value
|
495
|
+
data = {
|
496
|
+
'data' => [{
|
497
|
+
'type' => 'mps/awesome'
|
498
|
+
}, {
|
499
|
+
'type' => 'not'
|
500
|
+
}]
|
501
|
+
}
|
502
|
+
assert_equal [{ 'type' => 'mps/awesome' }], JsonPath.new('$.data[?(@.type == "mps/awesome")]').on(data)
|
503
|
+
end
|
504
|
+
|
505
|
+
def test_floating_point_with_precision_marker
|
506
|
+
data = {
|
507
|
+
'data' => {
|
508
|
+
'type' => 0.00001
|
509
|
+
}
|
510
|
+
}
|
511
|
+
assert_equal [{ 'type' => 0.00001 }], JsonPath.new('$.data[?(@.type == 0.00001)]').on(data)
|
512
|
+
end
|
513
|
+
|
514
|
+
def test_digits_only_string
|
515
|
+
data = {
|
516
|
+
'foo' => {
|
517
|
+
'type' => 'users',
|
518
|
+
'id' => '123'
|
519
|
+
}
|
520
|
+
}
|
521
|
+
assert_equal([{ 'type' => 'users', 'id' => '123' }], JsonPath.new("$.foo[?(@.id == '123')]").on(data))
|
522
|
+
end
|
523
|
+
|
524
|
+
def test_digits_only_string_in_array
|
525
|
+
data = {
|
526
|
+
'foo' => [{
|
527
|
+
'type' => 'users',
|
528
|
+
'id' => '123'
|
529
|
+
}, {
|
530
|
+
'type' => 'users',
|
531
|
+
'id' => '321'
|
532
|
+
}]
|
533
|
+
}
|
534
|
+
assert_equal([{ 'type' => 'users', 'id' => '123' }], JsonPath.new("$.foo[?(@.id == '123')]").on(data))
|
535
|
+
end
|
536
|
+
|
537
|
+
def test_at_in_filter
|
538
|
+
jsonld = {
|
539
|
+
'mentions' => [
|
540
|
+
{
|
541
|
+
'name' => 'Delimara Powerplant',
|
542
|
+
'identifier' => 'krzana://took/powerstation/Delimara Powerplant',
|
543
|
+
'@type' => 'Place',
|
544
|
+
'geo' => {
|
545
|
+
'latitude' => 35.83020073454,
|
546
|
+
'longitude' => 14.55602645874
|
547
|
+
}
|
548
|
+
}
|
549
|
+
]
|
550
|
+
}
|
551
|
+
assert_equal(['Place'], JsonPath.new("$..mentions[?(@['@type'] == 'Place')].@type").on(jsonld))
|
552
|
+
end
|
553
|
+
|
554
|
+
def test_dollar_in_filter
|
555
|
+
jsonld = {
|
556
|
+
'mentions' => [
|
557
|
+
{
|
558
|
+
'name' => 'Delimara Powerplant',
|
559
|
+
'identifier' => 'krzana://took/powerstation/Delimara Powerplant',
|
560
|
+
'$type' => 'Place',
|
561
|
+
'geo' => {
|
562
|
+
'latitude' => 35.83020073454,
|
563
|
+
'longitude' => 14.55602645874
|
564
|
+
}
|
565
|
+
}
|
566
|
+
]
|
567
|
+
}
|
568
|
+
assert_equal(['Place'], JsonPath.new("$..mentions[?(@['$type'] == 'Place')].$type").on(jsonld))
|
569
|
+
end
|
570
|
+
|
571
|
+
def test_underscore_in_filter
|
572
|
+
jsonld = {
|
573
|
+
'attributes' => [
|
574
|
+
{
|
575
|
+
'store' => [
|
576
|
+
{ 'with' => 'urn' },
|
577
|
+
{ 'with_underscore' => 'urn:1' }
|
578
|
+
]
|
579
|
+
}
|
580
|
+
]
|
581
|
+
}
|
582
|
+
assert_equal(['urn:1'], JsonPath.new("$.attributes..store[?(@['with_underscore'] == 'urn:1')].with_underscore").on(jsonld))
|
583
|
+
end
|
584
|
+
|
585
|
+
def test_space_in_filter
|
586
|
+
jsonld = {
|
587
|
+
'store' => [
|
588
|
+
{ 'withoutspace' => 'urn' },
|
589
|
+
{ 'with space' => 'urn:1' }
|
590
|
+
]
|
591
|
+
}
|
592
|
+
assert_equal([{ 'with space' => 'urn:1' }], JsonPath.new("$.store[?(@['with space'])]").on(jsonld))
|
593
|
+
end
|
594
|
+
|
595
|
+
def test_at_in_value
|
596
|
+
jsonld = {
|
597
|
+
'mentions' =>
|
598
|
+
{
|
599
|
+
'name' => 'Delimara Powerplant',
|
600
|
+
'identifier' => 'krzana://took/powerstation/Delimara Powerplant',
|
601
|
+
'type' => '@Place',
|
602
|
+
'geo' => {
|
603
|
+
'latitude' => 35.83020073454,
|
604
|
+
'longitude' => 14.55602645874
|
605
|
+
}
|
606
|
+
}
|
607
|
+
}
|
608
|
+
assert_equal(['@Place'], JsonPath.new("$..mentions.type[?(@ == '@Place')]").on(jsonld))
|
609
|
+
end
|
610
|
+
|
611
|
+
def test_parens_in_value
|
612
|
+
data = {
|
613
|
+
'data' => {
|
614
|
+
'number' => '(492) 080-3961'
|
615
|
+
}
|
616
|
+
}
|
617
|
+
assert_equal [{ 'number' => '(492) 080-3961' }], JsonPath.new("$.data[?(@.number == '(492) 080-3961')]").on(data)
|
618
|
+
end
|
619
|
+
|
620
|
+
def test_boolean_parameter_value
|
621
|
+
data = {
|
622
|
+
'data' => [{
|
623
|
+
'isTrue' => true,
|
624
|
+
'name' => 'testname1'
|
625
|
+
}, {
|
626
|
+
'isTrue' => false,
|
627
|
+
'name' => 'testname2'
|
628
|
+
}]
|
629
|
+
}
|
630
|
+
|
631
|
+
# These queries should be equivalent
|
632
|
+
expected = [{ 'isTrue' => true, 'name' => 'testname1' }]
|
633
|
+
assert_equal expected, JsonPath.new('$.data[?(@.isTrue)]').on(data)
|
634
|
+
assert_equal expected, JsonPath.new('$.data[?(@.isTrue==true)]').on(data)
|
635
|
+
assert_equal expected, JsonPath.new('$.data[?(@.isTrue == true)]').on(data)
|
636
|
+
|
637
|
+
# These queries should be equivalent
|
638
|
+
expected = [{ 'isTrue' => false, 'name' => 'testname2' }]
|
639
|
+
assert_equal expected, JsonPath.new('$.data[?(@.isTrue != true)]').on(data)
|
640
|
+
assert_equal expected, JsonPath.new('$.data[?(@.isTrue!=true)]').on(data)
|
641
|
+
assert_equal expected, JsonPath.new('$.data[?(@.isTrue==false)]').on(data)
|
642
|
+
end
|
643
|
+
|
644
|
+
def test_and_operator_with_boolean_parameter_value
|
645
|
+
data = {
|
646
|
+
'data' => [{
|
647
|
+
'hasProperty1' => true,
|
648
|
+
'hasProperty2' => false,
|
649
|
+
'name' => 'testname1'
|
650
|
+
}, {
|
651
|
+
'hasProperty1' => false,
|
652
|
+
'hasProperty2' => true,
|
653
|
+
'name' => 'testname2'
|
654
|
+
}, {
|
655
|
+
'hasProperty1' => true,
|
656
|
+
'hasProperty2' => true,
|
657
|
+
'name' => 'testname3'
|
658
|
+
}]
|
659
|
+
}
|
660
|
+
assert_equal ['testname3'], JsonPath.new('$.data[?(@.hasProperty1 && @.hasProperty2)].name').on(data)
|
661
|
+
end
|
662
|
+
|
663
|
+
def test_regex_simple
|
664
|
+
assert_equal %w[asdf asdf2], JsonPath.new('$.store.book..tags[?(@ =~ /asdf/)]').on(@object)
|
665
|
+
assert_equal %w[asdf asdf2], JsonPath.new('$.store.book..tags[?(@=~/asdf/)]').on(@object)
|
666
|
+
end
|
667
|
+
|
668
|
+
def test_regex_simple_miss
|
669
|
+
assert_equal [], JsonPath.new('$.store.book..tags[?(@ =~ /wut/)]').on(@object)
|
670
|
+
end
|
671
|
+
|
672
|
+
def test_regex_r
|
673
|
+
assert_equal %w[asdf asdf2], JsonPath.new('$.store.book..tags[?(@ =~ %r{asdf})]').on(@object)
|
674
|
+
end
|
675
|
+
|
676
|
+
def test_regex_flags
|
677
|
+
assert_equal [
|
678
|
+
@object['store']['book'][2],
|
679
|
+
@object['store']['book'][4],
|
680
|
+
@object['store']['book'][5],
|
681
|
+
@object['store']['book'][6]
|
682
|
+
], JsonPath.new('$..book[?(@.author =~ /herman|lukyanenko/i)]').on(@object)
|
683
|
+
end
|
684
|
+
|
685
|
+
def test_regex_error
|
686
|
+
assert_raises ArgumentError do
|
687
|
+
JsonPath.new('$.store.book..tags[?(@ =~ asdf)]').on(@object)
|
688
|
+
end
|
689
|
+
end
|
690
|
+
|
691
|
+
def test_regression_1
|
692
|
+
json = {
|
693
|
+
ok: true,
|
694
|
+
channels: [
|
695
|
+
{
|
696
|
+
id: 'C09C5GYHF',
|
697
|
+
name: 'general'
|
698
|
+
},
|
699
|
+
{
|
700
|
+
id: 'C09C598QL',
|
701
|
+
name: 'random'
|
702
|
+
}
|
703
|
+
]
|
704
|
+
}.to_json
|
705
|
+
|
706
|
+
assert_equal 'C09C5GYHF', JsonPath.on(json, "$..channels[?(@.name == 'general')].id")[0]
|
707
|
+
end
|
708
|
+
|
709
|
+
def test_regression_2
|
710
|
+
json = {
|
711
|
+
ok: true,
|
712
|
+
channels: [
|
713
|
+
{
|
714
|
+
id: 'C09C5GYHF',
|
715
|
+
name: 'general',
|
716
|
+
is_archived: false
|
717
|
+
},
|
718
|
+
{
|
719
|
+
id: 'C09C598QL',
|
720
|
+
name: 'random',
|
721
|
+
is_archived: true
|
722
|
+
}
|
723
|
+
]
|
724
|
+
}.to_json
|
725
|
+
|
726
|
+
assert_equal 'C09C5GYHF', JsonPath.on(json, '$..channels[?(@.is_archived == false)].id')[0]
|
727
|
+
end
|
728
|
+
|
729
|
+
def test_regression_3
|
730
|
+
json = {
|
731
|
+
ok: true,
|
732
|
+
channels: [
|
733
|
+
{
|
734
|
+
id: 'C09C5GYHF',
|
735
|
+
name: 'general',
|
736
|
+
is_archived: false
|
737
|
+
},
|
738
|
+
{
|
739
|
+
id: 'C09C598QL',
|
740
|
+
name: 'random',
|
741
|
+
is_archived: true
|
742
|
+
}
|
743
|
+
]
|
744
|
+
}.to_json
|
745
|
+
|
746
|
+
assert_equal 'C09C598QL', JsonPath.on(json, '$..channels[?(@.is_archived)].id')[0]
|
747
|
+
end
|
748
|
+
|
749
|
+
def test_regression_4
|
750
|
+
json = {
|
751
|
+
ok: true,
|
752
|
+
channels: [
|
753
|
+
{
|
754
|
+
id: 'C09C5GYHF',
|
755
|
+
name: 'general',
|
756
|
+
is_archived: false
|
757
|
+
},
|
758
|
+
{
|
759
|
+
id: 'C09C598QL',
|
760
|
+
name: 'random',
|
761
|
+
is_archived: true
|
762
|
+
}
|
763
|
+
]
|
764
|
+
}.to_json
|
765
|
+
|
766
|
+
assert_equal ['C09C5GYHF'], JsonPath.on(json, "$..channels[?(@.name == 'general')].id")
|
767
|
+
end
|
768
|
+
|
769
|
+
def test_regression_5
|
770
|
+
json = {
|
771
|
+
ok: true,
|
772
|
+
channels: [
|
773
|
+
{
|
774
|
+
id: 'C09C5GYHF',
|
775
|
+
name: 'general',
|
776
|
+
is_archived: 'false'
|
777
|
+
},
|
778
|
+
{
|
779
|
+
id: 'C09C598QL',
|
780
|
+
name: 'random',
|
781
|
+
is_archived: true
|
782
|
+
}
|
783
|
+
]
|
784
|
+
}.to_json
|
785
|
+
|
786
|
+
assert_equal 'C09C5GYHF', JsonPath.on(json, "$..channels[?(@.is_archived == 'false')].id")[0]
|
787
|
+
end
|
788
|
+
|
789
|
+
def test_quote
|
790
|
+
json = {
|
791
|
+
channels: [
|
792
|
+
{
|
793
|
+
name: "King's Speech"
|
794
|
+
}
|
795
|
+
]
|
796
|
+
}.to_json
|
797
|
+
|
798
|
+
assert_equal [{ 'name' => "King\'s Speech" }], JsonPath.on(json, "$..channels[?(@.name == 'King\'s Speech')]")
|
799
|
+
end
|
800
|
+
|
801
|
+
def test_curly_brackets
|
802
|
+
data = {
|
803
|
+
'{data}' => 'data'
|
804
|
+
}
|
805
|
+
assert_equal ['data'], JsonPath.new('$.{data}').on(data)
|
806
|
+
end
|
807
|
+
|
808
|
+
def test_symbolize
|
809
|
+
data = '
|
810
|
+
{
|
811
|
+
"store": {
|
812
|
+
"bicycle": {
|
813
|
+
"price": 19.95,
|
814
|
+
"color": "red"
|
815
|
+
},
|
816
|
+
"book": [
|
817
|
+
{
|
818
|
+
"price": 8.95,
|
819
|
+
"category": "reference",
|
820
|
+
"title": "Sayings of the Century",
|
821
|
+
"author": "Nigel Rees"
|
822
|
+
},
|
823
|
+
{
|
824
|
+
"price": 12.99,
|
825
|
+
"category": "fiction",
|
826
|
+
"title": "Sword of Honour",
|
827
|
+
"author": "Evelyn Waugh"
|
828
|
+
},
|
829
|
+
{
|
830
|
+
"price": 8.99,
|
831
|
+
"category": "fiction",
|
832
|
+
"isbn": "0-553-21311-3",
|
833
|
+
"title": "Moby Dick",
|
834
|
+
"author": "Herman Melville",
|
835
|
+
"color": "blue"
|
836
|
+
},
|
837
|
+
{
|
838
|
+
"price": 22.99,
|
839
|
+
"category": "fiction",
|
840
|
+
"isbn": "0-395-19395-8",
|
841
|
+
"title": "The Lord of the Rings",
|
842
|
+
"author": "Tolkien"
|
843
|
+
}
|
844
|
+
]
|
845
|
+
}
|
846
|
+
}
|
847
|
+
'
|
848
|
+
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)
|
849
|
+
end
|
850
|
+
|
851
|
+
def test_changed
|
852
|
+
json =
|
853
|
+
{
|
854
|
+
'snapshot' => {
|
855
|
+
'objects' => {
|
856
|
+
'whatever' => [
|
857
|
+
{
|
858
|
+
'column' => {
|
859
|
+
'name' => 'ASSOCIATE_FLAG',
|
860
|
+
'nullable' => true
|
861
|
+
}
|
862
|
+
},
|
863
|
+
{
|
864
|
+
'column' => {
|
865
|
+
'name' => 'AUTHOR',
|
866
|
+
'nullable' => false
|
867
|
+
}
|
868
|
+
}
|
869
|
+
]
|
870
|
+
}
|
871
|
+
}
|
872
|
+
}
|
873
|
+
assert_equal true, JsonPath.on(json, "$..column[?(@.name == 'ASSOCIATE_FLAG')].nullable")[0]
|
874
|
+
end
|
875
|
+
|
876
|
+
def test_another
|
877
|
+
json = {
|
878
|
+
initial: true,
|
879
|
+
not: true
|
880
|
+
}.to_json
|
881
|
+
assert_equal [{ 'initial' => true, 'not' => true }], JsonPath.on(json, '$.[?(@.initial == true)]')
|
882
|
+
json = {
|
883
|
+
initial: false,
|
884
|
+
not: true
|
885
|
+
}.to_json
|
886
|
+
assert_equal [], JsonPath.on(json, '$.initial[?(@)]')
|
887
|
+
assert_equal [], JsonPath.on(json, '$.[?(@.initial == true)]')
|
888
|
+
assert_equal [{ 'initial' => false, 'not' => true }], JsonPath.on(json, '$.[?(@.initial == false)]')
|
889
|
+
json = {
|
890
|
+
initial: 'false',
|
891
|
+
not: true
|
892
|
+
}.to_json
|
893
|
+
assert_equal [{ 'initial' => 'false', 'not' => true }], JsonPath.on(json, "$.[?(@.initial == 'false')]")
|
894
|
+
assert_equal [], JsonPath.on(json, '$.[?(@.initial == false)]')
|
895
|
+
end
|
896
|
+
|
897
|
+
def test_hanging
|
898
|
+
json = { initial: true }.to_json
|
899
|
+
success_path = '$.initial'
|
900
|
+
assert_equal [true], JsonPath.on(json, success_path)
|
901
|
+
broken_path = "$.initial\n"
|
902
|
+
assert_equal [true], JsonPath.on(json, broken_path)
|
903
|
+
end
|
904
|
+
|
905
|
+
def test_complex_nested_grouping
|
906
|
+
path = "$..book[?((@['author'] == 'Evelyn Waugh' || @['author'] == 'Herman Melville') && (@['price'] == 33 || @['price'] == 9))]"
|
907
|
+
assert_equal [@object['store']['book'][2]], JsonPath.new(path).on(@object)
|
908
|
+
end
|
909
|
+
|
910
|
+
def test_nested_with_unknown_key
|
911
|
+
path = "$..[?(@.price == 9 || @.price == 33)].title"
|
912
|
+
assert_equal ["Sayings of the Century", "Moby Dick", "Sayings of the Century", "Moby Dick"], JsonPath.new(path).on(@object)
|
913
|
+
end
|
914
|
+
|
915
|
+
def test_nested_with_unknown_key_filtered_array
|
916
|
+
path = "$..[?(@['price'] == 9 || @['price'] == 33)].title"
|
917
|
+
assert_equal ["Sayings of the Century", "Moby Dick", "Sayings of the Century", "Moby Dick"], JsonPath.new(path).on(@object)
|
918
|
+
end
|
919
|
+
|
920
|
+
def test_runtime_error_frozen_string
|
921
|
+
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')
|
922
|
+
json = '
|
923
|
+
{
|
924
|
+
"test": "something"
|
925
|
+
}
|
926
|
+
'.to_json
|
927
|
+
assert_raises(ArgumentError, "RuntimeError: character '|' not supported in query") do
|
928
|
+
JsonPath.on(json, '$.description|title')
|
929
|
+
end
|
930
|
+
end
|
931
|
+
|
932
|
+
def test_delete_more_items
|
933
|
+
a = { 'itemList' =>
|
934
|
+
[{ 'alfa' => 'beta1' },
|
935
|
+
{ 'alfa' => 'beta2' },
|
936
|
+
{ 'alfa' => 'beta3' },
|
937
|
+
{ 'alfa' => 'beta4' },
|
938
|
+
{ 'alfa' => 'beta5' },
|
939
|
+
{ 'alfa' => 'beta6' },
|
940
|
+
{ 'alfa' => 'beta7' },
|
941
|
+
{ 'alfa' => 'beta8' },
|
942
|
+
{ 'alfa' => 'beta9' },
|
943
|
+
{ 'alfa' => 'beta10' },
|
944
|
+
{ 'alfa' => 'beta11' },
|
945
|
+
{ 'alfa' => 'beta12' }] }
|
946
|
+
expected = { 'itemList' => [{ 'alfa' => 'beta1' }] }
|
947
|
+
assert_equal expected, JsonPath.for(a.to_json).delete('$.itemList[1:12:1]').to_hash
|
948
|
+
end
|
949
|
+
|
950
|
+
def test_delete_more_items_with_stepping
|
951
|
+
a = { 'itemList' =>
|
952
|
+
[{ 'alfa' => 'beta1' },
|
953
|
+
{ 'alfa' => 'beta2' },
|
954
|
+
{ 'alfa' => 'beta3' },
|
955
|
+
{ 'alfa' => 'beta4' },
|
956
|
+
{ 'alfa' => 'beta5' },
|
957
|
+
{ 'alfa' => 'beta6' },
|
958
|
+
{ 'alfa' => 'beta7' },
|
959
|
+
{ 'alfa' => 'beta8' },
|
960
|
+
{ 'alfa' => 'beta9' },
|
961
|
+
{ 'alfa' => 'beta10' },
|
962
|
+
{ 'alfa' => 'beta11' },
|
963
|
+
{ 'alfa' => 'beta12' }] }
|
964
|
+
expected = { 'itemList' =>
|
965
|
+
[{ 'alfa' => 'beta1' },
|
966
|
+
{ 'alfa' => 'beta3' },
|
967
|
+
{ 'alfa' => 'beta5' },
|
968
|
+
{ 'alfa' => 'beta7' },
|
969
|
+
{ 'alfa' => 'beta8' },
|
970
|
+
{ 'alfa' => 'beta9' },
|
971
|
+
{ 'alfa' => 'beta10' },
|
972
|
+
{ 'alfa' => 'beta11' },
|
973
|
+
{ 'alfa' => 'beta12' }] }
|
974
|
+
assert_equal expected, JsonPath.for(a.to_json).delete('$.itemList[1:6:2]').to_hash
|
975
|
+
end
|
976
|
+
|
977
|
+
def test_nested_values
|
978
|
+
json = '
|
979
|
+
{
|
980
|
+
"phoneNumbers": [
|
981
|
+
[{
|
982
|
+
"type" : "iPhone",
|
983
|
+
"number": "0123-4567-8888"
|
984
|
+
}],
|
985
|
+
[{
|
986
|
+
"type" : "home",
|
987
|
+
"number": "0123-4567-8910"
|
988
|
+
}]
|
989
|
+
]
|
990
|
+
}
|
991
|
+
'.to_json
|
992
|
+
assert_equal [[{ 'type' => 'home', 'number' => '0123-4567-8910' }]], JsonPath.on(json, "$.phoneNumbers[?(@[0].type == 'home')]")
|
993
|
+
assert_equal [], JsonPath.on(json, "$.phoneNumbers[?(@[2].type == 'home')]")
|
994
|
+
json = '
|
995
|
+
{
|
996
|
+
"phoneNumbers":
|
997
|
+
{
|
998
|
+
"type" : "iPhone",
|
999
|
+
"number": "0123-4567-8888"
|
1000
|
+
}
|
1001
|
+
}
|
1002
|
+
'.to_json
|
1003
|
+
assert_equal [], JsonPath.on(json, "$.phoneNumbers[?(@[0].type == 'home')]")
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
def test_selecting_multiple_keys_on_hash
|
1007
|
+
json = '
|
1008
|
+
{
|
1009
|
+
"category": "reference",
|
1010
|
+
"author": "Nigel Rees",
|
1011
|
+
"title": "Sayings of the Century",
|
1012
|
+
"price": 8.95
|
1013
|
+
}
|
1014
|
+
'.to_json
|
1015
|
+
assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, '$.(category,author)')
|
1016
|
+
end
|
1017
|
+
|
1018
|
+
def test_selecting_multiple_keys_on_sub_hash
|
1019
|
+
skip("Failing as the semantics of .(x,y) is unclear")
|
1020
|
+
json = '
|
1021
|
+
{
|
1022
|
+
"book": {
|
1023
|
+
"category": "reference",
|
1024
|
+
"author": "Nigel Rees",
|
1025
|
+
"title": "Sayings of the Century",
|
1026
|
+
"price": 8.95
|
1027
|
+
}
|
1028
|
+
}
|
1029
|
+
'.to_json
|
1030
|
+
assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, '$.book.(category,author)')
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
def test_selecting_multiple_keys_on_array
|
1034
|
+
json = '
|
1035
|
+
{
|
1036
|
+
"store": {
|
1037
|
+
"book": [
|
1038
|
+
{
|
1039
|
+
"category": "reference",
|
1040
|
+
"author": "Nigel Rees",
|
1041
|
+
"title": "Sayings of the Century",
|
1042
|
+
"price": 8.95
|
1043
|
+
},
|
1044
|
+
{
|
1045
|
+
"category": "fiction",
|
1046
|
+
"author": "Evelyn Waugh",
|
1047
|
+
"title": "Sword of Honour",
|
1048
|
+
"price": 12.99
|
1049
|
+
}
|
1050
|
+
]
|
1051
|
+
}
|
1052
|
+
}
|
1053
|
+
'.to_json
|
1054
|
+
|
1055
|
+
assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }, { 'category' => 'fiction', 'author' => 'Evelyn Waugh' }], JsonPath.on(json, '$.store.book[*](category,author)')
|
1056
|
+
end
|
1057
|
+
|
1058
|
+
def test_selecting_multiple_keys_on_array_with_filter
|
1059
|
+
json = '
|
1060
|
+
{
|
1061
|
+
"store": {
|
1062
|
+
"book": [
|
1063
|
+
{
|
1064
|
+
"category": "reference",
|
1065
|
+
"author": "Nigel Rees",
|
1066
|
+
"title": "Sayings of the Century",
|
1067
|
+
"price": 8.95
|
1068
|
+
},
|
1069
|
+
{
|
1070
|
+
"category": "fiction",
|
1071
|
+
"author": "Evelyn Waugh",
|
1072
|
+
"title": "Sword of Honour",
|
1073
|
+
"price": 12.99
|
1074
|
+
}
|
1075
|
+
]
|
1076
|
+
}
|
1077
|
+
}
|
1078
|
+
'.to_json
|
1079
|
+
|
1080
|
+
assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, "$.store.book[?(@['price'] == 8.95)](category,author)")
|
1081
|
+
assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, "$.store.book[?(@['price'] == 8.95)]( category, author )")
|
1082
|
+
end
|
1083
|
+
|
1084
|
+
def test_selecting_multiple_keys_with_filter_with_space_in_catergory
|
1085
|
+
json = '
|
1086
|
+
{
|
1087
|
+
"store": {
|
1088
|
+
"book": [
|
1089
|
+
{
|
1090
|
+
"cate gory": "reference",
|
1091
|
+
"author": "Nigel Rees",
|
1092
|
+
"title": "Sayings of the Century",
|
1093
|
+
"price": 8.95
|
1094
|
+
},
|
1095
|
+
{
|
1096
|
+
"cate gory": "fiction",
|
1097
|
+
"author": "Evelyn Waugh",
|
1098
|
+
"title": "Sword of Honour",
|
1099
|
+
"price": 12.99
|
1100
|
+
}
|
1101
|
+
]
|
1102
|
+
}
|
1103
|
+
}
|
1104
|
+
'.to_json
|
1105
|
+
|
1106
|
+
assert_equal [{ 'cate gory' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, "$.store.book[?(@['price'] == 8.95)]( cate gory, author )")
|
1107
|
+
end
|
1108
|
+
|
1109
|
+
def test_use_symbol_opt
|
1110
|
+
json = {
|
1111
|
+
store: {
|
1112
|
+
book: [
|
1113
|
+
{
|
1114
|
+
category: "reference",
|
1115
|
+
author: "Nigel Rees",
|
1116
|
+
title: "Sayings of the Century",
|
1117
|
+
price: 8.95
|
1118
|
+
},
|
1119
|
+
{
|
1120
|
+
category: "fiction",
|
1121
|
+
author: "Evelyn Waugh",
|
1122
|
+
title: "Sword of Honour",
|
1123
|
+
price: 12.99
|
1124
|
+
}
|
1125
|
+
]
|
1126
|
+
}
|
1127
|
+
}
|
1128
|
+
on = ->(path){ JsonPath.on(json, path, use_symbols: true) }
|
1129
|
+
assert_equal ['reference', 'fiction'], on.("$.store.book[*].category")
|
1130
|
+
assert_equal ['reference', 'fiction'], on.("$..category")
|
1131
|
+
assert_equal ['reference'], on.("$.store.book[?(@['price'] == 8.95)].category")
|
1132
|
+
assert_equal [{'category' => 'reference'}], on.("$.store.book[?(@['price'] == 8.95)](category)")
|
1133
|
+
end
|
1134
|
+
|
1135
|
+
def test_object_method_send
|
1136
|
+
j = {height: 5, hash: "some_hash"}.to_json
|
1137
|
+
hs = JsonPath.new "$..send"
|
1138
|
+
assert_equal([], hs.on(j))
|
1139
|
+
hs = JsonPath.new "$..hash"
|
1140
|
+
assert_equal(["some_hash"], hs.on(j))
|
1141
|
+
hs = JsonPath.new "$..send"
|
1142
|
+
assert_equal([], hs.on(j))
|
1143
|
+
j = {height: 5, send: "should_still_work"}.to_json
|
1144
|
+
hs = JsonPath.new "$..send"
|
1145
|
+
assert_equal(['should_still_work'], hs.on(j))
|
1146
|
+
end
|
1147
|
+
|
1148
|
+
def test_index_access_by_number
|
1149
|
+
data = {
|
1150
|
+
'1': 'foo'
|
1151
|
+
}
|
1152
|
+
assert_equal ['foo'], JsonPath.new('$.1').on(data.to_json)
|
1153
|
+
end
|
1154
|
+
|
1155
|
+
def test_behavior_on_null_and_missing
|
1156
|
+
data = {
|
1157
|
+
"foo" => nil,
|
1158
|
+
"bar" => {
|
1159
|
+
"baz" => nil
|
1160
|
+
},
|
1161
|
+
"bars" => [
|
1162
|
+
{ "foo" => 12 },
|
1163
|
+
{ "foo" => nil },
|
1164
|
+
{ }
|
1165
|
+
]
|
1166
|
+
}
|
1167
|
+
assert_equal [nil], JsonPath.new('$.foo').on(data)
|
1168
|
+
assert_equal [nil], JsonPath.new('$.bar.baz').on(data)
|
1169
|
+
assert_equal [], JsonPath.new('$.baz').on(data)
|
1170
|
+
assert_equal [], JsonPath.new('$.bar.foo').on(data)
|
1171
|
+
assert_equal [12, nil], JsonPath.new('$.bars[*].foo').on(data)
|
1172
|
+
end
|
1173
|
+
|
1174
|
+
def test_default_path_leaf_to_null_opt
|
1175
|
+
data = {
|
1176
|
+
"foo" => nil,
|
1177
|
+
"bar" => {
|
1178
|
+
"baz" => nil
|
1179
|
+
},
|
1180
|
+
"bars" => [
|
1181
|
+
{ "foo" => 12 },
|
1182
|
+
{ "foo" => nil },
|
1183
|
+
{ }
|
1184
|
+
]
|
1185
|
+
}
|
1186
|
+
assert_equal [nil], JsonPath.new('$.foo', default_path_leaf_to_null: true).on(data)
|
1187
|
+
assert_equal [nil], JsonPath.new('$.bar.baz', default_path_leaf_to_null: true).on(data)
|
1188
|
+
assert_equal [nil], JsonPath.new('$.baz', default_path_leaf_to_null: true).on(data)
|
1189
|
+
assert_equal [nil], JsonPath.new('$.bar.foo', default_path_leaf_to_null: true).on(data)
|
1190
|
+
assert_equal [12, nil, nil], JsonPath.new('$.bars[*].foo', default_path_leaf_to_null: true).on(data)
|
1191
|
+
end
|
1192
|
+
|
1193
|
+
def test_raise_max_nesting_error
|
1194
|
+
json = {
|
1195
|
+
a: {
|
1196
|
+
b: {
|
1197
|
+
c: {
|
1198
|
+
}
|
1199
|
+
}
|
1200
|
+
}
|
1201
|
+
}.to_json
|
1202
|
+
|
1203
|
+
assert_raises(MultiJson::ParseError) { JsonPath.new('$.a', max_nesting: 1).on(json) }
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
def test_linefeed_in_path_error
|
1207
|
+
assert_raises(ArgumentError) { JsonPath.new("$.store\n.book") }
|
1208
|
+
end
|
1209
|
+
|
1210
|
+
def test_with_max_nesting_false
|
1211
|
+
json = {
|
1212
|
+
a: {
|
1213
|
+
b: {
|
1214
|
+
c: {
|
1215
|
+
}
|
1216
|
+
}
|
1217
|
+
}
|
1218
|
+
}.to_json
|
1219
|
+
|
1220
|
+
assert_equal [{}], JsonPath.new('$.a.b.c', max_nesting: false).on(json)
|
1221
|
+
end
|
1222
|
+
|
1223
|
+
def test_initialize_with_max_nesting_exceeding_limit
|
1224
|
+
json = {
|
1225
|
+
a: {
|
1226
|
+
b: {
|
1227
|
+
c: {
|
1228
|
+
}
|
1229
|
+
}
|
1230
|
+
}
|
1231
|
+
}.to_json
|
1232
|
+
|
1233
|
+
json_obj = JsonPath.new('$.a.b.c', max_nesting: 105)
|
1234
|
+
assert_equal [{}], json_obj.on(json)
|
1235
|
+
assert_equal false, json_obj.instance_variable_get(:@opts)[:max_nesting]
|
1236
|
+
end
|
1237
|
+
|
1238
|
+
def test_initialize_without_max_nesting_exceeding_limit
|
1239
|
+
json_obj = JsonPath.new('$.a.b.c', max_nesting: 90)
|
1240
|
+
assert_equal 90, json_obj.instance_variable_get(:@opts)[:max_nesting]
|
1241
|
+
end
|
1242
|
+
|
1243
|
+
def test_initialize_with_max_nesting_false_limit
|
1244
|
+
json_obj = JsonPath.new('$.a.b.c', max_nesting: false)
|
1245
|
+
assert_equal false, json_obj.instance_variable_get(:@opts)[:max_nesting]
|
1246
|
+
end
|
1247
|
+
|
1248
|
+
def example_object
|
1249
|
+
{ 'store' => {
|
1250
|
+
'book' => [
|
1251
|
+
{ 'category' => 'reference',
|
1252
|
+
'author' => 'Nigel Rees',
|
1253
|
+
'title' => 'Sayings of the Century',
|
1254
|
+
'price' => 9,
|
1255
|
+
'tags' => %w[asdf asdf2],
|
1256
|
+
'year published' => 1999 },
|
1257
|
+
{ 'category' => 'fiction',
|
1258
|
+
'author' => 'Evelyn Waugh',
|
1259
|
+
'title' => 'Sword of Honour',
|
1260
|
+
'price' => 13,
|
1261
|
+
'year published' => 1952 },
|
1262
|
+
{ 'category' => 'fiction',
|
1263
|
+
'author' => 'Herman Melville',
|
1264
|
+
'title' => 'Moby Dick',
|
1265
|
+
'isbn' => '0-553-21311-3',
|
1266
|
+
'price' => 9 },
|
1267
|
+
{ 'category' => 'fiction',
|
1268
|
+
'author' => 'J. R. R. Tolkien',
|
1269
|
+
'title' => 'The Lord of the Rings',
|
1270
|
+
'isbn' => '0-395-19395-8',
|
1271
|
+
'price' => 23 },
|
1272
|
+
{ 'category' => 'russian_fiction',
|
1273
|
+
'author' => 'Lukyanenko',
|
1274
|
+
'title' => 'Imperatory Illuziy',
|
1275
|
+
'written' => {
|
1276
|
+
'year' => 1995
|
1277
|
+
} },
|
1278
|
+
{ 'category' => 'russian_fiction',
|
1279
|
+
'author' => 'Lukyanenko',
|
1280
|
+
'title' => 'Osennie Vizity',
|
1281
|
+
'written' => {
|
1282
|
+
'year' => 1996
|
1283
|
+
} },
|
1284
|
+
{ 'category' => 'russian_fiction',
|
1285
|
+
'author' => 'Lukyanenko',
|
1286
|
+
'title' => 'Ne vremya dlya drakonov',
|
1287
|
+
'written' => {
|
1288
|
+
'year' => 1997
|
1289
|
+
} }
|
1290
|
+
],
|
1291
|
+
'bicycle' => {
|
1292
|
+
'color' => 'red',
|
1293
|
+
'price' => 20,
|
1294
|
+
'catalogue_number' => 123_45,
|
1295
|
+
'single-speed' => 'no',
|
1296
|
+
'2seater' => 'yes',
|
1297
|
+
'make:model' => 'Zippy Sweetwheeler'
|
1298
|
+
},
|
1299
|
+
'@id' => 'http://example.org/store/42',
|
1300
|
+
'$meta-data' => 'whatevs',
|
1301
|
+
'Übermorgen' => 'The day after tomorrow',
|
1302
|
+
'Title Case' => 'A title case string',
|
1303
|
+
'_links' => { 'self' => {} }
|
1304
|
+
} }
|
1305
|
+
end
|
1306
|
+
|
1307
|
+
def test_fetch_all_path
|
1308
|
+
data = {
|
1309
|
+
"foo" => nil,
|
1310
|
+
"bar" => {
|
1311
|
+
"baz" => nil
|
1312
|
+
},
|
1313
|
+
"bars" => [
|
1314
|
+
{ "foo" => 12 },
|
1315
|
+
{ "foo" => nil },
|
1316
|
+
{ }
|
1317
|
+
]
|
1318
|
+
}
|
1319
|
+
assert_equal ["$", "$.foo", "$.bar", "$.bar.baz", "$.bars", "$.bars[0].foo", "$.bars[0]", "$.bars[1].foo", "$.bars[1]", "$.bars[2]"], JsonPath.fetch_all_path(data)
|
1320
|
+
end
|
1321
|
+
|
1322
|
+
|
1323
|
+
def test_extractore_with_dollar_key
|
1324
|
+
json = {"test" => {"$" =>"success", "a" => "123"}}
|
1325
|
+
assert_equal ["success"], JsonPath.on(json, "$.test.$")
|
1326
|
+
assert_equal ["123"], JsonPath.on(json, "$.test.a")
|
1327
|
+
end
|
1328
|
+
|
1329
|
+
def test_symbolize_key
|
1330
|
+
data = { "store" => { "book" => [{"category" => "reference"}]}}
|
1331
|
+
assert_equal [{"category": "reference"}], JsonPath.new('$..book[0]', symbolize_keys: true).on(data)
|
1332
|
+
assert_equal [{"category": "reference"}], JsonPath.new('$..book[0]').on(data, symbolize_keys: true)
|
1333
|
+
end
|
1334
|
+
end
|