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