@nymphjs/query-parser 1.0.0-beta.13 → 1.0.0-beta.131
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.
- package/CHANGELOG.md +499 -0
- package/README.md +64 -50
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/queryParser.js +953 -0
- package/dist/queryParser.js.map +1 -0
- package/dist/queryParser.test.js +1686 -0
- package/dist/queryParser.test.js.map +1 -0
- package/jest.config.js +31 -5
- package/package.json +35 -34
- package/src/index.ts +2 -2
- package/src/queryParser.test.ts +1106 -164
- package/src/queryParser.ts +425 -140
- package/tsconfig.json +7 -4
- package/typedoc.json +4 -0
- package/lib/index.d.ts +0 -4
- package/lib/index.js +0 -25
- package/lib/index.js.map +0 -1
- package/lib/queryParser.js +0 -672
- package/lib/queryParser.js.map +0 -1
- package/lib/queryParser.test.js +0 -856
- package/lib/queryParser.test.js.map +0 -1
- package/webpack.config.js +0 -28
- /package/{lib → dist}/queryParser.d.ts +0 -0
- /package/{lib → dist}/queryParser.test.d.ts +0 -0
package/src/queryParser.test.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import type { Entity } from '@nymphjs/client';
|
|
2
|
-
import queryParser from './queryParser';
|
|
2
|
+
import queryParser from './queryParser.js';
|
|
3
3
|
|
|
4
4
|
const BlogPost = function () {} as unknown as typeof Entity;
|
|
5
5
|
const Category = function () {} as unknown as typeof Entity;
|
|
6
|
+
const List = function () {} as unknown as typeof Entity;
|
|
7
|
+
|
|
8
|
+
const Mail = function () {} as unknown as typeof Entity;
|
|
9
|
+
const Headers = function () {} as unknown as typeof Entity;
|
|
10
|
+
const Body = function () {} as unknown as typeof Entity;
|
|
11
|
+
const Label = function () {} as unknown as typeof Entity;
|
|
12
|
+
const Domain = function () {} as unknown as typeof Entity;
|
|
6
13
|
|
|
7
14
|
describe('queryParser', () => {
|
|
8
15
|
it('parses a basic query', () => {
|
|
@@ -55,13 +62,13 @@ describe('queryParser', () => {
|
|
|
55
62
|
});
|
|
56
63
|
|
|
57
64
|
it('gives the correct entity and default fields to bare queries', () => {
|
|
58
|
-
const query = 'category<{
|
|
65
|
+
const query = 'category<{Cat search}>';
|
|
59
66
|
const [options, ...selectors] = queryParser({
|
|
60
67
|
query,
|
|
61
68
|
entityClass: BlogPost,
|
|
62
69
|
defaultFields: ['text'],
|
|
63
70
|
qrefMap: {
|
|
64
|
-
|
|
71
|
+
Cat: {
|
|
65
72
|
class: Category,
|
|
66
73
|
defaultFields: ['name'],
|
|
67
74
|
},
|
|
@@ -97,13 +104,13 @@ describe('queryParser', () => {
|
|
|
97
104
|
|
|
98
105
|
it('parses the example query from the readme', () => {
|
|
99
106
|
const query =
|
|
100
|
-
'limit:4 foobar (| [archived] mdate<"2 weeks ago") category<{
|
|
107
|
+
'limit:4 foobar (| [archived] mdate<"2 weeks ago") category<{Cat Tech}>';
|
|
101
108
|
const [options, ...selectors] = queryParser({
|
|
102
109
|
query,
|
|
103
110
|
entityClass: BlogPost,
|
|
104
111
|
defaultFields: ['title', 'body'],
|
|
105
112
|
qrefMap: {
|
|
106
|
-
|
|
113
|
+
Cat: {
|
|
107
114
|
class: Category,
|
|
108
115
|
defaultFields: ['name'],
|
|
109
116
|
},
|
|
@@ -150,31 +157,809 @@ describe('queryParser', () => {
|
|
|
150
157
|
]);
|
|
151
158
|
});
|
|
152
159
|
|
|
153
|
-
it('parses
|
|
154
|
-
const query =
|
|
160
|
+
it('parses a query with json value with spaces', () => {
|
|
161
|
+
const query =
|
|
162
|
+
'obj={"prop": "my value"} foobar arr=["a value", "another value"]';
|
|
155
163
|
const [options, ...selectors] = queryParser({
|
|
156
164
|
query,
|
|
157
165
|
entityClass: BlogPost,
|
|
158
|
-
defaultFields: ['
|
|
166
|
+
defaultFields: ['title', 'body'],
|
|
159
167
|
});
|
|
160
168
|
|
|
161
169
|
expect(options).toEqual({
|
|
162
170
|
class: BlogPost,
|
|
163
|
-
limit: 10,
|
|
164
|
-
offset: 15,
|
|
165
|
-
reverse: true,
|
|
166
171
|
});
|
|
167
172
|
|
|
168
173
|
expect(selectors).toEqual([
|
|
174
|
+
{
|
|
175
|
+
type: '&',
|
|
176
|
+
equal: [
|
|
177
|
+
['obj', { prop: 'my value' }],
|
|
178
|
+
['arr', ['a value', 'another value']],
|
|
179
|
+
],
|
|
180
|
+
},
|
|
169
181
|
{
|
|
170
182
|
type: '|',
|
|
171
|
-
ilike: [
|
|
183
|
+
ilike: [
|
|
184
|
+
['title', '%foobar%'],
|
|
185
|
+
['body', '%foobar%'],
|
|
186
|
+
],
|
|
172
187
|
},
|
|
173
188
|
]);
|
|
174
189
|
});
|
|
175
190
|
|
|
176
|
-
it('parses
|
|
177
|
-
const query =
|
|
191
|
+
it('parses a query with nested json value with spaces', () => {
|
|
192
|
+
const query =
|
|
193
|
+
'obj={"obj": {"sub": "my value"}, "prop": "my value"} foobar arr=["a value", "another value", {"prop": [1, 2, 3]}]';
|
|
194
|
+
const [options, ...selectors] = queryParser({
|
|
195
|
+
query,
|
|
196
|
+
entityClass: BlogPost,
|
|
197
|
+
defaultFields: ['title', 'body'],
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
expect(options).toEqual({
|
|
201
|
+
class: BlogPost,
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
expect(selectors).toEqual([
|
|
205
|
+
{
|
|
206
|
+
type: '&',
|
|
207
|
+
equal: [
|
|
208
|
+
['obj', { obj: { sub: 'my value' }, prop: 'my value' }],
|
|
209
|
+
['arr', ['a value', 'another value', { prop: [1, 2, 3] }]],
|
|
210
|
+
],
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
type: '|',
|
|
214
|
+
ilike: [
|
|
215
|
+
['title', '%foobar%'],
|
|
216
|
+
['body', '%foobar%'],
|
|
217
|
+
],
|
|
218
|
+
},
|
|
219
|
+
]);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('parses a query with broken json', () => {
|
|
223
|
+
const query = 'obj={"obj":"val"';
|
|
224
|
+
const [options, ...selectors] = queryParser({
|
|
225
|
+
query,
|
|
226
|
+
entityClass: BlogPost,
|
|
227
|
+
defaultFields: ['title', 'body'],
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
expect(options).toEqual({
|
|
231
|
+
class: BlogPost,
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
expect(selectors).toEqual([
|
|
235
|
+
{
|
|
236
|
+
type: '&',
|
|
237
|
+
equal: [['obj', '{"obj":"val"']],
|
|
238
|
+
},
|
|
239
|
+
]);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('parses a query with broken json and correct json', () => {
|
|
243
|
+
const query = 'obj={"obj":"val" another={"prop":"value"}';
|
|
244
|
+
const [options, ...selectors] = queryParser({
|
|
245
|
+
query,
|
|
246
|
+
entityClass: BlogPost,
|
|
247
|
+
defaultFields: ['title', 'body'],
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
expect(options).toEqual({
|
|
251
|
+
class: BlogPost,
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
expect(selectors).toEqual([
|
|
255
|
+
{
|
|
256
|
+
type: '&',
|
|
257
|
+
equal: [
|
|
258
|
+
['another', { prop: 'value' }],
|
|
259
|
+
['obj', '{"obj":"val"'],
|
|
260
|
+
],
|
|
261
|
+
},
|
|
262
|
+
]);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('parses a query with search', () => {
|
|
266
|
+
const query = 'limit:4 foobar prop(a search string)';
|
|
267
|
+
const [options, ...selectors] = queryParser({
|
|
268
|
+
query,
|
|
269
|
+
entityClass: BlogPost,
|
|
270
|
+
defaultFields: ['title', 'body'],
|
|
271
|
+
qrefMap: {
|
|
272
|
+
cat: {
|
|
273
|
+
class: Category,
|
|
274
|
+
defaultFields: ['name'],
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
expect(options).toEqual({
|
|
280
|
+
class: BlogPost,
|
|
281
|
+
limit: 4,
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
expect(selectors).toEqual([
|
|
285
|
+
{
|
|
286
|
+
type: '&',
|
|
287
|
+
search: [['prop', 'a search string']],
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
type: '|',
|
|
291
|
+
ilike: [
|
|
292
|
+
['title', '%foobar%'],
|
|
293
|
+
['body', '%foobar%'],
|
|
294
|
+
],
|
|
295
|
+
},
|
|
296
|
+
]);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('parses a query with not search', () => {
|
|
300
|
+
const query = 'limit:4 foobar -prop(a search string)';
|
|
301
|
+
const [options, ...selectors] = queryParser({
|
|
302
|
+
query,
|
|
303
|
+
entityClass: BlogPost,
|
|
304
|
+
defaultFields: ['title', 'body'],
|
|
305
|
+
qrefMap: {
|
|
306
|
+
cat: {
|
|
307
|
+
class: Category,
|
|
308
|
+
defaultFields: ['name'],
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
expect(options).toEqual({
|
|
314
|
+
class: BlogPost,
|
|
315
|
+
limit: 4,
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
expect(selectors).toEqual([
|
|
319
|
+
{
|
|
320
|
+
type: '&',
|
|
321
|
+
'!search': [['prop', 'a search string']],
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
type: '|',
|
|
325
|
+
ilike: [
|
|
326
|
+
['title', '%foobar%'],
|
|
327
|
+
['body', '%foobar%'],
|
|
328
|
+
],
|
|
329
|
+
},
|
|
330
|
+
]);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('parses a query with colon search', () => {
|
|
334
|
+
const query = 'limit:4 foobar prop:string';
|
|
335
|
+
const [options, ...selectors] = queryParser({
|
|
336
|
+
query,
|
|
337
|
+
entityClass: BlogPost,
|
|
338
|
+
defaultFields: ['title', 'body'],
|
|
339
|
+
qrefMap: {
|
|
340
|
+
cat: {
|
|
341
|
+
class: Category,
|
|
342
|
+
defaultFields: ['name'],
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
expect(options).toEqual({
|
|
348
|
+
class: BlogPost,
|
|
349
|
+
limit: 4,
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
expect(selectors).toEqual([
|
|
353
|
+
{
|
|
354
|
+
type: '&',
|
|
355
|
+
search: [['prop', 'string']],
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
type: '|',
|
|
359
|
+
ilike: [
|
|
360
|
+
['title', '%foobar%'],
|
|
361
|
+
['body', '%foobar%'],
|
|
362
|
+
],
|
|
363
|
+
},
|
|
364
|
+
]);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('parses a query with not colon search', () => {
|
|
368
|
+
const query = 'limit:4 foobar -prop:string';
|
|
369
|
+
const [options, ...selectors] = queryParser({
|
|
370
|
+
query,
|
|
371
|
+
entityClass: BlogPost,
|
|
372
|
+
defaultFields: ['title', 'body'],
|
|
373
|
+
qrefMap: {
|
|
374
|
+
cat: {
|
|
375
|
+
class: Category,
|
|
376
|
+
defaultFields: ['name'],
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
expect(options).toEqual({
|
|
382
|
+
class: BlogPost,
|
|
383
|
+
limit: 4,
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
expect(selectors).toEqual([
|
|
387
|
+
{
|
|
388
|
+
type: '&',
|
|
389
|
+
'!search': [['prop', 'string']],
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
type: '|',
|
|
393
|
+
ilike: [
|
|
394
|
+
['title', '%foobar%'],
|
|
395
|
+
['body', '%foobar%'],
|
|
396
|
+
],
|
|
397
|
+
},
|
|
398
|
+
]);
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it('parses a query with search in a selector', () => {
|
|
402
|
+
const query =
|
|
403
|
+
'limit:4 foobar (| prop(a search string) prop2("another search string"))';
|
|
404
|
+
const [options, ...selectors] = queryParser({
|
|
405
|
+
query,
|
|
406
|
+
entityClass: BlogPost,
|
|
407
|
+
defaultFields: ['title', 'body'],
|
|
408
|
+
qrefMap: {
|
|
409
|
+
cat: {
|
|
410
|
+
class: Category,
|
|
411
|
+
defaultFields: ['name'],
|
|
412
|
+
},
|
|
413
|
+
},
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
expect(options).toEqual({
|
|
417
|
+
class: BlogPost,
|
|
418
|
+
limit: 4,
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
expect(selectors).toEqual([
|
|
422
|
+
{
|
|
423
|
+
type: '&',
|
|
424
|
+
selector: [
|
|
425
|
+
{
|
|
426
|
+
type: '|',
|
|
427
|
+
search: [
|
|
428
|
+
['prop', 'a search string'],
|
|
429
|
+
['prop2', '"another search string"'],
|
|
430
|
+
],
|
|
431
|
+
},
|
|
432
|
+
],
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
type: '|',
|
|
436
|
+
ilike: [
|
|
437
|
+
['title', '%foobar%'],
|
|
438
|
+
['body', '%foobar%'],
|
|
439
|
+
],
|
|
440
|
+
},
|
|
441
|
+
]);
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
it('parses a query with colon search in a selector', () => {
|
|
445
|
+
const query =
|
|
446
|
+
'limit:4 foobar (| prop:string prop2:"another search string" -prop3:pickle -prop4:\'another -pickle string\')';
|
|
447
|
+
const [options, ...selectors] = queryParser({
|
|
448
|
+
query,
|
|
449
|
+
entityClass: BlogPost,
|
|
450
|
+
defaultFields: ['title', 'body'],
|
|
451
|
+
qrefMap: {
|
|
452
|
+
cat: {
|
|
453
|
+
class: Category,
|
|
454
|
+
defaultFields: ['name'],
|
|
455
|
+
},
|
|
456
|
+
},
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
expect(options).toEqual({
|
|
460
|
+
class: BlogPost,
|
|
461
|
+
limit: 4,
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
expect(selectors).toEqual([
|
|
465
|
+
{
|
|
466
|
+
type: '&',
|
|
467
|
+
selector: [
|
|
468
|
+
{
|
|
469
|
+
type: '|',
|
|
470
|
+
search: [
|
|
471
|
+
['prop', 'string'],
|
|
472
|
+
['prop2', '"another search string"'],
|
|
473
|
+
],
|
|
474
|
+
'!search': [
|
|
475
|
+
['prop3', 'pickle'],
|
|
476
|
+
['prop4', "'another -pickle string'"],
|
|
477
|
+
],
|
|
478
|
+
},
|
|
479
|
+
],
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
type: '|',
|
|
483
|
+
ilike: [
|
|
484
|
+
['title', '%foobar%'],
|
|
485
|
+
['body', '%foobar%'],
|
|
486
|
+
],
|
|
487
|
+
},
|
|
488
|
+
]);
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
it('parses a query with lt and tag', () => {
|
|
492
|
+
const query = 'limit:4 foobar mdate<"2 weeks ago" <tag>';
|
|
493
|
+
const [options, ...selectors] = queryParser({
|
|
494
|
+
query,
|
|
495
|
+
entityClass: BlogPost,
|
|
496
|
+
defaultFields: ['title', 'body'],
|
|
497
|
+
qrefMap: {
|
|
498
|
+
cat: {
|
|
499
|
+
class: Category,
|
|
500
|
+
defaultFields: ['name'],
|
|
501
|
+
},
|
|
502
|
+
},
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
expect(options).toEqual({
|
|
506
|
+
class: BlogPost,
|
|
507
|
+
limit: 4,
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
expect(selectors).toEqual([
|
|
511
|
+
{
|
|
512
|
+
type: '&',
|
|
513
|
+
lt: [['mdate', null, '2 weeks ago']],
|
|
514
|
+
tag: ['tag'],
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
type: '|',
|
|
518
|
+
ilike: [
|
|
519
|
+
['title', '%foobar%'],
|
|
520
|
+
['body', '%foobar%'],
|
|
521
|
+
],
|
|
522
|
+
},
|
|
523
|
+
]);
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
it('parses a query with contain that has brackets', () => {
|
|
527
|
+
const query = 'limit:4 foobar string<"a string with < and > characters">';
|
|
528
|
+
const [options, ...selectors] = queryParser({
|
|
529
|
+
query,
|
|
530
|
+
entityClass: BlogPost,
|
|
531
|
+
defaultFields: ['title', 'body'],
|
|
532
|
+
qrefMap: {
|
|
533
|
+
cat: {
|
|
534
|
+
class: Category,
|
|
535
|
+
defaultFields: ['name'],
|
|
536
|
+
},
|
|
537
|
+
},
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
expect(options).toEqual({
|
|
541
|
+
class: BlogPost,
|
|
542
|
+
limit: 4,
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
expect(selectors).toEqual([
|
|
546
|
+
{
|
|
547
|
+
type: '&',
|
|
548
|
+
contain: [['string', 'a string with < and > characters']],
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
type: '|',
|
|
552
|
+
ilike: [
|
|
553
|
+
['title', '%foobar%'],
|
|
554
|
+
['body', '%foobar%'],
|
|
555
|
+
],
|
|
556
|
+
},
|
|
557
|
+
]);
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
it('parses a query with contain that has quotes', () => {
|
|
561
|
+
const query = 'limit:4 foobar string<"a string with a \\" characters">';
|
|
562
|
+
const [options, ...selectors] = queryParser({
|
|
563
|
+
query,
|
|
564
|
+
entityClass: BlogPost,
|
|
565
|
+
defaultFields: ['title', 'body'],
|
|
566
|
+
qrefMap: {
|
|
567
|
+
cat: {
|
|
568
|
+
class: Category,
|
|
569
|
+
defaultFields: ['name'],
|
|
570
|
+
},
|
|
571
|
+
},
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
expect(options).toEqual({
|
|
575
|
+
class: BlogPost,
|
|
576
|
+
limit: 4,
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
expect(selectors).toEqual([
|
|
580
|
+
{
|
|
581
|
+
type: '&',
|
|
582
|
+
contain: [['string', 'a string with a " characters']],
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
type: '|',
|
|
586
|
+
ilike: [
|
|
587
|
+
['title', '%foobar%'],
|
|
588
|
+
['body', '%foobar%'],
|
|
589
|
+
],
|
|
590
|
+
},
|
|
591
|
+
]);
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
it('parses a query with a dash in the property name', () => {
|
|
595
|
+
const query = 'limit:4 foobar Test-Prop<"a string">';
|
|
596
|
+
const [options, ...selectors] = queryParser({
|
|
597
|
+
query,
|
|
598
|
+
entityClass: BlogPost,
|
|
599
|
+
defaultFields: ['title', 'body'],
|
|
600
|
+
qrefMap: {
|
|
601
|
+
cat: {
|
|
602
|
+
class: Category,
|
|
603
|
+
defaultFields: ['name'],
|
|
604
|
+
},
|
|
605
|
+
},
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
expect(options).toEqual({
|
|
609
|
+
class: BlogPost,
|
|
610
|
+
limit: 4,
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
expect(selectors).toEqual([
|
|
614
|
+
{
|
|
615
|
+
type: '&',
|
|
616
|
+
contain: [['Test-Prop', 'a string']],
|
|
617
|
+
},
|
|
618
|
+
{
|
|
619
|
+
type: '|',
|
|
620
|
+
ilike: [
|
|
621
|
+
['title', '%foobar%'],
|
|
622
|
+
['body', '%foobar%'],
|
|
623
|
+
],
|
|
624
|
+
},
|
|
625
|
+
]);
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
it('parses all options', () => {
|
|
629
|
+
const query = 'limit:10 offset:15 sort:someProp reverse:true search';
|
|
630
|
+
const [options, ...selectors] = queryParser({
|
|
631
|
+
query,
|
|
632
|
+
entityClass: BlogPost,
|
|
633
|
+
defaultFields: ['text'],
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
expect(options).toEqual({
|
|
637
|
+
class: BlogPost,
|
|
638
|
+
limit: 10,
|
|
639
|
+
offset: 15,
|
|
640
|
+
sort: 'someProp',
|
|
641
|
+
reverse: true,
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
expect(selectors).toEqual([
|
|
645
|
+
{
|
|
646
|
+
type: '|',
|
|
647
|
+
ilike: [['text', '%search%']],
|
|
648
|
+
},
|
|
649
|
+
]);
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
it('parses null sort option', () => {
|
|
653
|
+
const query = 'limit:10 offset:15 sort:- reverse:true search';
|
|
654
|
+
const [options, ...selectors] = queryParser({
|
|
655
|
+
query,
|
|
656
|
+
entityClass: BlogPost,
|
|
657
|
+
defaultFields: ['text'],
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
expect(options).toEqual({
|
|
661
|
+
class: BlogPost,
|
|
662
|
+
limit: 10,
|
|
663
|
+
offset: 15,
|
|
664
|
+
sort: null,
|
|
665
|
+
reverse: true,
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
expect(selectors).toEqual([
|
|
669
|
+
{
|
|
670
|
+
type: '|',
|
|
671
|
+
ilike: [['text', '%search%']],
|
|
672
|
+
},
|
|
673
|
+
]);
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
it('parses simple equal clauses', () => {
|
|
677
|
+
const query = 'prop=string';
|
|
678
|
+
const [options, ...selectors] = queryParser({
|
|
679
|
+
query,
|
|
680
|
+
entityClass: BlogPost,
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
expect(options).toEqual({
|
|
684
|
+
class: BlogPost,
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
expect(selectors).toEqual([
|
|
688
|
+
{
|
|
689
|
+
type: '&',
|
|
690
|
+
equal: [['prop', 'string']],
|
|
691
|
+
},
|
|
692
|
+
]);
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
it('parses simple not equal clauses', () => {
|
|
696
|
+
const query = '-prop=string';
|
|
697
|
+
const [options, ...selectors] = queryParser({
|
|
698
|
+
query,
|
|
699
|
+
entityClass: BlogPost,
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
expect(options).toEqual({
|
|
703
|
+
class: BlogPost,
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
expect(selectors).toEqual([
|
|
707
|
+
{
|
|
708
|
+
type: '&',
|
|
709
|
+
'!equal': [['prop', 'string']],
|
|
710
|
+
},
|
|
711
|
+
]);
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
it('parses quoted equal clauses', () => {
|
|
715
|
+
const query = 'prop="a string"';
|
|
716
|
+
const [options, ...selectors] = queryParser({
|
|
717
|
+
query,
|
|
718
|
+
entityClass: BlogPost,
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
expect(options).toEqual({
|
|
722
|
+
class: BlogPost,
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
expect(selectors).toEqual([
|
|
726
|
+
{
|
|
727
|
+
type: '&',
|
|
728
|
+
equal: [['prop', 'a string']],
|
|
729
|
+
},
|
|
730
|
+
]);
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
it('parses quoted not equal clauses', () => {
|
|
734
|
+
const query = '-prop="a string"';
|
|
735
|
+
const [options, ...selectors] = queryParser({
|
|
736
|
+
query,
|
|
737
|
+
entityClass: BlogPost,
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
expect(options).toEqual({
|
|
741
|
+
class: BlogPost,
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
expect(selectors).toEqual([
|
|
745
|
+
{
|
|
746
|
+
type: '&',
|
|
747
|
+
'!equal': [['prop', 'a string']],
|
|
748
|
+
},
|
|
749
|
+
]);
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
it('parses json equal clauses', () => {
|
|
753
|
+
const query = 'prop=true';
|
|
754
|
+
const [options, ...selectors] = queryParser({
|
|
755
|
+
query,
|
|
756
|
+
entityClass: BlogPost,
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
expect(options).toEqual({
|
|
760
|
+
class: BlogPost,
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
expect(selectors).toEqual([
|
|
764
|
+
{
|
|
765
|
+
type: '&',
|
|
766
|
+
equal: [['prop', true]],
|
|
767
|
+
},
|
|
768
|
+
]);
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
it('parses json not equal clauses', () => {
|
|
772
|
+
const query = '-prop=true';
|
|
773
|
+
const [options, ...selectors] = queryParser({
|
|
774
|
+
query,
|
|
775
|
+
entityClass: BlogPost,
|
|
776
|
+
});
|
|
777
|
+
|
|
778
|
+
expect(options).toEqual({
|
|
779
|
+
class: BlogPost,
|
|
780
|
+
});
|
|
781
|
+
|
|
782
|
+
expect(selectors).toEqual([
|
|
783
|
+
{
|
|
784
|
+
type: '&',
|
|
785
|
+
'!equal': [['prop', true]],
|
|
786
|
+
},
|
|
787
|
+
]);
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
it('parses guid clauses', () => {
|
|
791
|
+
const query = '{111111111111111111111111}';
|
|
792
|
+
const [options, ...selectors] = queryParser({
|
|
793
|
+
query,
|
|
794
|
+
entityClass: BlogPost,
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
expect(options).toEqual({
|
|
798
|
+
class: BlogPost,
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
expect(selectors).toEqual([
|
|
802
|
+
{
|
|
803
|
+
type: '&',
|
|
804
|
+
guid: ['111111111111111111111111'],
|
|
805
|
+
},
|
|
806
|
+
]);
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
it('parses not guid clauses', () => {
|
|
810
|
+
const query = '-{111111111111111111111111}';
|
|
811
|
+
const [options, ...selectors] = queryParser({
|
|
812
|
+
query,
|
|
813
|
+
entityClass: BlogPost,
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
expect(options).toEqual({
|
|
817
|
+
class: BlogPost,
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
expect(selectors).toEqual([
|
|
821
|
+
{
|
|
822
|
+
type: '&',
|
|
823
|
+
'!guid': ['111111111111111111111111'],
|
|
824
|
+
},
|
|
825
|
+
]);
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
it('parses tag clauses', () => {
|
|
829
|
+
const query = '<tagname>';
|
|
830
|
+
const [options, ...selectors] = queryParser({
|
|
831
|
+
query,
|
|
832
|
+
entityClass: BlogPost,
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
expect(options).toEqual({
|
|
836
|
+
class: BlogPost,
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
expect(selectors).toEqual([
|
|
840
|
+
{
|
|
841
|
+
type: '&',
|
|
842
|
+
tag: ['tagname'],
|
|
843
|
+
},
|
|
844
|
+
]);
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
it('parses not tag clauses', () => {
|
|
848
|
+
const query = '-<tagname>';
|
|
849
|
+
const [options, ...selectors] = queryParser({
|
|
850
|
+
query,
|
|
851
|
+
entityClass: BlogPost,
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
expect(options).toEqual({
|
|
855
|
+
class: BlogPost,
|
|
856
|
+
});
|
|
857
|
+
|
|
858
|
+
expect(selectors).toEqual([
|
|
859
|
+
{
|
|
860
|
+
type: '&',
|
|
861
|
+
'!tag': ['tagname'],
|
|
862
|
+
},
|
|
863
|
+
]);
|
|
864
|
+
});
|
|
865
|
+
|
|
866
|
+
it('parses truthy clauses', () => {
|
|
867
|
+
const query = '[truthyname]';
|
|
868
|
+
const [options, ...selectors] = queryParser({
|
|
869
|
+
query,
|
|
870
|
+
entityClass: BlogPost,
|
|
871
|
+
});
|
|
872
|
+
|
|
873
|
+
expect(options).toEqual({
|
|
874
|
+
class: BlogPost,
|
|
875
|
+
});
|
|
876
|
+
|
|
877
|
+
expect(selectors).toEqual([
|
|
878
|
+
{
|
|
879
|
+
type: '&',
|
|
880
|
+
truthy: ['truthyname'],
|
|
881
|
+
},
|
|
882
|
+
]);
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
it('parses not truthy clauses', () => {
|
|
886
|
+
const query = '-[truthyname]';
|
|
887
|
+
const [options, ...selectors] = queryParser({
|
|
888
|
+
query,
|
|
889
|
+
entityClass: BlogPost,
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
expect(options).toEqual({
|
|
893
|
+
class: BlogPost,
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
expect(selectors).toEqual([
|
|
897
|
+
{
|
|
898
|
+
type: '&',
|
|
899
|
+
'!truthy': ['truthyname'],
|
|
900
|
+
},
|
|
901
|
+
]);
|
|
902
|
+
});
|
|
903
|
+
|
|
904
|
+
it('parses ref clauses', () => {
|
|
905
|
+
const query = 'prop<{111111111111111111111111}>';
|
|
906
|
+
const [options, ...selectors] = queryParser({
|
|
907
|
+
query,
|
|
908
|
+
entityClass: BlogPost,
|
|
909
|
+
});
|
|
910
|
+
|
|
911
|
+
expect(options).toEqual({
|
|
912
|
+
class: BlogPost,
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
expect(selectors).toEqual([
|
|
916
|
+
{
|
|
917
|
+
type: '&',
|
|
918
|
+
ref: [['prop', '111111111111111111111111']],
|
|
919
|
+
},
|
|
920
|
+
]);
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
it('parses not ref clauses', () => {
|
|
924
|
+
const query = '-prop<{111111111111111111111111}>';
|
|
925
|
+
const [options, ...selectors] = queryParser({
|
|
926
|
+
query,
|
|
927
|
+
entityClass: BlogPost,
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
expect(options).toEqual({
|
|
931
|
+
class: BlogPost,
|
|
932
|
+
});
|
|
933
|
+
|
|
934
|
+
expect(selectors).toEqual([
|
|
935
|
+
{
|
|
936
|
+
type: '&',
|
|
937
|
+
'!ref': [['prop', '111111111111111111111111']],
|
|
938
|
+
},
|
|
939
|
+
]);
|
|
940
|
+
});
|
|
941
|
+
|
|
942
|
+
it('parses simple contain clauses', () => {
|
|
943
|
+
const query = 'prop<string>';
|
|
944
|
+
const [options, ...selectors] = queryParser({
|
|
945
|
+
query,
|
|
946
|
+
entityClass: BlogPost,
|
|
947
|
+
});
|
|
948
|
+
|
|
949
|
+
expect(options).toEqual({
|
|
950
|
+
class: BlogPost,
|
|
951
|
+
});
|
|
952
|
+
|
|
953
|
+
expect(selectors).toEqual([
|
|
954
|
+
{
|
|
955
|
+
type: '&',
|
|
956
|
+
contain: [['prop', 'string']],
|
|
957
|
+
},
|
|
958
|
+
]);
|
|
959
|
+
});
|
|
960
|
+
|
|
961
|
+
it('parses simple not contain clauses', () => {
|
|
962
|
+
const query = '-prop<string>';
|
|
178
963
|
const [options, ...selectors] = queryParser({
|
|
179
964
|
query,
|
|
180
965
|
entityClass: BlogPost,
|
|
@@ -187,13 +972,13 @@ describe('queryParser', () => {
|
|
|
187
972
|
expect(selectors).toEqual([
|
|
188
973
|
{
|
|
189
974
|
type: '&',
|
|
190
|
-
|
|
975
|
+
'!contain': [['prop', 'string']],
|
|
191
976
|
},
|
|
192
977
|
]);
|
|
193
978
|
});
|
|
194
979
|
|
|
195
|
-
it('parses
|
|
196
|
-
const query = 'prop
|
|
980
|
+
it('parses json contain clauses', () => {
|
|
981
|
+
const query = 'prop<true>';
|
|
197
982
|
const [options, ...selectors] = queryParser({
|
|
198
983
|
query,
|
|
199
984
|
entityClass: BlogPost,
|
|
@@ -206,13 +991,13 @@ describe('queryParser', () => {
|
|
|
206
991
|
expect(selectors).toEqual([
|
|
207
992
|
{
|
|
208
993
|
type: '&',
|
|
209
|
-
|
|
994
|
+
contain: [['prop', true]],
|
|
210
995
|
},
|
|
211
996
|
]);
|
|
212
997
|
});
|
|
213
998
|
|
|
214
|
-
it('parses
|
|
215
|
-
const query = 'prop
|
|
999
|
+
it('parses json not contain clauses', () => {
|
|
1000
|
+
const query = '-prop<true>';
|
|
216
1001
|
const [options, ...selectors] = queryParser({
|
|
217
1002
|
query,
|
|
218
1003
|
entityClass: BlogPost,
|
|
@@ -225,13 +1010,13 @@ describe('queryParser', () => {
|
|
|
225
1010
|
expect(selectors).toEqual([
|
|
226
1011
|
{
|
|
227
1012
|
type: '&',
|
|
228
|
-
|
|
1013
|
+
'!contain': [['prop', true]],
|
|
229
1014
|
},
|
|
230
1015
|
]);
|
|
231
1016
|
});
|
|
232
1017
|
|
|
233
|
-
it('parses
|
|
234
|
-
const query = 'prop
|
|
1018
|
+
it('parses match clauses', () => {
|
|
1019
|
+
const query = 'prop~/regex/';
|
|
235
1020
|
const [options, ...selectors] = queryParser({
|
|
236
1021
|
query,
|
|
237
1022
|
entityClass: BlogPost,
|
|
@@ -244,13 +1029,13 @@ describe('queryParser', () => {
|
|
|
244
1029
|
expect(selectors).toEqual([
|
|
245
1030
|
{
|
|
246
1031
|
type: '&',
|
|
247
|
-
|
|
1032
|
+
match: [['prop', 'regex']],
|
|
248
1033
|
},
|
|
249
1034
|
]);
|
|
250
1035
|
});
|
|
251
1036
|
|
|
252
|
-
it('parses
|
|
253
|
-
const query = 'prop
|
|
1037
|
+
it('parses not match clauses', () => {
|
|
1038
|
+
const query = '-prop~/regex/';
|
|
254
1039
|
const [options, ...selectors] = queryParser({
|
|
255
1040
|
query,
|
|
256
1041
|
entityClass: BlogPost,
|
|
@@ -263,13 +1048,13 @@ describe('queryParser', () => {
|
|
|
263
1048
|
expect(selectors).toEqual([
|
|
264
1049
|
{
|
|
265
1050
|
type: '&',
|
|
266
|
-
|
|
1051
|
+
'!match': [['prop', 'regex']],
|
|
267
1052
|
},
|
|
268
1053
|
]);
|
|
269
1054
|
});
|
|
270
1055
|
|
|
271
|
-
it('parses
|
|
272
|
-
const query = 'prop
|
|
1056
|
+
it('parses imatch clauses', () => {
|
|
1057
|
+
const query = 'prop~/regex/i';
|
|
273
1058
|
const [options, ...selectors] = queryParser({
|
|
274
1059
|
query,
|
|
275
1060
|
entityClass: BlogPost,
|
|
@@ -282,13 +1067,13 @@ describe('queryParser', () => {
|
|
|
282
1067
|
expect(selectors).toEqual([
|
|
283
1068
|
{
|
|
284
1069
|
type: '&',
|
|
285
|
-
|
|
1070
|
+
imatch: [['prop', 'regex']],
|
|
286
1071
|
},
|
|
287
1072
|
]);
|
|
288
1073
|
});
|
|
289
1074
|
|
|
290
|
-
it('parses
|
|
291
|
-
const query = '
|
|
1075
|
+
it('parses not imatch clauses', () => {
|
|
1076
|
+
const query = '-prop~/regex/i';
|
|
292
1077
|
const [options, ...selectors] = queryParser({
|
|
293
1078
|
query,
|
|
294
1079
|
entityClass: BlogPost,
|
|
@@ -301,13 +1086,13 @@ describe('queryParser', () => {
|
|
|
301
1086
|
expect(selectors).toEqual([
|
|
302
1087
|
{
|
|
303
1088
|
type: '&',
|
|
304
|
-
|
|
1089
|
+
'!imatch': [['prop', 'regex']],
|
|
305
1090
|
},
|
|
306
1091
|
]);
|
|
307
1092
|
});
|
|
308
1093
|
|
|
309
|
-
it('parses
|
|
310
|
-
const query = '
|
|
1094
|
+
it('parses simple like clauses', () => {
|
|
1095
|
+
const query = 'prop~pattern';
|
|
311
1096
|
const [options, ...selectors] = queryParser({
|
|
312
1097
|
query,
|
|
313
1098
|
entityClass: BlogPost,
|
|
@@ -320,13 +1105,13 @@ describe('queryParser', () => {
|
|
|
320
1105
|
expect(selectors).toEqual([
|
|
321
1106
|
{
|
|
322
1107
|
type: '&',
|
|
323
|
-
|
|
1108
|
+
like: [['prop', 'pattern']],
|
|
324
1109
|
},
|
|
325
1110
|
]);
|
|
326
1111
|
});
|
|
327
1112
|
|
|
328
|
-
it('parses
|
|
329
|
-
const query = '
|
|
1113
|
+
it('parses simple not like clauses', () => {
|
|
1114
|
+
const query = '-prop~pattern';
|
|
330
1115
|
const [options, ...selectors] = queryParser({
|
|
331
1116
|
query,
|
|
332
1117
|
entityClass: BlogPost,
|
|
@@ -339,13 +1124,13 @@ describe('queryParser', () => {
|
|
|
339
1124
|
expect(selectors).toEqual([
|
|
340
1125
|
{
|
|
341
1126
|
type: '&',
|
|
342
|
-
|
|
1127
|
+
'!like': [['prop', 'pattern']],
|
|
343
1128
|
},
|
|
344
1129
|
]);
|
|
345
1130
|
});
|
|
346
1131
|
|
|
347
|
-
it('parses
|
|
348
|
-
const query = '
|
|
1132
|
+
it('parses quoted like clauses', () => {
|
|
1133
|
+
const query = 'prop~"a pattern"';
|
|
349
1134
|
const [options, ...selectors] = queryParser({
|
|
350
1135
|
query,
|
|
351
1136
|
entityClass: BlogPost,
|
|
@@ -358,13 +1143,13 @@ describe('queryParser', () => {
|
|
|
358
1143
|
expect(selectors).toEqual([
|
|
359
1144
|
{
|
|
360
1145
|
type: '&',
|
|
361
|
-
|
|
1146
|
+
like: [['prop', 'a pattern']],
|
|
362
1147
|
},
|
|
363
1148
|
]);
|
|
364
1149
|
});
|
|
365
1150
|
|
|
366
|
-
it('parses
|
|
367
|
-
const query = '
|
|
1151
|
+
it('parses quoted not like clauses', () => {
|
|
1152
|
+
const query = '-prop~"a pattern"';
|
|
368
1153
|
const [options, ...selectors] = queryParser({
|
|
369
1154
|
query,
|
|
370
1155
|
entityClass: BlogPost,
|
|
@@ -377,13 +1162,13 @@ describe('queryParser', () => {
|
|
|
377
1162
|
expect(selectors).toEqual([
|
|
378
1163
|
{
|
|
379
1164
|
type: '&',
|
|
380
|
-
|
|
1165
|
+
'!like': [['prop', 'a pattern']],
|
|
381
1166
|
},
|
|
382
1167
|
]);
|
|
383
1168
|
});
|
|
384
1169
|
|
|
385
|
-
it('parses
|
|
386
|
-
const query = '
|
|
1170
|
+
it('parses ilike clauses', () => {
|
|
1171
|
+
const query = 'prop~"a pattern"i';
|
|
387
1172
|
const [options, ...selectors] = queryParser({
|
|
388
1173
|
query,
|
|
389
1174
|
entityClass: BlogPost,
|
|
@@ -396,13 +1181,13 @@ describe('queryParser', () => {
|
|
|
396
1181
|
expect(selectors).toEqual([
|
|
397
1182
|
{
|
|
398
1183
|
type: '&',
|
|
399
|
-
|
|
1184
|
+
ilike: [['prop', 'a pattern']],
|
|
400
1185
|
},
|
|
401
1186
|
]);
|
|
402
1187
|
});
|
|
403
1188
|
|
|
404
|
-
it('parses
|
|
405
|
-
const query = 'prop
|
|
1189
|
+
it('parses not ilike clauses', () => {
|
|
1190
|
+
const query = '-prop~"a pattern"i';
|
|
406
1191
|
const [options, ...selectors] = queryParser({
|
|
407
1192
|
query,
|
|
408
1193
|
entityClass: BlogPost,
|
|
@@ -415,13 +1200,13 @@ describe('queryParser', () => {
|
|
|
415
1200
|
expect(selectors).toEqual([
|
|
416
1201
|
{
|
|
417
1202
|
type: '&',
|
|
418
|
-
|
|
1203
|
+
'!ilike': [['prop', 'a pattern']],
|
|
419
1204
|
},
|
|
420
1205
|
]);
|
|
421
1206
|
});
|
|
422
1207
|
|
|
423
|
-
it('parses
|
|
424
|
-
const query = 'prop
|
|
1208
|
+
it('parses simple gt clauses', () => {
|
|
1209
|
+
const query = 'prop>30.5';
|
|
425
1210
|
const [options, ...selectors] = queryParser({
|
|
426
1211
|
query,
|
|
427
1212
|
entityClass: BlogPost,
|
|
@@ -434,13 +1219,13 @@ describe('queryParser', () => {
|
|
|
434
1219
|
expect(selectors).toEqual([
|
|
435
1220
|
{
|
|
436
1221
|
type: '&',
|
|
437
|
-
|
|
1222
|
+
gt: [['prop', 30.5]],
|
|
438
1223
|
},
|
|
439
1224
|
]);
|
|
440
1225
|
});
|
|
441
1226
|
|
|
442
|
-
it('parses simple
|
|
443
|
-
const query = 'prop
|
|
1227
|
+
it('parses simple not gt clauses', () => {
|
|
1228
|
+
const query = '-prop>30.5';
|
|
444
1229
|
const [options, ...selectors] = queryParser({
|
|
445
1230
|
query,
|
|
446
1231
|
entityClass: BlogPost,
|
|
@@ -453,13 +1238,13 @@ describe('queryParser', () => {
|
|
|
453
1238
|
expect(selectors).toEqual([
|
|
454
1239
|
{
|
|
455
1240
|
type: '&',
|
|
456
|
-
|
|
1241
|
+
'!gt': [['prop', 30.5]],
|
|
457
1242
|
},
|
|
458
1243
|
]);
|
|
459
1244
|
});
|
|
460
1245
|
|
|
461
|
-
it('parses simple
|
|
462
|
-
const query = 'prop
|
|
1246
|
+
it('parses simple relative gt clauses', () => {
|
|
1247
|
+
const query = 'prop>yesterday';
|
|
463
1248
|
const [options, ...selectors] = queryParser({
|
|
464
1249
|
query,
|
|
465
1250
|
entityClass: BlogPost,
|
|
@@ -472,13 +1257,13 @@ describe('queryParser', () => {
|
|
|
472
1257
|
expect(selectors).toEqual([
|
|
473
1258
|
{
|
|
474
1259
|
type: '&',
|
|
475
|
-
|
|
1260
|
+
gt: [['prop', null, 'yesterday']],
|
|
476
1261
|
},
|
|
477
1262
|
]);
|
|
478
1263
|
});
|
|
479
1264
|
|
|
480
|
-
it('parses
|
|
481
|
-
const query = 'prop
|
|
1265
|
+
it('parses simple relative not gt clauses', () => {
|
|
1266
|
+
const query = '-prop>yesterday';
|
|
482
1267
|
const [options, ...selectors] = queryParser({
|
|
483
1268
|
query,
|
|
484
1269
|
entityClass: BlogPost,
|
|
@@ -491,13 +1276,13 @@ describe('queryParser', () => {
|
|
|
491
1276
|
expect(selectors).toEqual([
|
|
492
1277
|
{
|
|
493
1278
|
type: '&',
|
|
494
|
-
|
|
1279
|
+
'!gt': [['prop', null, 'yesterday']],
|
|
495
1280
|
},
|
|
496
1281
|
]);
|
|
497
1282
|
});
|
|
498
1283
|
|
|
499
|
-
it('parses
|
|
500
|
-
const query = 'prop
|
|
1284
|
+
it('parses quote relative gt clauses', () => {
|
|
1285
|
+
const query = 'prop>"3 weeks ago"';
|
|
501
1286
|
const [options, ...selectors] = queryParser({
|
|
502
1287
|
query,
|
|
503
1288
|
entityClass: BlogPost,
|
|
@@ -510,13 +1295,13 @@ describe('queryParser', () => {
|
|
|
510
1295
|
expect(selectors).toEqual([
|
|
511
1296
|
{
|
|
512
1297
|
type: '&',
|
|
513
|
-
|
|
1298
|
+
gt: [['prop', null, '3 weeks ago']],
|
|
514
1299
|
},
|
|
515
1300
|
]);
|
|
516
1301
|
});
|
|
517
1302
|
|
|
518
|
-
it('parses
|
|
519
|
-
const query = 'prop
|
|
1303
|
+
it('parses quote relative not gt clauses', () => {
|
|
1304
|
+
const query = '-prop>"3 weeks ago"';
|
|
520
1305
|
const [options, ...selectors] = queryParser({
|
|
521
1306
|
query,
|
|
522
1307
|
entityClass: BlogPost,
|
|
@@ -529,13 +1314,13 @@ describe('queryParser', () => {
|
|
|
529
1314
|
expect(selectors).toEqual([
|
|
530
1315
|
{
|
|
531
1316
|
type: '&',
|
|
532
|
-
|
|
1317
|
+
'!gt': [['prop', null, '3 weeks ago']],
|
|
533
1318
|
},
|
|
534
1319
|
]);
|
|
535
1320
|
});
|
|
536
1321
|
|
|
537
|
-
it('parses
|
|
538
|
-
const query = 'prop
|
|
1322
|
+
it('parses simple gte clauses', () => {
|
|
1323
|
+
const query = 'prop>=30.5';
|
|
539
1324
|
const [options, ...selectors] = queryParser({
|
|
540
1325
|
query,
|
|
541
1326
|
entityClass: BlogPost,
|
|
@@ -548,13 +1333,13 @@ describe('queryParser', () => {
|
|
|
548
1333
|
expect(selectors).toEqual([
|
|
549
1334
|
{
|
|
550
1335
|
type: '&',
|
|
551
|
-
|
|
1336
|
+
gte: [['prop', 30.5]],
|
|
552
1337
|
},
|
|
553
1338
|
]);
|
|
554
1339
|
});
|
|
555
1340
|
|
|
556
|
-
it('parses
|
|
557
|
-
const query = 'prop
|
|
1341
|
+
it('parses simple not gte clauses', () => {
|
|
1342
|
+
const query = '-prop>=30.5';
|
|
558
1343
|
const [options, ...selectors] = queryParser({
|
|
559
1344
|
query,
|
|
560
1345
|
entityClass: BlogPost,
|
|
@@ -567,13 +1352,13 @@ describe('queryParser', () => {
|
|
|
567
1352
|
expect(selectors).toEqual([
|
|
568
1353
|
{
|
|
569
1354
|
type: '&',
|
|
570
|
-
|
|
1355
|
+
'!gte': [['prop', 30.5]],
|
|
571
1356
|
},
|
|
572
1357
|
]);
|
|
573
1358
|
});
|
|
574
1359
|
|
|
575
|
-
it('parses
|
|
576
|
-
const query = 'prop
|
|
1360
|
+
it('parses simple relative gte clauses', () => {
|
|
1361
|
+
const query = 'prop>=yesterday';
|
|
577
1362
|
const [options, ...selectors] = queryParser({
|
|
578
1363
|
query,
|
|
579
1364
|
entityClass: BlogPost,
|
|
@@ -586,13 +1371,13 @@ describe('queryParser', () => {
|
|
|
586
1371
|
expect(selectors).toEqual([
|
|
587
1372
|
{
|
|
588
1373
|
type: '&',
|
|
589
|
-
|
|
1374
|
+
gte: [['prop', null, 'yesterday']],
|
|
590
1375
|
},
|
|
591
1376
|
]);
|
|
592
1377
|
});
|
|
593
1378
|
|
|
594
|
-
it('parses simple
|
|
595
|
-
const query = 'prop
|
|
1379
|
+
it('parses simple relative not gte clauses', () => {
|
|
1380
|
+
const query = '-prop>=yesterday';
|
|
596
1381
|
const [options, ...selectors] = queryParser({
|
|
597
1382
|
query,
|
|
598
1383
|
entityClass: BlogPost,
|
|
@@ -605,13 +1390,13 @@ describe('queryParser', () => {
|
|
|
605
1390
|
expect(selectors).toEqual([
|
|
606
1391
|
{
|
|
607
1392
|
type: '&',
|
|
608
|
-
|
|
1393
|
+
'!gte': [['prop', null, 'yesterday']],
|
|
609
1394
|
},
|
|
610
1395
|
]);
|
|
611
1396
|
});
|
|
612
1397
|
|
|
613
|
-
it('parses
|
|
614
|
-
const query = 'prop
|
|
1398
|
+
it('parses quote relative gte clauses', () => {
|
|
1399
|
+
const query = 'prop>="3 weeks ago"';
|
|
615
1400
|
const [options, ...selectors] = queryParser({
|
|
616
1401
|
query,
|
|
617
1402
|
entityClass: BlogPost,
|
|
@@ -624,13 +1409,13 @@ describe('queryParser', () => {
|
|
|
624
1409
|
expect(selectors).toEqual([
|
|
625
1410
|
{
|
|
626
1411
|
type: '&',
|
|
627
|
-
|
|
1412
|
+
gte: [['prop', null, '3 weeks ago']],
|
|
628
1413
|
},
|
|
629
1414
|
]);
|
|
630
1415
|
});
|
|
631
1416
|
|
|
632
|
-
it('parses
|
|
633
|
-
const query = 'prop
|
|
1417
|
+
it('parses quote relative not gte clauses', () => {
|
|
1418
|
+
const query = '-prop>="3 weeks ago"';
|
|
634
1419
|
const [options, ...selectors] = queryParser({
|
|
635
1420
|
query,
|
|
636
1421
|
entityClass: BlogPost,
|
|
@@ -643,13 +1428,13 @@ describe('queryParser', () => {
|
|
|
643
1428
|
expect(selectors).toEqual([
|
|
644
1429
|
{
|
|
645
1430
|
type: '&',
|
|
646
|
-
|
|
1431
|
+
'!gte': [['prop', null, '3 weeks ago']],
|
|
647
1432
|
},
|
|
648
1433
|
]);
|
|
649
1434
|
});
|
|
650
1435
|
|
|
651
|
-
it('parses
|
|
652
|
-
const query = 'prop
|
|
1436
|
+
it('parses simple lt clauses', () => {
|
|
1437
|
+
const query = 'prop<30.5';
|
|
653
1438
|
const [options, ...selectors] = queryParser({
|
|
654
1439
|
query,
|
|
655
1440
|
entityClass: BlogPost,
|
|
@@ -662,13 +1447,13 @@ describe('queryParser', () => {
|
|
|
662
1447
|
expect(selectors).toEqual([
|
|
663
1448
|
{
|
|
664
1449
|
type: '&',
|
|
665
|
-
|
|
1450
|
+
lt: [['prop', 30.5]],
|
|
666
1451
|
},
|
|
667
1452
|
]);
|
|
668
1453
|
});
|
|
669
1454
|
|
|
670
|
-
it('parses
|
|
671
|
-
const query = 'prop
|
|
1455
|
+
it('parses simple not lt clauses', () => {
|
|
1456
|
+
const query = '-prop<30.5';
|
|
672
1457
|
const [options, ...selectors] = queryParser({
|
|
673
1458
|
query,
|
|
674
1459
|
entityClass: BlogPost,
|
|
@@ -681,13 +1466,13 @@ describe('queryParser', () => {
|
|
|
681
1466
|
expect(selectors).toEqual([
|
|
682
1467
|
{
|
|
683
1468
|
type: '&',
|
|
684
|
-
|
|
1469
|
+
'!lt': [['prop', 30.5]],
|
|
685
1470
|
},
|
|
686
1471
|
]);
|
|
687
1472
|
});
|
|
688
1473
|
|
|
689
|
-
it('parses
|
|
690
|
-
const query = 'prop
|
|
1474
|
+
it('parses simple relative lt clauses', () => {
|
|
1475
|
+
const query = 'prop<yesterday';
|
|
691
1476
|
const [options, ...selectors] = queryParser({
|
|
692
1477
|
query,
|
|
693
1478
|
entityClass: BlogPost,
|
|
@@ -700,13 +1485,13 @@ describe('queryParser', () => {
|
|
|
700
1485
|
expect(selectors).toEqual([
|
|
701
1486
|
{
|
|
702
1487
|
type: '&',
|
|
703
|
-
|
|
1488
|
+
lt: [['prop', null, 'yesterday']],
|
|
704
1489
|
},
|
|
705
1490
|
]);
|
|
706
1491
|
});
|
|
707
1492
|
|
|
708
|
-
it('parses simple
|
|
709
|
-
const query = 'prop
|
|
1493
|
+
it('parses simple relative not lt clauses', () => {
|
|
1494
|
+
const query = '-prop<yesterday';
|
|
710
1495
|
const [options, ...selectors] = queryParser({
|
|
711
1496
|
query,
|
|
712
1497
|
entityClass: BlogPost,
|
|
@@ -719,13 +1504,13 @@ describe('queryParser', () => {
|
|
|
719
1504
|
expect(selectors).toEqual([
|
|
720
1505
|
{
|
|
721
1506
|
type: '&',
|
|
722
|
-
|
|
1507
|
+
'!lt': [['prop', null, 'yesterday']],
|
|
723
1508
|
},
|
|
724
1509
|
]);
|
|
725
1510
|
});
|
|
726
1511
|
|
|
727
|
-
it('parses
|
|
728
|
-
const query = 'prop
|
|
1512
|
+
it('parses quote relative lt clauses', () => {
|
|
1513
|
+
const query = 'prop<"3 weeks ago"';
|
|
729
1514
|
const [options, ...selectors] = queryParser({
|
|
730
1515
|
query,
|
|
731
1516
|
entityClass: BlogPost,
|
|
@@ -738,13 +1523,13 @@ describe('queryParser', () => {
|
|
|
738
1523
|
expect(selectors).toEqual([
|
|
739
1524
|
{
|
|
740
1525
|
type: '&',
|
|
741
|
-
|
|
1526
|
+
lt: [['prop', null, '3 weeks ago']],
|
|
742
1527
|
},
|
|
743
1528
|
]);
|
|
744
1529
|
});
|
|
745
1530
|
|
|
746
|
-
it('parses quote relative
|
|
747
|
-
const query = 'prop
|
|
1531
|
+
it('parses quote relative not lt clauses', () => {
|
|
1532
|
+
const query = '-prop<"3 weeks ago"';
|
|
748
1533
|
const [options, ...selectors] = queryParser({
|
|
749
1534
|
query,
|
|
750
1535
|
entityClass: BlogPost,
|
|
@@ -757,13 +1542,13 @@ describe('queryParser', () => {
|
|
|
757
1542
|
expect(selectors).toEqual([
|
|
758
1543
|
{
|
|
759
1544
|
type: '&',
|
|
760
|
-
|
|
1545
|
+
'!lt': [['prop', null, '3 weeks ago']],
|
|
761
1546
|
},
|
|
762
1547
|
]);
|
|
763
1548
|
});
|
|
764
1549
|
|
|
765
|
-
it('parses simple
|
|
766
|
-
const query = 'prop
|
|
1550
|
+
it('parses simple lte clauses', () => {
|
|
1551
|
+
const query = 'prop<=30.5';
|
|
767
1552
|
const [options, ...selectors] = queryParser({
|
|
768
1553
|
query,
|
|
769
1554
|
entityClass: BlogPost,
|
|
@@ -776,13 +1561,13 @@ describe('queryParser', () => {
|
|
|
776
1561
|
expect(selectors).toEqual([
|
|
777
1562
|
{
|
|
778
1563
|
type: '&',
|
|
779
|
-
|
|
1564
|
+
lte: [['prop', 30.5]],
|
|
780
1565
|
},
|
|
781
1566
|
]);
|
|
782
1567
|
});
|
|
783
1568
|
|
|
784
|
-
it('parses simple
|
|
785
|
-
const query = 'prop
|
|
1569
|
+
it('parses simple not lte clauses', () => {
|
|
1570
|
+
const query = '-prop<=30.5';
|
|
786
1571
|
const [options, ...selectors] = queryParser({
|
|
787
1572
|
query,
|
|
788
1573
|
entityClass: BlogPost,
|
|
@@ -795,13 +1580,13 @@ describe('queryParser', () => {
|
|
|
795
1580
|
expect(selectors).toEqual([
|
|
796
1581
|
{
|
|
797
1582
|
type: '&',
|
|
798
|
-
|
|
1583
|
+
'!lte': [['prop', 30.5]],
|
|
799
1584
|
},
|
|
800
1585
|
]);
|
|
801
1586
|
});
|
|
802
1587
|
|
|
803
|
-
it('parses
|
|
804
|
-
const query = 'prop
|
|
1588
|
+
it('parses simple relative lte clauses', () => {
|
|
1589
|
+
const query = 'prop<=yesterday';
|
|
805
1590
|
const [options, ...selectors] = queryParser({
|
|
806
1591
|
query,
|
|
807
1592
|
entityClass: BlogPost,
|
|
@@ -814,13 +1599,13 @@ describe('queryParser', () => {
|
|
|
814
1599
|
expect(selectors).toEqual([
|
|
815
1600
|
{
|
|
816
1601
|
type: '&',
|
|
817
|
-
|
|
1602
|
+
lte: [['prop', null, 'yesterday']],
|
|
818
1603
|
},
|
|
819
1604
|
]);
|
|
820
1605
|
});
|
|
821
1606
|
|
|
822
|
-
it('parses simple
|
|
823
|
-
const query = 'prop
|
|
1607
|
+
it('parses simple relative not lte clauses', () => {
|
|
1608
|
+
const query = '-prop<=yesterday';
|
|
824
1609
|
const [options, ...selectors] = queryParser({
|
|
825
1610
|
query,
|
|
826
1611
|
entityClass: BlogPost,
|
|
@@ -833,13 +1618,13 @@ describe('queryParser', () => {
|
|
|
833
1618
|
expect(selectors).toEqual([
|
|
834
1619
|
{
|
|
835
1620
|
type: '&',
|
|
836
|
-
|
|
1621
|
+
'!lte': [['prop', null, 'yesterday']],
|
|
837
1622
|
},
|
|
838
1623
|
]);
|
|
839
1624
|
});
|
|
840
1625
|
|
|
841
|
-
it('parses
|
|
842
|
-
const query = 'prop
|
|
1626
|
+
it('parses quote relative lte clauses', () => {
|
|
1627
|
+
const query = 'prop<="3 weeks ago"';
|
|
843
1628
|
const [options, ...selectors] = queryParser({
|
|
844
1629
|
query,
|
|
845
1630
|
entityClass: BlogPost,
|
|
@@ -852,13 +1637,13 @@ describe('queryParser', () => {
|
|
|
852
1637
|
expect(selectors).toEqual([
|
|
853
1638
|
{
|
|
854
1639
|
type: '&',
|
|
855
|
-
|
|
1640
|
+
lte: [['prop', null, '3 weeks ago']],
|
|
856
1641
|
},
|
|
857
1642
|
]);
|
|
858
1643
|
});
|
|
859
1644
|
|
|
860
|
-
it('parses quote relative
|
|
861
|
-
const query = 'prop
|
|
1645
|
+
it('parses quote relative not lte clauses', () => {
|
|
1646
|
+
const query = '-prop<="3 weeks ago"';
|
|
862
1647
|
const [options, ...selectors] = queryParser({
|
|
863
1648
|
query,
|
|
864
1649
|
entityClass: BlogPost,
|
|
@@ -871,13 +1656,14 @@ describe('queryParser', () => {
|
|
|
871
1656
|
expect(selectors).toEqual([
|
|
872
1657
|
{
|
|
873
1658
|
type: '&',
|
|
874
|
-
|
|
1659
|
+
'!lte': [['prop', null, '3 weeks ago']],
|
|
875
1660
|
},
|
|
876
1661
|
]);
|
|
877
1662
|
});
|
|
878
1663
|
|
|
879
|
-
it('parses
|
|
880
|
-
const query =
|
|
1664
|
+
it('parses complex selectors', () => {
|
|
1665
|
+
const query =
|
|
1666
|
+
'(! [published] <draft>) (| -cdate>"6 months ago" mdate>"1 month ago")';
|
|
881
1667
|
const [options, ...selectors] = queryParser({
|
|
882
1668
|
query,
|
|
883
1669
|
entityClass: BlogPost,
|
|
@@ -890,13 +1676,25 @@ describe('queryParser', () => {
|
|
|
890
1676
|
expect(selectors).toEqual([
|
|
891
1677
|
{
|
|
892
1678
|
type: '&',
|
|
893
|
-
|
|
1679
|
+
selector: [
|
|
1680
|
+
{
|
|
1681
|
+
type: '|',
|
|
1682
|
+
'!gt': [['cdate', null, '6 months ago']],
|
|
1683
|
+
gt: [['mdate', null, '1 month ago']],
|
|
1684
|
+
},
|
|
1685
|
+
{
|
|
1686
|
+
type: '!&',
|
|
1687
|
+
truthy: ['published'],
|
|
1688
|
+
tag: ['draft'],
|
|
1689
|
+
},
|
|
1690
|
+
],
|
|
894
1691
|
},
|
|
895
1692
|
]);
|
|
896
1693
|
});
|
|
897
1694
|
|
|
898
|
-
it('parses
|
|
899
|
-
const query =
|
|
1695
|
+
it('parses nested selectors', () => {
|
|
1696
|
+
const query =
|
|
1697
|
+
'(! [published] <draft> (| -cdate>"6 months ago" mdate>"1 month ago"))';
|
|
900
1698
|
const [options, ...selectors] = queryParser({
|
|
901
1699
|
query,
|
|
902
1700
|
entityClass: BlogPost,
|
|
@@ -908,17 +1706,37 @@ describe('queryParser', () => {
|
|
|
908
1706
|
|
|
909
1707
|
expect(selectors).toEqual([
|
|
910
1708
|
{
|
|
911
|
-
type: '
|
|
912
|
-
|
|
1709
|
+
type: '!&',
|
|
1710
|
+
truthy: ['published'],
|
|
1711
|
+
tag: ['draft'],
|
|
1712
|
+
selector: [
|
|
1713
|
+
{
|
|
1714
|
+
type: '|',
|
|
1715
|
+
'!gt': [['cdate', null, '6 months ago']],
|
|
1716
|
+
gt: [['mdate', null, '1 month ago']],
|
|
1717
|
+
},
|
|
1718
|
+
],
|
|
913
1719
|
},
|
|
914
1720
|
]);
|
|
915
1721
|
});
|
|
916
1722
|
|
|
917
|
-
it('parses
|
|
918
|
-
const query =
|
|
1723
|
+
it('parses nested qref clauses', () => {
|
|
1724
|
+
const query =
|
|
1725
|
+
'categories<{Category parent<{Category list<{List frosting name(favorite)}>}> -parent<{Category id="sort+newsletters"}>}>';
|
|
919
1726
|
const [options, ...selectors] = queryParser({
|
|
920
1727
|
query,
|
|
921
1728
|
entityClass: BlogPost,
|
|
1729
|
+
defaultFields: ['title', 'body'],
|
|
1730
|
+
qrefMap: {
|
|
1731
|
+
Category: {
|
|
1732
|
+
class: Category,
|
|
1733
|
+
defaultFields: ['name'],
|
|
1734
|
+
},
|
|
1735
|
+
List: {
|
|
1736
|
+
class: List,
|
|
1737
|
+
defaultFields: ['name'],
|
|
1738
|
+
},
|
|
1739
|
+
},
|
|
922
1740
|
});
|
|
923
1741
|
|
|
924
1742
|
expect(options).toEqual({
|
|
@@ -928,14 +1746,62 @@ describe('queryParser', () => {
|
|
|
928
1746
|
expect(selectors).toEqual([
|
|
929
1747
|
{
|
|
930
1748
|
type: '&',
|
|
931
|
-
|
|
1749
|
+
qref: [
|
|
1750
|
+
[
|
|
1751
|
+
'categories',
|
|
1752
|
+
[
|
|
1753
|
+
{ class: Category },
|
|
1754
|
+
{
|
|
1755
|
+
type: '&',
|
|
1756
|
+
qref: [
|
|
1757
|
+
[
|
|
1758
|
+
'parent',
|
|
1759
|
+
[
|
|
1760
|
+
{ class: Category },
|
|
1761
|
+
{
|
|
1762
|
+
type: '&',
|
|
1763
|
+
qref: [
|
|
1764
|
+
[
|
|
1765
|
+
'list',
|
|
1766
|
+
[
|
|
1767
|
+
{ class: List },
|
|
1768
|
+
{
|
|
1769
|
+
type: '&',
|
|
1770
|
+
search: [['name', 'favorite']],
|
|
1771
|
+
},
|
|
1772
|
+
{
|
|
1773
|
+
type: '|',
|
|
1774
|
+
ilike: [['name', '%frosting%']],
|
|
1775
|
+
},
|
|
1776
|
+
],
|
|
1777
|
+
],
|
|
1778
|
+
],
|
|
1779
|
+
},
|
|
1780
|
+
],
|
|
1781
|
+
],
|
|
1782
|
+
],
|
|
1783
|
+
'!qref': [
|
|
1784
|
+
[
|
|
1785
|
+
'parent',
|
|
1786
|
+
[
|
|
1787
|
+
{ class: Category },
|
|
1788
|
+
{
|
|
1789
|
+
type: '&',
|
|
1790
|
+
equal: [['id', 'sort+newsletters']],
|
|
1791
|
+
},
|
|
1792
|
+
],
|
|
1793
|
+
],
|
|
1794
|
+
],
|
|
1795
|
+
},
|
|
1796
|
+
],
|
|
1797
|
+
],
|
|
1798
|
+
],
|
|
932
1799
|
},
|
|
933
1800
|
]);
|
|
934
1801
|
});
|
|
935
1802
|
|
|
936
|
-
it('
|
|
937
|
-
const query =
|
|
938
|
-
'(! [published] <draft>) (| cdate>"6 months ago" mdate>"1 month ago")';
|
|
1803
|
+
it('handles badly nested qref', () => {
|
|
1804
|
+
const query = 'categories<{Category parent<{Category id="top"}>';
|
|
939
1805
|
const [options, ...selectors] = queryParser({
|
|
940
1806
|
query,
|
|
941
1807
|
entityClass: BlogPost,
|
|
@@ -948,50 +1814,126 @@ describe('queryParser', () => {
|
|
|
948
1814
|
expect(selectors).toEqual([
|
|
949
1815
|
{
|
|
950
1816
|
type: '&',
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
type: '|',
|
|
954
|
-
gt: [
|
|
955
|
-
['cdate', null, '6 months ago'],
|
|
956
|
-
['mdate', null, '1 month ago'],
|
|
957
|
-
],
|
|
958
|
-
},
|
|
959
|
-
{
|
|
960
|
-
type: '!&',
|
|
961
|
-
truthy: ['published'],
|
|
962
|
-
tag: ['draft'],
|
|
963
|
-
},
|
|
964
|
-
],
|
|
1817
|
+
contain: [['categories', '{Category parent<{Category}']],
|
|
1818
|
+
equal: [['id', 'top']],
|
|
965
1819
|
},
|
|
966
1820
|
]);
|
|
967
1821
|
});
|
|
968
1822
|
|
|
969
|
-
it('parses
|
|
1823
|
+
it('parses a realistic query', () => {
|
|
970
1824
|
const query =
|
|
971
|
-
'
|
|
1825
|
+
'labels<{Label [aggbox]}> -[trash] [delivered] -<spam> -<bare> -<autoreply> -<draft> -<sent> limit:10 reverse:true';
|
|
972
1826
|
const [options, ...selectors] = queryParser({
|
|
973
1827
|
query,
|
|
974
|
-
entityClass:
|
|
1828
|
+
entityClass: Mail,
|
|
1829
|
+
defaultFields: ['subject', 'from', 'sender'],
|
|
1830
|
+
qrefMap: {
|
|
1831
|
+
Mail: {
|
|
1832
|
+
class: Mail,
|
|
1833
|
+
defaultFields: ['subject', 'from', 'sender'],
|
|
1834
|
+
},
|
|
1835
|
+
Headers: {
|
|
1836
|
+
class: Headers,
|
|
1837
|
+
defaultFields: ['Message-ID'],
|
|
1838
|
+
},
|
|
1839
|
+
Body: {
|
|
1840
|
+
class: Body,
|
|
1841
|
+
defaultFields: ['text'],
|
|
1842
|
+
},
|
|
1843
|
+
Label: {
|
|
1844
|
+
class: Label,
|
|
1845
|
+
defaultFields: ['name', 'id'],
|
|
1846
|
+
},
|
|
1847
|
+
Domain: {
|
|
1848
|
+
class: Domain,
|
|
1849
|
+
defaultFields: ['fqdn'],
|
|
1850
|
+
},
|
|
1851
|
+
},
|
|
1852
|
+
bareHandler: (
|
|
1853
|
+
input,
|
|
1854
|
+
entityClass,
|
|
1855
|
+
defaultFields = ['subject', 'from', 'sender'],
|
|
1856
|
+
) => {
|
|
1857
|
+
if (entityClass === Mail) {
|
|
1858
|
+
return {
|
|
1859
|
+
type: '|',
|
|
1860
|
+
search: defaultFields.map((field) => [field, input]) as [
|
|
1861
|
+
string,
|
|
1862
|
+
string,
|
|
1863
|
+
][],
|
|
1864
|
+
qref: [
|
|
1865
|
+
[
|
|
1866
|
+
'body',
|
|
1867
|
+
[
|
|
1868
|
+
{ class: Body },
|
|
1869
|
+
{
|
|
1870
|
+
type: '&',
|
|
1871
|
+
search: ['text', input],
|
|
1872
|
+
},
|
|
1873
|
+
],
|
|
1874
|
+
],
|
|
1875
|
+
[
|
|
1876
|
+
'body',
|
|
1877
|
+
[
|
|
1878
|
+
{ class: Body },
|
|
1879
|
+
{
|
|
1880
|
+
type: '&',
|
|
1881
|
+
search: ['html', input],
|
|
1882
|
+
},
|
|
1883
|
+
],
|
|
1884
|
+
],
|
|
1885
|
+
[
|
|
1886
|
+
'body',
|
|
1887
|
+
[
|
|
1888
|
+
{ class: Body },
|
|
1889
|
+
{
|
|
1890
|
+
type: '&',
|
|
1891
|
+
search: ['attachments', input],
|
|
1892
|
+
},
|
|
1893
|
+
],
|
|
1894
|
+
],
|
|
1895
|
+
],
|
|
1896
|
+
};
|
|
1897
|
+
}
|
|
1898
|
+
if (defaultFields.length) {
|
|
1899
|
+
return {
|
|
1900
|
+
type: '|',
|
|
1901
|
+
search: defaultFields.map((field) => [field, input]) as [
|
|
1902
|
+
string,
|
|
1903
|
+
string,
|
|
1904
|
+
][],
|
|
1905
|
+
};
|
|
1906
|
+
}
|
|
1907
|
+
return {};
|
|
1908
|
+
},
|
|
975
1909
|
});
|
|
976
1910
|
|
|
977
1911
|
expect(options).toEqual({
|
|
978
|
-
class:
|
|
1912
|
+
class: Mail,
|
|
1913
|
+
limit: 10,
|
|
1914
|
+
reverse: true,
|
|
979
1915
|
});
|
|
980
1916
|
|
|
981
1917
|
expect(selectors).toEqual([
|
|
982
1918
|
{
|
|
983
|
-
type: '
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
1919
|
+
type: '&',
|
|
1920
|
+
'!tag': ['spam', 'bare', 'autoreply', 'draft', 'sent'],
|
|
1921
|
+
'!truthy': ['trash'],
|
|
1922
|
+
qref: [
|
|
1923
|
+
[
|
|
1924
|
+
'labels',
|
|
1925
|
+
[
|
|
1926
|
+
{
|
|
1927
|
+
class: Label,
|
|
1928
|
+
},
|
|
1929
|
+
{
|
|
1930
|
+
truthy: ['aggbox'],
|
|
1931
|
+
type: '&',
|
|
1932
|
+
},
|
|
992
1933
|
],
|
|
993
|
-
|
|
1934
|
+
],
|
|
994
1935
|
],
|
|
1936
|
+
truthy: ['delivered'],
|
|
995
1937
|
},
|
|
996
1938
|
]);
|
|
997
1939
|
});
|