1 | var assert = require('assert');
|
2 | var jp = require('../');
|
3 |
|
4 | var data = require('./data/store.json');
|
5 |
|
6 | suite('query', function() {
|
7 |
|
8 | test('first-level member', function() {
|
9 | var results = jp.nodes(data, '$.store');
|
10 | assert.deepEqual(results, [ { path: ['$', 'store'], value: data.store } ]);
|
11 | });
|
12 |
|
13 | test('authors of all books in the store', function() {
|
14 | var results = jp.nodes(data, '$.store.book[*].author');
|
15 | assert.deepEqual(results, [
|
16 | { path: ['$', 'store', 'book', 0, 'author'], value: 'Nigel Rees' },
|
17 | { path: ['$', 'store', 'book', 1, 'author'], value: 'Evelyn Waugh' },
|
18 | { path: ['$', 'store', 'book', 2, 'author'], value: 'Herman Melville' },
|
19 | { path: ['$', 'store', 'book', 3, 'author'], value: 'J. R. R. Tolkien' }
|
20 | ]);
|
21 | });
|
22 |
|
23 | test('all authors', function() {
|
24 | var results = jp.nodes(data, '$..author');
|
25 | assert.deepEqual(results, [
|
26 | { path: ['$', 'store', 'book', 0, 'author'], value: 'Nigel Rees' },
|
27 | { path: ['$', 'store', 'book', 1, 'author'], value: 'Evelyn Waugh' },
|
28 | { path: ['$', 'store', 'book', 2, 'author'], value: 'Herman Melville' },
|
29 | { path: ['$', 'store', 'book', 3, 'author'], value: 'J. R. R. Tolkien' }
|
30 | ]);
|
31 | });
|
32 |
|
33 | test('all authors via subscript descendant string literal', function() {
|
34 | var results = jp.nodes(data, "$..['author']");
|
35 | assert.deepEqual(results, [
|
36 | { path: ['$', 'store', 'book', 0, 'author'], value: 'Nigel Rees' },
|
37 | { path: ['$', 'store', 'book', 1, 'author'], value: 'Evelyn Waugh' },
|
38 | { path: ['$', 'store', 'book', 2, 'author'], value: 'Herman Melville' },
|
39 | { path: ['$', 'store', 'book', 3, 'author'], value: 'J. R. R. Tolkien' }
|
40 | ]);
|
41 | });
|
42 |
|
43 | test('all things in store', function() {
|
44 | var results = jp.nodes(data, '$.store.*');
|
45 | assert.deepEqual(results, [
|
46 | { path: ['$', 'store', 'book'], value: data.store.book },
|
47 | { path: ['$', 'store', 'bicycle'], value: data.store.bicycle }
|
48 | ]);
|
49 | });
|
50 |
|
51 | test('price of everything in the store', function() {
|
52 | var results = jp.nodes(data, '$.store..price');
|
53 | assert.deepEqual(results, [
|
54 | { path: ['$', 'store', 'book', 0, 'price'], value: 8.95 },
|
55 | { path: ['$', 'store', 'book', 1, 'price'], value: 12.99 },
|
56 | { path: ['$', 'store', 'book', 2, 'price'], value: 8.99 },
|
57 | { path: ['$', 'store', 'book', 3, 'price'], value: 22.99 },
|
58 | { path: ['$', 'store', 'bicycle', 'price'], value: 19.95 }
|
59 | ]);
|
60 | });
|
61 |
|
62 | test('last book in order via expression', function() {
|
63 | var results = jp.nodes(data, '$..book[(@.length-1)]');
|
64 | assert.deepEqual(results, [ { path: ['$', 'store', 'book', 3], value: data.store.book[3] }]);
|
65 | });
|
66 |
|
67 | test('first two books via union', function() {
|
68 | var results = jp.nodes(data, '$..book[0,1]');
|
69 | assert.deepEqual(results, [
|
70 | { path: ['$', 'store', 'book', 0], value: data.store.book[0] },
|
71 | { path: ['$', 'store', 'book', 1], value: data.store.book[1] }
|
72 | ]);
|
73 | });
|
74 |
|
75 | test('first two books via slice', function() {
|
76 | var results = jp.nodes(data, '$..book[0:2]');
|
77 | assert.deepEqual(results, [
|
78 | { path: ['$', 'store', 'book', 0], value: data.store.book[0] },
|
79 | { path: ['$', 'store', 'book', 1], value: data.store.book[1] }
|
80 | ]);
|
81 | });
|
82 |
|
83 | test('filter all books with isbn number', function() {
|
84 | var results = jp.nodes(data, '$..book[?(@.isbn)]');
|
85 | assert.deepEqual(results, [
|
86 | { path: ['$', 'store', 'book', 2], value: data.store.book[2] },
|
87 | { path: ['$', 'store', 'book', 3], value: data.store.book[3] }
|
88 | ]);
|
89 | });
|
90 |
|
91 | test('filter all books with a price less than 10', function() {
|
92 | var results = jp.nodes(data, '$..book[?(@.price<10)]');
|
93 | assert.deepEqual(results, [
|
94 | { path: ['$', 'store', 'book', 0], value: data.store.book[0] },
|
95 | { path: ['$', 'store', 'book', 2], value: data.store.book[2] }
|
96 | ]);
|
97 | });
|
98 |
|
99 | test('first ten of all elements', function() {
|
100 | var results = jp.nodes(data, '$..*', 10);
|
101 | assert.deepEqual(results, [
|
102 | { path: [ '$', 'store' ], value: data.store },
|
103 | { path: [ '$', 'store', 'book' ], value: data.store.book },
|
104 | { path: [ '$', 'store', 'bicycle' ], value: data.store.bicycle },
|
105 | { path: [ '$', 'store', 'book', 0 ], value: data.store.book[0] },
|
106 | { path: [ '$', 'store', 'book', 1 ], value: data.store.book[1] },
|
107 | { path: [ '$', 'store', 'book', 2 ], value: data.store.book[2] },
|
108 | { path: [ '$', 'store', 'book', 3 ], value: data.store.book[3] },
|
109 | { path: [ '$', 'store', 'book', 0, 'category' ], value: 'reference' },
|
110 | { path: [ '$', 'store', 'book', 0, 'author' ], value: 'Nigel Rees' },
|
111 | { path: [ '$', 'store', 'book', 0, 'title' ], value: 'Sayings of the Century' }
|
112 | ])
|
113 | });
|
114 |
|
115 | test('all elements', function() {
|
116 | var results = jp.nodes(data, '$..*');
|
117 |
|
118 | assert.deepEqual(results, [
|
119 | { path: [ '$', 'store' ], value: data.store },
|
120 | { path: [ '$', 'store', 'book' ], value: data.store.book },
|
121 | { path: [ '$', 'store', 'bicycle' ], value: data.store.bicycle },
|
122 | { path: [ '$', 'store', 'book', 0 ], value: data.store.book[0] },
|
123 | { path: [ '$', 'store', 'book', 1 ], value: data.store.book[1] },
|
124 | { path: [ '$', 'store', 'book', 2 ], value: data.store.book[2] },
|
125 | { path: [ '$', 'store', 'book', 3 ], value: data.store.book[3] },
|
126 | { path: [ '$', 'store', 'book', 0, 'category' ], value: 'reference' },
|
127 | { path: [ '$', 'store', 'book', 0, 'author' ], value: 'Nigel Rees' },
|
128 | { path: [ '$', 'store', 'book', 0, 'title' ], value: 'Sayings of the Century' },
|
129 | { path: [ '$', 'store', 'book', 0, 'price' ], value: 8.95 },
|
130 | { path: [ '$', 'store', 'book', 1, 'category' ], value: 'fiction' },
|
131 | { path: [ '$', 'store', 'book', 1, 'author' ], value: 'Evelyn Waugh' },
|
132 | { path: [ '$', 'store', 'book', 1, 'title' ], value: 'Sword of Honour' },
|
133 | { path: [ '$', 'store', 'book', 1, 'price' ], value: 12.99 },
|
134 | { path: [ '$', 'store', 'book', 2, 'category' ], value: 'fiction' },
|
135 | { path: [ '$', 'store', 'book', 2, 'author' ], value: 'Herman Melville' },
|
136 | { path: [ '$', 'store', 'book', 2, 'title' ], value: 'Moby Dick' },
|
137 | { path: [ '$', 'store', 'book', 2, 'isbn' ], value: '0-553-21311-3' },
|
138 | { path: [ '$', 'store', 'book', 2, 'price' ], value: 8.99 },
|
139 | { path: [ '$', 'store', 'book', 3, 'category' ], value: 'fiction' },
|
140 | { path: [ '$', 'store', 'book', 3, 'author' ], value: 'J. R. R. Tolkien' },
|
141 | { path: [ '$', 'store', 'book', 3, 'title' ], value: 'The Lord of the Rings' },
|
142 | { path: [ '$', 'store', 'book', 3, 'isbn' ], value: '0-395-19395-8' },
|
143 | { path: [ '$', 'store', 'book', 3, 'price' ], value: 22.99 },
|
144 | { path: [ '$', 'store', 'bicycle', 'color' ], value: 'red' },
|
145 | { path: [ '$', 'store', 'bicycle', 'price' ], value: 19.95 }
|
146 | ]);
|
147 | });
|
148 |
|
149 | test('all elements via subscript wildcard', function() {
|
150 | var results = jp.nodes(data, '$..*');
|
151 | assert.deepEqual(jp.nodes(data, '$..[*]'), jp.nodes(data, '$..*'));
|
152 | });
|
153 |
|
154 | test('object subscript wildcard', function() {
|
155 | var results = jp.query(data, '$.store[*]');
|
156 | assert.deepEqual(results, [ data.store.book, data.store.bicycle ]);
|
157 | });
|
158 |
|
159 | test('no match returns empty array', function() {
|
160 | var results = jp.nodes(data, '$..bookz');
|
161 | assert.deepEqual(results, []);
|
162 | });
|
163 |
|
164 | test('member numeric literal gets first element', function() {
|
165 | var results = jp.nodes(data, '$.store.book.0');
|
166 | assert.deepEqual(results, [ { path: [ '$', 'store', 'book', 0 ], value: data.store.book[0] } ]);
|
167 | });
|
168 |
|
169 | test('member numeric literal matches string-numeric key', function() {
|
170 | var data = { authors: { '1': 'Herman Melville', '2': 'J. R. R. Tolkien' } };
|
171 | var results = jp.nodes(data, '$.authors.1');
|
172 | assert.deepEqual(results, [ { path: [ '$', 'authors', 1 ], value: 'Herman Melville' } ]);
|
173 | });
|
174 |
|
175 | test('descendant numeric literal gets first element', function() {
|
176 | var results = jp.nodes(data, '$.store.book..0');
|
177 | assert.deepEqual(results, [ { path: [ '$', 'store', 'book', 0 ], value: data.store.book[0] } ]);
|
178 | });
|
179 |
|
180 | test('root element gets us original obj', function() {
|
181 | var results = jp.nodes(data, '$');
|
182 | assert.deepEqual(results, [ { path: ['$'], value: data } ]);
|
183 | });
|
184 |
|
185 | test('subscript double-quoted string', function() {
|
186 | var results = jp.nodes(data, '$["store"]');
|
187 | assert.deepEqual(results, [ { path: ['$', 'store'], value: data.store} ]);
|
188 | });
|
189 |
|
190 | test('subscript single-quoted string', function() {
|
191 | var results = jp.nodes(data, "$['store']");
|
192 | assert.deepEqual(results, [ { path: ['$', 'store'], value: data.store} ]);
|
193 | });
|
194 |
|
195 | test('leading member component', function() {
|
196 | var results = jp.nodes(data, "store");
|
197 | assert.deepEqual(results, [ { path: ['$', 'store'], value: data.store} ]);
|
198 | });
|
199 |
|
200 | test('union of three array slices', function() {
|
201 | var results = jp.query(data, "$.store.book[0:1,1:2,2:3]");
|
202 | assert.deepEqual(results, data.store.book.slice(0,3));
|
203 | });
|
204 |
|
205 | test('slice with step > 1', function() {
|
206 | var results = jp.query(data, "$.store.book[0:4:2]");
|
207 | assert.deepEqual(results, [ data.store.book[0], data.store.book[2]]);
|
208 | });
|
209 |
|
210 | test('union of subscript string literal keys', function() {
|
211 | var results = jp.nodes(data, "$.store['book','bicycle']");
|
212 | assert.deepEqual(results, [
|
213 | { path: ['$', 'store', 'book'], value: data.store.book },
|
214 | { path: ['$', 'store', 'bicycle'], value: data.store.bicycle },
|
215 | ]);
|
216 | });
|
217 |
|
218 | test('union of subscript string literal three keys', function() {
|
219 | var results = jp.nodes(data, "$.store.book[0]['title','author','price']");
|
220 | assert.deepEqual(results, [
|
221 | { path: ['$', 'store', 'book', 0, 'title'], value: data.store.book[0].title },
|
222 | { path: ['$', 'store', 'book', 0, 'author'], value: data.store.book[0].author },
|
223 | { path: ['$', 'store', 'book', 0, 'price'], value: data.store.book[0].price }
|
224 | ]);
|
225 | });
|
226 |
|
227 | test('union of subscript integer three keys followed by member-child-identifier', function() {
|
228 | var results = jp.nodes(data, "$.store.book[1,2,3]['title']");
|
229 | assert.deepEqual(results, [
|
230 | { path: ['$', 'store', 'book', 1, 'title'], value: data.store.book[1].title },
|
231 | { path: ['$', 'store', 'book', 2, 'title'], value: data.store.book[2].title },
|
232 | { path: ['$', 'store', 'book', 3, 'title'], value: data.store.book[3].title }
|
233 | ]);
|
234 | });
|
235 |
|
236 | test('union of subscript integer three keys followed by union of subscript string literal three keys', function() {
|
237 | var results = jp.nodes(data, "$.store.book[0,1,2,3]['title','author','price']");
|
238 | assert.deepEqual(results, [
|
239 | { path: ['$', 'store', 'book', 0, 'title'], value: data.store.book[0].title },
|
240 | { path: ['$', 'store', 'book', 0, 'author'], value: data.store.book[0].author },
|
241 | { path: ['$', 'store', 'book', 0, 'price'], value: data.store.book[0].price },
|
242 | { path: ['$', 'store', 'book', 1, 'title'], value: data.store.book[1].title },
|
243 | { path: ['$', 'store', 'book', 1, 'author'], value: data.store.book[1].author },
|
244 | { path: ['$', 'store', 'book', 1, 'price'], value: data.store.book[1].price },
|
245 | { path: ['$', 'store', 'book', 2, 'title'], value: data.store.book[2].title },
|
246 | { path: ['$', 'store', 'book', 2, 'author'], value: data.store.book[2].author },
|
247 | { path: ['$', 'store', 'book', 2, 'price'], value: data.store.book[2].price },
|
248 | { path: ['$', 'store', 'book', 3, 'title'], value: data.store.book[3].title },
|
249 | { path: ['$', 'store', 'book', 3, 'author'], value: data.store.book[3].author },
|
250 | { path: ['$', 'store', 'book', 3, 'price'], value: data.store.book[3].price }
|
251 | ]);
|
252 | });
|
253 |
|
254 | test('union of subscript integer four keys, including an inexistent one, followed by union of subscript string literal three keys', function() {
|
255 | var results = jp.nodes(data, "$.store.book[0,1,2,3,151]['title','author','price']");
|
256 | assert.deepEqual(results, [
|
257 | { path: ['$', 'store', 'book', 0, 'title'], value: data.store.book[0].title },
|
258 | { path: ['$', 'store', 'book', 0, 'author'], value: data.store.book[0].author },
|
259 | { path: ['$', 'store', 'book', 0, 'price'], value: data.store.book[0].price },
|
260 | { path: ['$', 'store', 'book', 1, 'title'], value: data.store.book[1].title },
|
261 | { path: ['$', 'store', 'book', 1, 'author'], value: data.store.book[1].author },
|
262 | { path: ['$', 'store', 'book', 1, 'price'], value: data.store.book[1].price },
|
263 | { path: ['$', 'store', 'book', 2, 'title'], value: data.store.book[2].title },
|
264 | { path: ['$', 'store', 'book', 2, 'author'], value: data.store.book[2].author },
|
265 | { path: ['$', 'store', 'book', 2, 'price'], value: data.store.book[2].price },
|
266 | { path: ['$', 'store', 'book', 3, 'title'], value: data.store.book[3].title },
|
267 | { path: ['$', 'store', 'book', 3, 'author'], value: data.store.book[3].author },
|
268 | { path: ['$', 'store', 'book', 3, 'price'], value: data.store.book[3].price }
|
269 | ]);
|
270 | });
|
271 |
|
272 | test('union of subscript integer three keys followed by union of subscript string literal three keys, followed by inexistent literal key', function() {
|
273 | var results = jp.nodes(data, "$.store.book[0,1,2,3]['title','author','price','fruit']");
|
274 | assert.deepEqual(results, [
|
275 | { path: ['$', 'store', 'book', 0, 'title'], value: data.store.book[0].title },
|
276 | { path: ['$', 'store', 'book', 0, 'author'], value: data.store.book[0].author },
|
277 | { path: ['$', 'store', 'book', 0, 'price'], value: data.store.book[0].price },
|
278 | { path: ['$', 'store', 'book', 1, 'title'], value: data.store.book[1].title },
|
279 | { path: ['$', 'store', 'book', 1, 'author'], value: data.store.book[1].author },
|
280 | { path: ['$', 'store', 'book', 1, 'price'], value: data.store.book[1].price },
|
281 | { path: ['$', 'store', 'book', 2, 'title'], value: data.store.book[2].title },
|
282 | { path: ['$', 'store', 'book', 2, 'author'], value: data.store.book[2].author },
|
283 | { path: ['$', 'store', 'book', 2, 'price'], value: data.store.book[2].price },
|
284 | { path: ['$', 'store', 'book', 3, 'title'], value: data.store.book[3].title },
|
285 | { path: ['$', 'store', 'book', 3, 'author'], value: data.store.book[3].author },
|
286 | { path: ['$', 'store', 'book', 3, 'price'], value: data.store.book[3].price }
|
287 | ]);
|
288 | });
|
289 |
|
290 | test('union of subscript 4 array slices followed by union of subscript string literal three keys', function() {
|
291 | var results = jp.nodes(data, "$.store.book[0:1,1:2,2:3,3:4]['title','author','price']");
|
292 | assert.deepEqual(results, [
|
293 | { path: ['$', 'store', 'book', 0, 'title'], value: data.store.book[0].title },
|
294 | { path: ['$', 'store', 'book', 0, 'author'], value: data.store.book[0].author },
|
295 | { path: ['$', 'store', 'book', 0, 'price'], value: data.store.book[0].price },
|
296 | { path: ['$', 'store', 'book', 1, 'title'], value: data.store.book[1].title },
|
297 | { path: ['$', 'store', 'book', 1, 'author'], value: data.store.book[1].author },
|
298 | { path: ['$', 'store', 'book', 1, 'price'], value: data.store.book[1].price },
|
299 | { path: ['$', 'store', 'book', 2, 'title'], value: data.store.book[2].title },
|
300 | { path: ['$', 'store', 'book', 2, 'author'], value: data.store.book[2].author },
|
301 | { path: ['$', 'store', 'book', 2, 'price'], value: data.store.book[2].price },
|
302 | { path: ['$', 'store', 'book', 3, 'title'], value: data.store.book[3].title },
|
303 | { path: ['$', 'store', 'book', 3, 'author'], value: data.store.book[3].author },
|
304 | { path: ['$', 'store', 'book', 3, 'price'], value: data.store.book[3].price }
|
305 | ]);
|
306 | });
|
307 |
|
308 |
|
309 | test('nested parentheses eval', function() {
|
310 | var pathExpression = '$..book[?( @.price && (@.price + 20 || false) )]'
|
311 | var results = jp.query(data, pathExpression);
|
312 | assert.deepEqual(results, data.store.book);
|
313 | });
|
314 |
|
315 | test('array indexes from 0 to 100', function() {
|
316 | var data = [];
|
317 | for (var i = 0; i <= 100; ++i)
|
318 | data[i] = Math.random();
|
319 |
|
320 | for (var i = 0; i <= 100; ++i) {
|
321 | var results = jp.query(data, '$[' + i.toString() + ']');
|
322 | assert.deepEqual(results, [data[i]]);
|
323 | }
|
324 | });
|
325 |
|
326 | test('descendant subscript numeric literal', function() {
|
327 | var data = [ 0, [ 1, 2, 3 ], [ 4, 5, 6 ] ];
|
328 | var results = jp.query(data, '$..[0]');
|
329 | assert.deepEqual(results, [ 0, 1, 4 ]);
|
330 | });
|
331 |
|
332 | test('descendant subscript numeric literal', function() {
|
333 | var data = [ 0, 1, [ 2, 3, 4 ], [ 5, 6, 7, [ 8, 9 , 10 ] ] ];
|
334 | var results = jp.query(data, '$..[0,1]');
|
335 | assert.deepEqual(results, [ 0, 1, 2, 3, 5, 6, 8, 9 ]);
|
336 | });
|
337 |
|
338 | test('throws for no input', function() {
|
339 | assert.throws(function() { jp.query() }, /needs to be an object/);
|
340 | });
|
341 |
|
342 | test('throws for bad input', function() {
|
343 | assert.throws(function() { jp.query("string", "string") }, /needs to be an object/);
|
344 | });
|
345 |
|
346 | test('throws for bad input', function() {
|
347 | assert.throws(function() { jp.query({}, null) }, /we need a path/);
|
348 | });
|
349 |
|
350 | test('throws for bad input', function() {
|
351 | assert.throws(function() { jp.query({}, 42) }, /we need a path/);
|
352 | });
|
353 |
|
354 | test('union on objects', function() {
|
355 | assert.deepEqual(jp.query({a: 1, b: 2, c: null}, '$..["a","b","c","d"]'), [1, 2, null]);
|
356 | });
|
357 |
|
358 | });
|
359 |
|