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('descendant numeric literal gets first element', function() {
|
170 | var results = jp.nodes(data, '$.store.book..0');
|
171 | assert.deepEqual(results, [ { path: [ '$', 'store', 'book', 0 ], value: data.store.book[0] } ]);
|
172 | });
|
173 |
|
174 | test('root element gets us original obj', function() {
|
175 | var results = jp.nodes(data, '$');
|
176 | assert.deepEqual(results, [ { path: ['$'], value: data } ]);
|
177 | });
|
178 |
|
179 | test('subscript double-quoted string', function() {
|
180 | var results = jp.nodes(data, '$["store"]');
|
181 | assert.deepEqual(results, [ { path: ['$', 'store'], value: data.store} ]);
|
182 | });
|
183 |
|
184 | test('subscript single-quoted string', function() {
|
185 | var results = jp.nodes(data, "$['store']");
|
186 | assert.deepEqual(results, [ { path: ['$', 'store'], value: data.store} ]);
|
187 | });
|
188 |
|
189 | test('leading member component', function() {
|
190 | var results = jp.nodes(data, "store");
|
191 | assert.deepEqual(results, [ { path: ['$', 'store'], value: data.store} ]);
|
192 | });
|
193 |
|
194 | test('union of three array slices', function() {
|
195 | var results = jp.query(data, "$.store.book[0:1,1:2,2:3]");
|
196 | assert.deepEqual(results, data.store.book.slice(0,3));
|
197 | });
|
198 |
|
199 | test('slice with step > 1', function() {
|
200 | var results = jp.query(data, "$.store.book[0:4:2]");
|
201 | assert.deepEqual(results, [ data.store.book[0], data.store.book[2]]);
|
202 | });
|
203 |
|
204 | test('union of subscript string literal keys', function() {
|
205 | var results = jp.nodes(data, "$.store['book','bicycle']");
|
206 | assert.deepEqual(results, [
|
207 | { path: ['$', 'store', 'book'], value: data.store.book },
|
208 | { path: ['$', 'store', 'bicycle'], value: data.store.bicycle },
|
209 | ]);
|
210 | });
|
211 |
|
212 | test('union of subscript string literal three keys', function() {
|
213 | var results = jp.nodes(data, "$.store.book[0]['title','author','price']");
|
214 | assert.deepEqual(results, [
|
215 | { path: ['$', 'store', 'book', 0, 'title'], value: data.store.book[0].title },
|
216 | { path: ['$', 'store', 'book', 0, 'author'], value: data.store.book[0].author },
|
217 | { path: ['$', 'store', 'book', 0, 'price'], value: data.store.book[0].price }
|
218 | ]);
|
219 | });
|
220 |
|
221 | test('union of subscript integer three keys followed by member-child-identifier', function() {
|
222 | var results = jp.nodes(data, "$.store.book[1,2,3]['title']");
|
223 | assert.deepEqual(results, [
|
224 | { path: ['$', 'store', 'book', 1, 'title'], value: data.store.book[1].title },
|
225 | { path: ['$', 'store', 'book', 2, 'title'], value: data.store.book[2].title },
|
226 | { path: ['$', 'store', 'book', 3, 'title'], value: data.store.book[3].title }
|
227 | ]);
|
228 | });
|
229 |
|
230 | test('union of subscript integer three keys followed by union of subscript string literal three keys', function() {
|
231 | var results = jp.nodes(data, "$.store.book[0,1,2,3]['title','author','price']");
|
232 | assert.deepEqual(results, [
|
233 | { path: ['$', 'store', 'book', 0, 'title'], value: data.store.book[0].title },
|
234 | { path: ['$', 'store', 'book', 0, 'author'], value: data.store.book[0].author },
|
235 | { path: ['$', 'store', 'book', 0, 'price'], value: data.store.book[0].price },
|
236 | { path: ['$', 'store', 'book', 1, 'title'], value: data.store.book[1].title },
|
237 | { path: ['$', 'store', 'book', 1, 'author'], value: data.store.book[1].author },
|
238 | { path: ['$', 'store', 'book', 1, 'price'], value: data.store.book[1].price },
|
239 | { path: ['$', 'store', 'book', 2, 'title'], value: data.store.book[2].title },
|
240 | { path: ['$', 'store', 'book', 2, 'author'], value: data.store.book[2].author },
|
241 | { path: ['$', 'store', 'book', 2, 'price'], value: data.store.book[2].price },
|
242 | { path: ['$', 'store', 'book', 3, 'title'], value: data.store.book[3].title },
|
243 | { path: ['$', 'store', 'book', 3, 'author'], value: data.store.book[3].author },
|
244 | { path: ['$', 'store', 'book', 3, 'price'], value: data.store.book[3].price }
|
245 | ]);
|
246 | });
|
247 |
|
248 | test('union of subscript 4 array slices followed by union of subscript string literal three keys', function() {
|
249 | var results = jp.nodes(data, "$.store.book[0:1,1:2,2:3,3:4]['title','author','price']");
|
250 | assert.deepEqual(results, [
|
251 | { path: ['$', 'store', 'book', 0, 'title'], value: data.store.book[0].title },
|
252 | { path: ['$', 'store', 'book', 0, 'author'], value: data.store.book[0].author },
|
253 | { path: ['$', 'store', 'book', 0, 'price'], value: data.store.book[0].price },
|
254 | { path: ['$', 'store', 'book', 1, 'title'], value: data.store.book[1].title },
|
255 | { path: ['$', 'store', 'book', 1, 'author'], value: data.store.book[1].author },
|
256 | { path: ['$', 'store', 'book', 1, 'price'], value: data.store.book[1].price },
|
257 | { path: ['$', 'store', 'book', 2, 'title'], value: data.store.book[2].title },
|
258 | { path: ['$', 'store', 'book', 2, 'author'], value: data.store.book[2].author },
|
259 | { path: ['$', 'store', 'book', 2, 'price'], value: data.store.book[2].price },
|
260 | { path: ['$', 'store', 'book', 3, 'title'], value: data.store.book[3].title },
|
261 | { path: ['$', 'store', 'book', 3, 'author'], value: data.store.book[3].author },
|
262 | { path: ['$', 'store', 'book', 3, 'price'], value: data.store.book[3].price }
|
263 | ]);
|
264 | });
|
265 |
|
266 |
|
267 | test('nested parentheses eval', function() {
|
268 | var pathExpression = '$..book[?( @.price && (@.price + 20 || false) )]'
|
269 | var results = jp.query(data, pathExpression);
|
270 | assert.deepEqual(results, data.store.book);
|
271 | });
|
272 |
|
273 | test('array indexes from 0 to 100', function() {
|
274 | var data = [];
|
275 | for (var i = 0; i <= 100; ++i)
|
276 | data[i] = Math.random();
|
277 |
|
278 | for (var i = 0; i <= 100; ++i) {
|
279 | var results = jp.query(data, '$[' + i.toString() + ']');
|
280 | assert.deepEqual(results, [data[i]]);
|
281 | }
|
282 | });
|
283 |
|
284 | test('descendant subscript numeric literal', function() {
|
285 | var data = [ 0, [ 1, 2, 3 ], [ 4, 5, 6 ] ];
|
286 | var results = jp.query(data, '$..[0]');
|
287 | assert.deepEqual(results, [ 0, 1, 4 ]);
|
288 | });
|
289 |
|
290 | test('descendant subscript numeric literal', function() {
|
291 | var data = [ 0, 1, [ 2, 3, 4 ], [ 5, 6, 7, [ 8, 9 , 10 ] ] ];
|
292 | var results = jp.query(data, '$..[0,1]');
|
293 | assert.deepEqual(results, [ 0, 1, 2, 3, 5, 6, 8, 9 ]);
|
294 | });
|
295 |
|
296 | test('throws for no input', function() {
|
297 | assert.throws(function() { jp.query() }, /needs to be an object/);
|
298 | });
|
299 |
|
300 | test('throws for bad input', function() {
|
301 | assert.throws(function() { jp.query("string", "string") }, /needs to be an object/);
|
302 | });
|
303 |
|
304 | test('throws for bad input', function() {
|
305 | assert.throws(function() { jp.query({}, null) }, /we need a path/);
|
306 | });
|
307 |
|
308 | test('throws for bad input', function() {
|
309 | assert.throws(function() { jp.query({}, 42) }, /we need a path/);
|
310 | });
|
311 |
|
312 | });
|
313 |
|