@nymphjs/query-parser 1.0.0-beta.13 → 1.0.0-beta.130

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.
@@ -0,0 +1,1686 @@
1
+ import queryParser from './queryParser.js';
2
+ const BlogPost = function () { };
3
+ const Category = function () { };
4
+ const List = function () { };
5
+ const Mail = function () { };
6
+ const Headers = function () { };
7
+ const Body = function () { };
8
+ const Label = function () { };
9
+ const Domain = function () { };
10
+ describe('queryParser', () => {
11
+ it('parses a basic query', () => {
12
+ const query = 'search';
13
+ const [options, ...selectors] = queryParser({
14
+ query,
15
+ entityClass: BlogPost,
16
+ defaultFields: ['text'],
17
+ });
18
+ expect(options).toEqual({
19
+ class: BlogPost,
20
+ });
21
+ expect(selectors).toEqual([
22
+ {
23
+ type: '|',
24
+ ilike: [['text', '%search%']],
25
+ },
26
+ ]);
27
+ });
28
+ it('allows bare queries to be customized', () => {
29
+ const query = 'search';
30
+ const [options, ...selectors] = queryParser({
31
+ query,
32
+ entityClass: BlogPost,
33
+ defaultFields: ['text'],
34
+ bareHandler: (input, entityClass, defaultFields) => {
35
+ expect(input).toEqual('search');
36
+ expect(entityClass).toBe(BlogPost);
37
+ expect(defaultFields).toEqual(['text']);
38
+ return {
39
+ equal: ['custom', input],
40
+ };
41
+ },
42
+ });
43
+ expect(options).toEqual({
44
+ class: BlogPost,
45
+ });
46
+ expect(selectors).toEqual([
47
+ {
48
+ type: '|',
49
+ equal: ['custom', 'search'],
50
+ },
51
+ ]);
52
+ });
53
+ it('gives the correct entity and default fields to bare queries', () => {
54
+ const query = 'category<{Cat search}>';
55
+ const [options, ...selectors] = queryParser({
56
+ query,
57
+ entityClass: BlogPost,
58
+ defaultFields: ['text'],
59
+ qrefMap: {
60
+ Cat: {
61
+ class: Category,
62
+ defaultFields: ['name'],
63
+ },
64
+ },
65
+ bareHandler: (input, entityClass, defaultFields) => {
66
+ expect(input).toEqual('search');
67
+ expect(entityClass).toBe(Category);
68
+ expect(defaultFields).toEqual(['name']);
69
+ return {
70
+ type: '!&',
71
+ equal: ['custom', input],
72
+ };
73
+ },
74
+ });
75
+ expect(options).toEqual({
76
+ class: BlogPost,
77
+ });
78
+ expect(selectors).toEqual([
79
+ {
80
+ type: '&',
81
+ qref: [
82
+ [
83
+ 'category',
84
+ [{ class: Category }, { type: '!&', equal: ['custom', 'search'] }],
85
+ ],
86
+ ],
87
+ },
88
+ ]);
89
+ });
90
+ it('parses the example query from the readme', () => {
91
+ const query = 'limit:4 foobar (| [archived] mdate<"2 weeks ago") category<{Cat Tech}>';
92
+ const [options, ...selectors] = queryParser({
93
+ query,
94
+ entityClass: BlogPost,
95
+ defaultFields: ['title', 'body'],
96
+ qrefMap: {
97
+ Cat: {
98
+ class: Category,
99
+ defaultFields: ['name'],
100
+ },
101
+ },
102
+ });
103
+ expect(options).toEqual({
104
+ class: BlogPost,
105
+ limit: 4,
106
+ });
107
+ expect(selectors).toEqual([
108
+ {
109
+ type: '&',
110
+ selector: [
111
+ {
112
+ type: '|',
113
+ truthy: ['archived'],
114
+ lt: [['mdate', null, '2 weeks ago']],
115
+ },
116
+ ],
117
+ qref: [
118
+ [
119
+ 'category',
120
+ [
121
+ {
122
+ class: Category,
123
+ },
124
+ {
125
+ type: '|',
126
+ ilike: [['name', '%Tech%']],
127
+ },
128
+ ],
129
+ ],
130
+ ],
131
+ },
132
+ {
133
+ type: '|',
134
+ ilike: [
135
+ ['title', '%foobar%'],
136
+ ['body', '%foobar%'],
137
+ ],
138
+ },
139
+ ]);
140
+ });
141
+ it('parses a query with json value with spaces', () => {
142
+ const query = 'obj={"prop": "my value"} foobar arr=["a value", "another value"]';
143
+ const [options, ...selectors] = queryParser({
144
+ query,
145
+ entityClass: BlogPost,
146
+ defaultFields: ['title', 'body'],
147
+ });
148
+ expect(options).toEqual({
149
+ class: BlogPost,
150
+ });
151
+ expect(selectors).toEqual([
152
+ {
153
+ type: '&',
154
+ equal: [
155
+ ['obj', { prop: 'my value' }],
156
+ ['arr', ['a value', 'another value']],
157
+ ],
158
+ },
159
+ {
160
+ type: '|',
161
+ ilike: [
162
+ ['title', '%foobar%'],
163
+ ['body', '%foobar%'],
164
+ ],
165
+ },
166
+ ]);
167
+ });
168
+ it('parses a query with nested json value with spaces', () => {
169
+ const query = 'obj={"obj": {"sub": "my value"}, "prop": "my value"} foobar arr=["a value", "another value", {"prop": [1, 2, 3]}]';
170
+ const [options, ...selectors] = queryParser({
171
+ query,
172
+ entityClass: BlogPost,
173
+ defaultFields: ['title', 'body'],
174
+ });
175
+ expect(options).toEqual({
176
+ class: BlogPost,
177
+ });
178
+ expect(selectors).toEqual([
179
+ {
180
+ type: '&',
181
+ equal: [
182
+ ['obj', { obj: { sub: 'my value' }, prop: 'my value' }],
183
+ ['arr', ['a value', 'another value', { prop: [1, 2, 3] }]],
184
+ ],
185
+ },
186
+ {
187
+ type: '|',
188
+ ilike: [
189
+ ['title', '%foobar%'],
190
+ ['body', '%foobar%'],
191
+ ],
192
+ },
193
+ ]);
194
+ });
195
+ it('parses a query with broken json', () => {
196
+ const query = 'obj={"obj":"val"';
197
+ const [options, ...selectors] = queryParser({
198
+ query,
199
+ entityClass: BlogPost,
200
+ defaultFields: ['title', 'body'],
201
+ });
202
+ expect(options).toEqual({
203
+ class: BlogPost,
204
+ });
205
+ expect(selectors).toEqual([
206
+ {
207
+ type: '&',
208
+ equal: [['obj', '{"obj":"val"']],
209
+ },
210
+ ]);
211
+ });
212
+ it('parses a query with broken json and correct json', () => {
213
+ const query = 'obj={"obj":"val" another={"prop":"value"}';
214
+ const [options, ...selectors] = queryParser({
215
+ query,
216
+ entityClass: BlogPost,
217
+ defaultFields: ['title', 'body'],
218
+ });
219
+ expect(options).toEqual({
220
+ class: BlogPost,
221
+ });
222
+ expect(selectors).toEqual([
223
+ {
224
+ type: '&',
225
+ equal: [
226
+ ['another', { prop: 'value' }],
227
+ ['obj', '{"obj":"val"'],
228
+ ],
229
+ },
230
+ ]);
231
+ });
232
+ it('parses a query with search', () => {
233
+ const query = 'limit:4 foobar prop(a search string)';
234
+ const [options, ...selectors] = queryParser({
235
+ query,
236
+ entityClass: BlogPost,
237
+ defaultFields: ['title', 'body'],
238
+ qrefMap: {
239
+ cat: {
240
+ class: Category,
241
+ defaultFields: ['name'],
242
+ },
243
+ },
244
+ });
245
+ expect(options).toEqual({
246
+ class: BlogPost,
247
+ limit: 4,
248
+ });
249
+ expect(selectors).toEqual([
250
+ {
251
+ type: '&',
252
+ search: [['prop', 'a search string']],
253
+ },
254
+ {
255
+ type: '|',
256
+ ilike: [
257
+ ['title', '%foobar%'],
258
+ ['body', '%foobar%'],
259
+ ],
260
+ },
261
+ ]);
262
+ });
263
+ it('parses a query with not search', () => {
264
+ const query = 'limit:4 foobar -prop(a search string)';
265
+ const [options, ...selectors] = queryParser({
266
+ query,
267
+ entityClass: BlogPost,
268
+ defaultFields: ['title', 'body'],
269
+ qrefMap: {
270
+ cat: {
271
+ class: Category,
272
+ defaultFields: ['name'],
273
+ },
274
+ },
275
+ });
276
+ expect(options).toEqual({
277
+ class: BlogPost,
278
+ limit: 4,
279
+ });
280
+ expect(selectors).toEqual([
281
+ {
282
+ type: '&',
283
+ '!search': [['prop', 'a search string']],
284
+ },
285
+ {
286
+ type: '|',
287
+ ilike: [
288
+ ['title', '%foobar%'],
289
+ ['body', '%foobar%'],
290
+ ],
291
+ },
292
+ ]);
293
+ });
294
+ it('parses a query with colon search', () => {
295
+ const query = 'limit:4 foobar prop:string';
296
+ const [options, ...selectors] = queryParser({
297
+ query,
298
+ entityClass: BlogPost,
299
+ defaultFields: ['title', 'body'],
300
+ qrefMap: {
301
+ cat: {
302
+ class: Category,
303
+ defaultFields: ['name'],
304
+ },
305
+ },
306
+ });
307
+ expect(options).toEqual({
308
+ class: BlogPost,
309
+ limit: 4,
310
+ });
311
+ expect(selectors).toEqual([
312
+ {
313
+ type: '&',
314
+ search: [['prop', 'string']],
315
+ },
316
+ {
317
+ type: '|',
318
+ ilike: [
319
+ ['title', '%foobar%'],
320
+ ['body', '%foobar%'],
321
+ ],
322
+ },
323
+ ]);
324
+ });
325
+ it('parses a query with not colon search', () => {
326
+ const query = 'limit:4 foobar -prop:string';
327
+ const [options, ...selectors] = queryParser({
328
+ query,
329
+ entityClass: BlogPost,
330
+ defaultFields: ['title', 'body'],
331
+ qrefMap: {
332
+ cat: {
333
+ class: Category,
334
+ defaultFields: ['name'],
335
+ },
336
+ },
337
+ });
338
+ expect(options).toEqual({
339
+ class: BlogPost,
340
+ limit: 4,
341
+ });
342
+ expect(selectors).toEqual([
343
+ {
344
+ type: '&',
345
+ '!search': [['prop', 'string']],
346
+ },
347
+ {
348
+ type: '|',
349
+ ilike: [
350
+ ['title', '%foobar%'],
351
+ ['body', '%foobar%'],
352
+ ],
353
+ },
354
+ ]);
355
+ });
356
+ it('parses a query with search in a selector', () => {
357
+ const query = 'limit:4 foobar (| prop(a search string) prop2("another search string"))';
358
+ const [options, ...selectors] = queryParser({
359
+ query,
360
+ entityClass: BlogPost,
361
+ defaultFields: ['title', 'body'],
362
+ qrefMap: {
363
+ cat: {
364
+ class: Category,
365
+ defaultFields: ['name'],
366
+ },
367
+ },
368
+ });
369
+ expect(options).toEqual({
370
+ class: BlogPost,
371
+ limit: 4,
372
+ });
373
+ expect(selectors).toEqual([
374
+ {
375
+ type: '&',
376
+ selector: [
377
+ {
378
+ type: '|',
379
+ search: [
380
+ ['prop', 'a search string'],
381
+ ['prop2', '"another search string"'],
382
+ ],
383
+ },
384
+ ],
385
+ },
386
+ {
387
+ type: '|',
388
+ ilike: [
389
+ ['title', '%foobar%'],
390
+ ['body', '%foobar%'],
391
+ ],
392
+ },
393
+ ]);
394
+ });
395
+ it('parses a query with colon search in a selector', () => {
396
+ const query = 'limit:4 foobar (| prop:string prop2:"another search string" -prop3:pickle -prop4:\'another -pickle string\')';
397
+ const [options, ...selectors] = queryParser({
398
+ query,
399
+ entityClass: BlogPost,
400
+ defaultFields: ['title', 'body'],
401
+ qrefMap: {
402
+ cat: {
403
+ class: Category,
404
+ defaultFields: ['name'],
405
+ },
406
+ },
407
+ });
408
+ expect(options).toEqual({
409
+ class: BlogPost,
410
+ limit: 4,
411
+ });
412
+ expect(selectors).toEqual([
413
+ {
414
+ type: '&',
415
+ selector: [
416
+ {
417
+ type: '|',
418
+ search: [
419
+ ['prop', 'string'],
420
+ ['prop2', '"another search string"'],
421
+ ],
422
+ '!search': [
423
+ ['prop3', 'pickle'],
424
+ ['prop4', "'another -pickle string'"],
425
+ ],
426
+ },
427
+ ],
428
+ },
429
+ {
430
+ type: '|',
431
+ ilike: [
432
+ ['title', '%foobar%'],
433
+ ['body', '%foobar%'],
434
+ ],
435
+ },
436
+ ]);
437
+ });
438
+ it('parses a query with lt and tag', () => {
439
+ const query = 'limit:4 foobar mdate<"2 weeks ago" <tag>';
440
+ const [options, ...selectors] = queryParser({
441
+ query,
442
+ entityClass: BlogPost,
443
+ defaultFields: ['title', 'body'],
444
+ qrefMap: {
445
+ cat: {
446
+ class: Category,
447
+ defaultFields: ['name'],
448
+ },
449
+ },
450
+ });
451
+ expect(options).toEqual({
452
+ class: BlogPost,
453
+ limit: 4,
454
+ });
455
+ expect(selectors).toEqual([
456
+ {
457
+ type: '&',
458
+ lt: [['mdate', null, '2 weeks ago']],
459
+ tag: ['tag'],
460
+ },
461
+ {
462
+ type: '|',
463
+ ilike: [
464
+ ['title', '%foobar%'],
465
+ ['body', '%foobar%'],
466
+ ],
467
+ },
468
+ ]);
469
+ });
470
+ it('parses a query with contain that has brackets', () => {
471
+ const query = 'limit:4 foobar string<"a string with < and > characters">';
472
+ const [options, ...selectors] = queryParser({
473
+ query,
474
+ entityClass: BlogPost,
475
+ defaultFields: ['title', 'body'],
476
+ qrefMap: {
477
+ cat: {
478
+ class: Category,
479
+ defaultFields: ['name'],
480
+ },
481
+ },
482
+ });
483
+ expect(options).toEqual({
484
+ class: BlogPost,
485
+ limit: 4,
486
+ });
487
+ expect(selectors).toEqual([
488
+ {
489
+ type: '&',
490
+ contain: [['string', 'a string with < and > characters']],
491
+ },
492
+ {
493
+ type: '|',
494
+ ilike: [
495
+ ['title', '%foobar%'],
496
+ ['body', '%foobar%'],
497
+ ],
498
+ },
499
+ ]);
500
+ });
501
+ it('parses a query with contain that has quotes', () => {
502
+ const query = 'limit:4 foobar string<"a string with a \\" characters">';
503
+ const [options, ...selectors] = queryParser({
504
+ query,
505
+ entityClass: BlogPost,
506
+ defaultFields: ['title', 'body'],
507
+ qrefMap: {
508
+ cat: {
509
+ class: Category,
510
+ defaultFields: ['name'],
511
+ },
512
+ },
513
+ });
514
+ expect(options).toEqual({
515
+ class: BlogPost,
516
+ limit: 4,
517
+ });
518
+ expect(selectors).toEqual([
519
+ {
520
+ type: '&',
521
+ contain: [['string', 'a string with a " characters']],
522
+ },
523
+ {
524
+ type: '|',
525
+ ilike: [
526
+ ['title', '%foobar%'],
527
+ ['body', '%foobar%'],
528
+ ],
529
+ },
530
+ ]);
531
+ });
532
+ it('parses a query with a dash in the property name', () => {
533
+ const query = 'limit:4 foobar Test-Prop<"a string">';
534
+ const [options, ...selectors] = queryParser({
535
+ query,
536
+ entityClass: BlogPost,
537
+ defaultFields: ['title', 'body'],
538
+ qrefMap: {
539
+ cat: {
540
+ class: Category,
541
+ defaultFields: ['name'],
542
+ },
543
+ },
544
+ });
545
+ expect(options).toEqual({
546
+ class: BlogPost,
547
+ limit: 4,
548
+ });
549
+ expect(selectors).toEqual([
550
+ {
551
+ type: '&',
552
+ contain: [['Test-Prop', 'a string']],
553
+ },
554
+ {
555
+ type: '|',
556
+ ilike: [
557
+ ['title', '%foobar%'],
558
+ ['body', '%foobar%'],
559
+ ],
560
+ },
561
+ ]);
562
+ });
563
+ it('parses all options', () => {
564
+ const query = 'limit:10 offset:15 sort:someProp reverse:true search';
565
+ const [options, ...selectors] = queryParser({
566
+ query,
567
+ entityClass: BlogPost,
568
+ defaultFields: ['text'],
569
+ });
570
+ expect(options).toEqual({
571
+ class: BlogPost,
572
+ limit: 10,
573
+ offset: 15,
574
+ sort: 'someProp',
575
+ reverse: true,
576
+ });
577
+ expect(selectors).toEqual([
578
+ {
579
+ type: '|',
580
+ ilike: [['text', '%search%']],
581
+ },
582
+ ]);
583
+ });
584
+ it('parses null sort option', () => {
585
+ const query = 'limit:10 offset:15 sort:- reverse:true search';
586
+ const [options, ...selectors] = queryParser({
587
+ query,
588
+ entityClass: BlogPost,
589
+ defaultFields: ['text'],
590
+ });
591
+ expect(options).toEqual({
592
+ class: BlogPost,
593
+ limit: 10,
594
+ offset: 15,
595
+ sort: null,
596
+ reverse: true,
597
+ });
598
+ expect(selectors).toEqual([
599
+ {
600
+ type: '|',
601
+ ilike: [['text', '%search%']],
602
+ },
603
+ ]);
604
+ });
605
+ it('parses simple equal clauses', () => {
606
+ const query = 'prop=string';
607
+ const [options, ...selectors] = queryParser({
608
+ query,
609
+ entityClass: BlogPost,
610
+ });
611
+ expect(options).toEqual({
612
+ class: BlogPost,
613
+ });
614
+ expect(selectors).toEqual([
615
+ {
616
+ type: '&',
617
+ equal: [['prop', 'string']],
618
+ },
619
+ ]);
620
+ });
621
+ it('parses simple not equal clauses', () => {
622
+ const query = '-prop=string';
623
+ const [options, ...selectors] = queryParser({
624
+ query,
625
+ entityClass: BlogPost,
626
+ });
627
+ expect(options).toEqual({
628
+ class: BlogPost,
629
+ });
630
+ expect(selectors).toEqual([
631
+ {
632
+ type: '&',
633
+ '!equal': [['prop', 'string']],
634
+ },
635
+ ]);
636
+ });
637
+ it('parses quoted equal clauses', () => {
638
+ const query = 'prop="a string"';
639
+ const [options, ...selectors] = queryParser({
640
+ query,
641
+ entityClass: BlogPost,
642
+ });
643
+ expect(options).toEqual({
644
+ class: BlogPost,
645
+ });
646
+ expect(selectors).toEqual([
647
+ {
648
+ type: '&',
649
+ equal: [['prop', 'a string']],
650
+ },
651
+ ]);
652
+ });
653
+ it('parses quoted not equal clauses', () => {
654
+ const query = '-prop="a string"';
655
+ const [options, ...selectors] = queryParser({
656
+ query,
657
+ entityClass: BlogPost,
658
+ });
659
+ expect(options).toEqual({
660
+ class: BlogPost,
661
+ });
662
+ expect(selectors).toEqual([
663
+ {
664
+ type: '&',
665
+ '!equal': [['prop', 'a string']],
666
+ },
667
+ ]);
668
+ });
669
+ it('parses json equal clauses', () => {
670
+ const query = 'prop=true';
671
+ const [options, ...selectors] = queryParser({
672
+ query,
673
+ entityClass: BlogPost,
674
+ });
675
+ expect(options).toEqual({
676
+ class: BlogPost,
677
+ });
678
+ expect(selectors).toEqual([
679
+ {
680
+ type: '&',
681
+ equal: [['prop', true]],
682
+ },
683
+ ]);
684
+ });
685
+ it('parses json not equal clauses', () => {
686
+ const query = '-prop=true';
687
+ const [options, ...selectors] = queryParser({
688
+ query,
689
+ entityClass: BlogPost,
690
+ });
691
+ expect(options).toEqual({
692
+ class: BlogPost,
693
+ });
694
+ expect(selectors).toEqual([
695
+ {
696
+ type: '&',
697
+ '!equal': [['prop', true]],
698
+ },
699
+ ]);
700
+ });
701
+ it('parses guid clauses', () => {
702
+ const query = '{111111111111111111111111}';
703
+ const [options, ...selectors] = queryParser({
704
+ query,
705
+ entityClass: BlogPost,
706
+ });
707
+ expect(options).toEqual({
708
+ class: BlogPost,
709
+ });
710
+ expect(selectors).toEqual([
711
+ {
712
+ type: '&',
713
+ guid: ['111111111111111111111111'],
714
+ },
715
+ ]);
716
+ });
717
+ it('parses not guid clauses', () => {
718
+ const query = '-{111111111111111111111111}';
719
+ const [options, ...selectors] = queryParser({
720
+ query,
721
+ entityClass: BlogPost,
722
+ });
723
+ expect(options).toEqual({
724
+ class: BlogPost,
725
+ });
726
+ expect(selectors).toEqual([
727
+ {
728
+ type: '&',
729
+ '!guid': ['111111111111111111111111'],
730
+ },
731
+ ]);
732
+ });
733
+ it('parses tag clauses', () => {
734
+ const query = '<tagname>';
735
+ const [options, ...selectors] = queryParser({
736
+ query,
737
+ entityClass: BlogPost,
738
+ });
739
+ expect(options).toEqual({
740
+ class: BlogPost,
741
+ });
742
+ expect(selectors).toEqual([
743
+ {
744
+ type: '&',
745
+ tag: ['tagname'],
746
+ },
747
+ ]);
748
+ });
749
+ it('parses not tag clauses', () => {
750
+ const query = '-<tagname>';
751
+ const [options, ...selectors] = queryParser({
752
+ query,
753
+ entityClass: BlogPost,
754
+ });
755
+ expect(options).toEqual({
756
+ class: BlogPost,
757
+ });
758
+ expect(selectors).toEqual([
759
+ {
760
+ type: '&',
761
+ '!tag': ['tagname'],
762
+ },
763
+ ]);
764
+ });
765
+ it('parses truthy clauses', () => {
766
+ const query = '[truthyname]';
767
+ const [options, ...selectors] = queryParser({
768
+ query,
769
+ entityClass: BlogPost,
770
+ });
771
+ expect(options).toEqual({
772
+ class: BlogPost,
773
+ });
774
+ expect(selectors).toEqual([
775
+ {
776
+ type: '&',
777
+ truthy: ['truthyname'],
778
+ },
779
+ ]);
780
+ });
781
+ it('parses not truthy clauses', () => {
782
+ const query = '-[truthyname]';
783
+ const [options, ...selectors] = queryParser({
784
+ query,
785
+ entityClass: BlogPost,
786
+ });
787
+ expect(options).toEqual({
788
+ class: BlogPost,
789
+ });
790
+ expect(selectors).toEqual([
791
+ {
792
+ type: '&',
793
+ '!truthy': ['truthyname'],
794
+ },
795
+ ]);
796
+ });
797
+ it('parses ref clauses', () => {
798
+ const query = 'prop<{111111111111111111111111}>';
799
+ const [options, ...selectors] = queryParser({
800
+ query,
801
+ entityClass: BlogPost,
802
+ });
803
+ expect(options).toEqual({
804
+ class: BlogPost,
805
+ });
806
+ expect(selectors).toEqual([
807
+ {
808
+ type: '&',
809
+ ref: [['prop', '111111111111111111111111']],
810
+ },
811
+ ]);
812
+ });
813
+ it('parses not ref clauses', () => {
814
+ const query = '-prop<{111111111111111111111111}>';
815
+ const [options, ...selectors] = queryParser({
816
+ query,
817
+ entityClass: BlogPost,
818
+ });
819
+ expect(options).toEqual({
820
+ class: BlogPost,
821
+ });
822
+ expect(selectors).toEqual([
823
+ {
824
+ type: '&',
825
+ '!ref': [['prop', '111111111111111111111111']],
826
+ },
827
+ ]);
828
+ });
829
+ it('parses simple contain clauses', () => {
830
+ const query = 'prop<string>';
831
+ const [options, ...selectors] = queryParser({
832
+ query,
833
+ entityClass: BlogPost,
834
+ });
835
+ expect(options).toEqual({
836
+ class: BlogPost,
837
+ });
838
+ expect(selectors).toEqual([
839
+ {
840
+ type: '&',
841
+ contain: [['prop', 'string']],
842
+ },
843
+ ]);
844
+ });
845
+ it('parses simple not contain clauses', () => {
846
+ const query = '-prop<string>';
847
+ const [options, ...selectors] = queryParser({
848
+ query,
849
+ entityClass: BlogPost,
850
+ });
851
+ expect(options).toEqual({
852
+ class: BlogPost,
853
+ });
854
+ expect(selectors).toEqual([
855
+ {
856
+ type: '&',
857
+ '!contain': [['prop', 'string']],
858
+ },
859
+ ]);
860
+ });
861
+ it('parses json contain clauses', () => {
862
+ const query = 'prop<true>';
863
+ const [options, ...selectors] = queryParser({
864
+ query,
865
+ entityClass: BlogPost,
866
+ });
867
+ expect(options).toEqual({
868
+ class: BlogPost,
869
+ });
870
+ expect(selectors).toEqual([
871
+ {
872
+ type: '&',
873
+ contain: [['prop', true]],
874
+ },
875
+ ]);
876
+ });
877
+ it('parses json not contain clauses', () => {
878
+ const query = '-prop<true>';
879
+ const [options, ...selectors] = queryParser({
880
+ query,
881
+ entityClass: BlogPost,
882
+ });
883
+ expect(options).toEqual({
884
+ class: BlogPost,
885
+ });
886
+ expect(selectors).toEqual([
887
+ {
888
+ type: '&',
889
+ '!contain': [['prop', true]],
890
+ },
891
+ ]);
892
+ });
893
+ it('parses match clauses', () => {
894
+ const query = 'prop~/regex/';
895
+ const [options, ...selectors] = queryParser({
896
+ query,
897
+ entityClass: BlogPost,
898
+ });
899
+ expect(options).toEqual({
900
+ class: BlogPost,
901
+ });
902
+ expect(selectors).toEqual([
903
+ {
904
+ type: '&',
905
+ match: [['prop', 'regex']],
906
+ },
907
+ ]);
908
+ });
909
+ it('parses not match clauses', () => {
910
+ const query = '-prop~/regex/';
911
+ const [options, ...selectors] = queryParser({
912
+ query,
913
+ entityClass: BlogPost,
914
+ });
915
+ expect(options).toEqual({
916
+ class: BlogPost,
917
+ });
918
+ expect(selectors).toEqual([
919
+ {
920
+ type: '&',
921
+ '!match': [['prop', 'regex']],
922
+ },
923
+ ]);
924
+ });
925
+ it('parses imatch clauses', () => {
926
+ const query = 'prop~/regex/i';
927
+ const [options, ...selectors] = queryParser({
928
+ query,
929
+ entityClass: BlogPost,
930
+ });
931
+ expect(options).toEqual({
932
+ class: BlogPost,
933
+ });
934
+ expect(selectors).toEqual([
935
+ {
936
+ type: '&',
937
+ imatch: [['prop', 'regex']],
938
+ },
939
+ ]);
940
+ });
941
+ it('parses not imatch clauses', () => {
942
+ const query = '-prop~/regex/i';
943
+ const [options, ...selectors] = queryParser({
944
+ query,
945
+ entityClass: BlogPost,
946
+ });
947
+ expect(options).toEqual({
948
+ class: BlogPost,
949
+ });
950
+ expect(selectors).toEqual([
951
+ {
952
+ type: '&',
953
+ '!imatch': [['prop', 'regex']],
954
+ },
955
+ ]);
956
+ });
957
+ it('parses simple like clauses', () => {
958
+ const query = 'prop~pattern';
959
+ const [options, ...selectors] = queryParser({
960
+ query,
961
+ entityClass: BlogPost,
962
+ });
963
+ expect(options).toEqual({
964
+ class: BlogPost,
965
+ });
966
+ expect(selectors).toEqual([
967
+ {
968
+ type: '&',
969
+ like: [['prop', 'pattern']],
970
+ },
971
+ ]);
972
+ });
973
+ it('parses simple not like clauses', () => {
974
+ const query = '-prop~pattern';
975
+ const [options, ...selectors] = queryParser({
976
+ query,
977
+ entityClass: BlogPost,
978
+ });
979
+ expect(options).toEqual({
980
+ class: BlogPost,
981
+ });
982
+ expect(selectors).toEqual([
983
+ {
984
+ type: '&',
985
+ '!like': [['prop', 'pattern']],
986
+ },
987
+ ]);
988
+ });
989
+ it('parses quoted like clauses', () => {
990
+ const query = 'prop~"a pattern"';
991
+ const [options, ...selectors] = queryParser({
992
+ query,
993
+ entityClass: BlogPost,
994
+ });
995
+ expect(options).toEqual({
996
+ class: BlogPost,
997
+ });
998
+ expect(selectors).toEqual([
999
+ {
1000
+ type: '&',
1001
+ like: [['prop', 'a pattern']],
1002
+ },
1003
+ ]);
1004
+ });
1005
+ it('parses quoted not like clauses', () => {
1006
+ const query = '-prop~"a pattern"';
1007
+ const [options, ...selectors] = queryParser({
1008
+ query,
1009
+ entityClass: BlogPost,
1010
+ });
1011
+ expect(options).toEqual({
1012
+ class: BlogPost,
1013
+ });
1014
+ expect(selectors).toEqual([
1015
+ {
1016
+ type: '&',
1017
+ '!like': [['prop', 'a pattern']],
1018
+ },
1019
+ ]);
1020
+ });
1021
+ it('parses ilike clauses', () => {
1022
+ const query = 'prop~"a pattern"i';
1023
+ const [options, ...selectors] = queryParser({
1024
+ query,
1025
+ entityClass: BlogPost,
1026
+ });
1027
+ expect(options).toEqual({
1028
+ class: BlogPost,
1029
+ });
1030
+ expect(selectors).toEqual([
1031
+ {
1032
+ type: '&',
1033
+ ilike: [['prop', 'a pattern']],
1034
+ },
1035
+ ]);
1036
+ });
1037
+ it('parses not ilike clauses', () => {
1038
+ const query = '-prop~"a pattern"i';
1039
+ const [options, ...selectors] = queryParser({
1040
+ query,
1041
+ entityClass: BlogPost,
1042
+ });
1043
+ expect(options).toEqual({
1044
+ class: BlogPost,
1045
+ });
1046
+ expect(selectors).toEqual([
1047
+ {
1048
+ type: '&',
1049
+ '!ilike': [['prop', 'a pattern']],
1050
+ },
1051
+ ]);
1052
+ });
1053
+ it('parses simple gt clauses', () => {
1054
+ const query = 'prop>30.5';
1055
+ const [options, ...selectors] = queryParser({
1056
+ query,
1057
+ entityClass: BlogPost,
1058
+ });
1059
+ expect(options).toEqual({
1060
+ class: BlogPost,
1061
+ });
1062
+ expect(selectors).toEqual([
1063
+ {
1064
+ type: '&',
1065
+ gt: [['prop', 30.5]],
1066
+ },
1067
+ ]);
1068
+ });
1069
+ it('parses simple not gt clauses', () => {
1070
+ const query = '-prop>30.5';
1071
+ const [options, ...selectors] = queryParser({
1072
+ query,
1073
+ entityClass: BlogPost,
1074
+ });
1075
+ expect(options).toEqual({
1076
+ class: BlogPost,
1077
+ });
1078
+ expect(selectors).toEqual([
1079
+ {
1080
+ type: '&',
1081
+ '!gt': [['prop', 30.5]],
1082
+ },
1083
+ ]);
1084
+ });
1085
+ it('parses simple relative gt clauses', () => {
1086
+ const query = 'prop>yesterday';
1087
+ const [options, ...selectors] = queryParser({
1088
+ query,
1089
+ entityClass: BlogPost,
1090
+ });
1091
+ expect(options).toEqual({
1092
+ class: BlogPost,
1093
+ });
1094
+ expect(selectors).toEqual([
1095
+ {
1096
+ type: '&',
1097
+ gt: [['prop', null, 'yesterday']],
1098
+ },
1099
+ ]);
1100
+ });
1101
+ it('parses simple relative not gt clauses', () => {
1102
+ const query = '-prop>yesterday';
1103
+ const [options, ...selectors] = queryParser({
1104
+ query,
1105
+ entityClass: BlogPost,
1106
+ });
1107
+ expect(options).toEqual({
1108
+ class: BlogPost,
1109
+ });
1110
+ expect(selectors).toEqual([
1111
+ {
1112
+ type: '&',
1113
+ '!gt': [['prop', null, 'yesterday']],
1114
+ },
1115
+ ]);
1116
+ });
1117
+ it('parses quote relative gt clauses', () => {
1118
+ const query = 'prop>"3 weeks ago"';
1119
+ const [options, ...selectors] = queryParser({
1120
+ query,
1121
+ entityClass: BlogPost,
1122
+ });
1123
+ expect(options).toEqual({
1124
+ class: BlogPost,
1125
+ });
1126
+ expect(selectors).toEqual([
1127
+ {
1128
+ type: '&',
1129
+ gt: [['prop', null, '3 weeks ago']],
1130
+ },
1131
+ ]);
1132
+ });
1133
+ it('parses quote relative not gt clauses', () => {
1134
+ const query = '-prop>"3 weeks ago"';
1135
+ const [options, ...selectors] = queryParser({
1136
+ query,
1137
+ entityClass: BlogPost,
1138
+ });
1139
+ expect(options).toEqual({
1140
+ class: BlogPost,
1141
+ });
1142
+ expect(selectors).toEqual([
1143
+ {
1144
+ type: '&',
1145
+ '!gt': [['prop', null, '3 weeks ago']],
1146
+ },
1147
+ ]);
1148
+ });
1149
+ it('parses simple gte clauses', () => {
1150
+ const query = 'prop>=30.5';
1151
+ const [options, ...selectors] = queryParser({
1152
+ query,
1153
+ entityClass: BlogPost,
1154
+ });
1155
+ expect(options).toEqual({
1156
+ class: BlogPost,
1157
+ });
1158
+ expect(selectors).toEqual([
1159
+ {
1160
+ type: '&',
1161
+ gte: [['prop', 30.5]],
1162
+ },
1163
+ ]);
1164
+ });
1165
+ it('parses simple not gte clauses', () => {
1166
+ const query = '-prop>=30.5';
1167
+ const [options, ...selectors] = queryParser({
1168
+ query,
1169
+ entityClass: BlogPost,
1170
+ });
1171
+ expect(options).toEqual({
1172
+ class: BlogPost,
1173
+ });
1174
+ expect(selectors).toEqual([
1175
+ {
1176
+ type: '&',
1177
+ '!gte': [['prop', 30.5]],
1178
+ },
1179
+ ]);
1180
+ });
1181
+ it('parses simple relative gte clauses', () => {
1182
+ const query = 'prop>=yesterday';
1183
+ const [options, ...selectors] = queryParser({
1184
+ query,
1185
+ entityClass: BlogPost,
1186
+ });
1187
+ expect(options).toEqual({
1188
+ class: BlogPost,
1189
+ });
1190
+ expect(selectors).toEqual([
1191
+ {
1192
+ type: '&',
1193
+ gte: [['prop', null, 'yesterday']],
1194
+ },
1195
+ ]);
1196
+ });
1197
+ it('parses simple relative not gte clauses', () => {
1198
+ const query = '-prop>=yesterday';
1199
+ const [options, ...selectors] = queryParser({
1200
+ query,
1201
+ entityClass: BlogPost,
1202
+ });
1203
+ expect(options).toEqual({
1204
+ class: BlogPost,
1205
+ });
1206
+ expect(selectors).toEqual([
1207
+ {
1208
+ type: '&',
1209
+ '!gte': [['prop', null, 'yesterday']],
1210
+ },
1211
+ ]);
1212
+ });
1213
+ it('parses quote relative gte clauses', () => {
1214
+ const query = 'prop>="3 weeks ago"';
1215
+ const [options, ...selectors] = queryParser({
1216
+ query,
1217
+ entityClass: BlogPost,
1218
+ });
1219
+ expect(options).toEqual({
1220
+ class: BlogPost,
1221
+ });
1222
+ expect(selectors).toEqual([
1223
+ {
1224
+ type: '&',
1225
+ gte: [['prop', null, '3 weeks ago']],
1226
+ },
1227
+ ]);
1228
+ });
1229
+ it('parses quote relative not gte clauses', () => {
1230
+ const query = '-prop>="3 weeks ago"';
1231
+ const [options, ...selectors] = queryParser({
1232
+ query,
1233
+ entityClass: BlogPost,
1234
+ });
1235
+ expect(options).toEqual({
1236
+ class: BlogPost,
1237
+ });
1238
+ expect(selectors).toEqual([
1239
+ {
1240
+ type: '&',
1241
+ '!gte': [['prop', null, '3 weeks ago']],
1242
+ },
1243
+ ]);
1244
+ });
1245
+ it('parses simple lt clauses', () => {
1246
+ const query = 'prop<30.5';
1247
+ const [options, ...selectors] = queryParser({
1248
+ query,
1249
+ entityClass: BlogPost,
1250
+ });
1251
+ expect(options).toEqual({
1252
+ class: BlogPost,
1253
+ });
1254
+ expect(selectors).toEqual([
1255
+ {
1256
+ type: '&',
1257
+ lt: [['prop', 30.5]],
1258
+ },
1259
+ ]);
1260
+ });
1261
+ it('parses simple not lt clauses', () => {
1262
+ const query = '-prop<30.5';
1263
+ const [options, ...selectors] = queryParser({
1264
+ query,
1265
+ entityClass: BlogPost,
1266
+ });
1267
+ expect(options).toEqual({
1268
+ class: BlogPost,
1269
+ });
1270
+ expect(selectors).toEqual([
1271
+ {
1272
+ type: '&',
1273
+ '!lt': [['prop', 30.5]],
1274
+ },
1275
+ ]);
1276
+ });
1277
+ it('parses simple relative lt clauses', () => {
1278
+ const query = 'prop<yesterday';
1279
+ const [options, ...selectors] = queryParser({
1280
+ query,
1281
+ entityClass: BlogPost,
1282
+ });
1283
+ expect(options).toEqual({
1284
+ class: BlogPost,
1285
+ });
1286
+ expect(selectors).toEqual([
1287
+ {
1288
+ type: '&',
1289
+ lt: [['prop', null, 'yesterday']],
1290
+ },
1291
+ ]);
1292
+ });
1293
+ it('parses simple relative not lt clauses', () => {
1294
+ const query = '-prop<yesterday';
1295
+ const [options, ...selectors] = queryParser({
1296
+ query,
1297
+ entityClass: BlogPost,
1298
+ });
1299
+ expect(options).toEqual({
1300
+ class: BlogPost,
1301
+ });
1302
+ expect(selectors).toEqual([
1303
+ {
1304
+ type: '&',
1305
+ '!lt': [['prop', null, 'yesterday']],
1306
+ },
1307
+ ]);
1308
+ });
1309
+ it('parses quote relative lt clauses', () => {
1310
+ const query = 'prop<"3 weeks ago"';
1311
+ const [options, ...selectors] = queryParser({
1312
+ query,
1313
+ entityClass: BlogPost,
1314
+ });
1315
+ expect(options).toEqual({
1316
+ class: BlogPost,
1317
+ });
1318
+ expect(selectors).toEqual([
1319
+ {
1320
+ type: '&',
1321
+ lt: [['prop', null, '3 weeks ago']],
1322
+ },
1323
+ ]);
1324
+ });
1325
+ it('parses quote relative not lt clauses', () => {
1326
+ const query = '-prop<"3 weeks ago"';
1327
+ const [options, ...selectors] = queryParser({
1328
+ query,
1329
+ entityClass: BlogPost,
1330
+ });
1331
+ expect(options).toEqual({
1332
+ class: BlogPost,
1333
+ });
1334
+ expect(selectors).toEqual([
1335
+ {
1336
+ type: '&',
1337
+ '!lt': [['prop', null, '3 weeks ago']],
1338
+ },
1339
+ ]);
1340
+ });
1341
+ it('parses simple lte clauses', () => {
1342
+ const query = 'prop<=30.5';
1343
+ const [options, ...selectors] = queryParser({
1344
+ query,
1345
+ entityClass: BlogPost,
1346
+ });
1347
+ expect(options).toEqual({
1348
+ class: BlogPost,
1349
+ });
1350
+ expect(selectors).toEqual([
1351
+ {
1352
+ type: '&',
1353
+ lte: [['prop', 30.5]],
1354
+ },
1355
+ ]);
1356
+ });
1357
+ it('parses simple not lte clauses', () => {
1358
+ const query = '-prop<=30.5';
1359
+ const [options, ...selectors] = queryParser({
1360
+ query,
1361
+ entityClass: BlogPost,
1362
+ });
1363
+ expect(options).toEqual({
1364
+ class: BlogPost,
1365
+ });
1366
+ expect(selectors).toEqual([
1367
+ {
1368
+ type: '&',
1369
+ '!lte': [['prop', 30.5]],
1370
+ },
1371
+ ]);
1372
+ });
1373
+ it('parses simple relative lte clauses', () => {
1374
+ const query = 'prop<=yesterday';
1375
+ const [options, ...selectors] = queryParser({
1376
+ query,
1377
+ entityClass: BlogPost,
1378
+ });
1379
+ expect(options).toEqual({
1380
+ class: BlogPost,
1381
+ });
1382
+ expect(selectors).toEqual([
1383
+ {
1384
+ type: '&',
1385
+ lte: [['prop', null, 'yesterday']],
1386
+ },
1387
+ ]);
1388
+ });
1389
+ it('parses simple relative not lte clauses', () => {
1390
+ const query = '-prop<=yesterday';
1391
+ const [options, ...selectors] = queryParser({
1392
+ query,
1393
+ entityClass: BlogPost,
1394
+ });
1395
+ expect(options).toEqual({
1396
+ class: BlogPost,
1397
+ });
1398
+ expect(selectors).toEqual([
1399
+ {
1400
+ type: '&',
1401
+ '!lte': [['prop', null, 'yesterday']],
1402
+ },
1403
+ ]);
1404
+ });
1405
+ it('parses quote relative lte clauses', () => {
1406
+ const query = 'prop<="3 weeks ago"';
1407
+ const [options, ...selectors] = queryParser({
1408
+ query,
1409
+ entityClass: BlogPost,
1410
+ });
1411
+ expect(options).toEqual({
1412
+ class: BlogPost,
1413
+ });
1414
+ expect(selectors).toEqual([
1415
+ {
1416
+ type: '&',
1417
+ lte: [['prop', null, '3 weeks ago']],
1418
+ },
1419
+ ]);
1420
+ });
1421
+ it('parses quote relative not lte clauses', () => {
1422
+ const query = '-prop<="3 weeks ago"';
1423
+ const [options, ...selectors] = queryParser({
1424
+ query,
1425
+ entityClass: BlogPost,
1426
+ });
1427
+ expect(options).toEqual({
1428
+ class: BlogPost,
1429
+ });
1430
+ expect(selectors).toEqual([
1431
+ {
1432
+ type: '&',
1433
+ '!lte': [['prop', null, '3 weeks ago']],
1434
+ },
1435
+ ]);
1436
+ });
1437
+ it('parses complex selectors', () => {
1438
+ const query = '(! [published] <draft>) (| -cdate>"6 months ago" mdate>"1 month ago")';
1439
+ const [options, ...selectors] = queryParser({
1440
+ query,
1441
+ entityClass: BlogPost,
1442
+ });
1443
+ expect(options).toEqual({
1444
+ class: BlogPost,
1445
+ });
1446
+ expect(selectors).toEqual([
1447
+ {
1448
+ type: '&',
1449
+ selector: [
1450
+ {
1451
+ type: '|',
1452
+ '!gt': [['cdate', null, '6 months ago']],
1453
+ gt: [['mdate', null, '1 month ago']],
1454
+ },
1455
+ {
1456
+ type: '!&',
1457
+ truthy: ['published'],
1458
+ tag: ['draft'],
1459
+ },
1460
+ ],
1461
+ },
1462
+ ]);
1463
+ });
1464
+ it('parses nested selectors', () => {
1465
+ const query = '(! [published] <draft> (| -cdate>"6 months ago" mdate>"1 month ago"))';
1466
+ const [options, ...selectors] = queryParser({
1467
+ query,
1468
+ entityClass: BlogPost,
1469
+ });
1470
+ expect(options).toEqual({
1471
+ class: BlogPost,
1472
+ });
1473
+ expect(selectors).toEqual([
1474
+ {
1475
+ type: '!&',
1476
+ truthy: ['published'],
1477
+ tag: ['draft'],
1478
+ selector: [
1479
+ {
1480
+ type: '|',
1481
+ '!gt': [['cdate', null, '6 months ago']],
1482
+ gt: [['mdate', null, '1 month ago']],
1483
+ },
1484
+ ],
1485
+ },
1486
+ ]);
1487
+ });
1488
+ it('parses nested qref clauses', () => {
1489
+ const query = 'categories<{Category parent<{Category list<{List frosting name(favorite)}>}> -parent<{Category id="sort+newsletters"}>}>';
1490
+ const [options, ...selectors] = queryParser({
1491
+ query,
1492
+ entityClass: BlogPost,
1493
+ defaultFields: ['title', 'body'],
1494
+ qrefMap: {
1495
+ Category: {
1496
+ class: Category,
1497
+ defaultFields: ['name'],
1498
+ },
1499
+ List: {
1500
+ class: List,
1501
+ defaultFields: ['name'],
1502
+ },
1503
+ },
1504
+ });
1505
+ expect(options).toEqual({
1506
+ class: BlogPost,
1507
+ });
1508
+ expect(selectors).toEqual([
1509
+ {
1510
+ type: '&',
1511
+ qref: [
1512
+ [
1513
+ 'categories',
1514
+ [
1515
+ { class: Category },
1516
+ {
1517
+ type: '&',
1518
+ qref: [
1519
+ [
1520
+ 'parent',
1521
+ [
1522
+ { class: Category },
1523
+ {
1524
+ type: '&',
1525
+ qref: [
1526
+ [
1527
+ 'list',
1528
+ [
1529
+ { class: List },
1530
+ {
1531
+ type: '&',
1532
+ search: [['name', 'favorite']],
1533
+ },
1534
+ {
1535
+ type: '|',
1536
+ ilike: [['name', '%frosting%']],
1537
+ },
1538
+ ],
1539
+ ],
1540
+ ],
1541
+ },
1542
+ ],
1543
+ ],
1544
+ ],
1545
+ '!qref': [
1546
+ [
1547
+ 'parent',
1548
+ [
1549
+ { class: Category },
1550
+ {
1551
+ type: '&',
1552
+ equal: [['id', 'sort+newsletters']],
1553
+ },
1554
+ ],
1555
+ ],
1556
+ ],
1557
+ },
1558
+ ],
1559
+ ],
1560
+ ],
1561
+ },
1562
+ ]);
1563
+ });
1564
+ it('handles badly nested qref', () => {
1565
+ const query = 'categories<{Category parent<{Category id="top"}>';
1566
+ const [options, ...selectors] = queryParser({
1567
+ query,
1568
+ entityClass: BlogPost,
1569
+ });
1570
+ expect(options).toEqual({
1571
+ class: BlogPost,
1572
+ });
1573
+ expect(selectors).toEqual([
1574
+ {
1575
+ type: '&',
1576
+ contain: [['categories', '{Category parent<{Category}']],
1577
+ equal: [['id', 'top']],
1578
+ },
1579
+ ]);
1580
+ });
1581
+ it('parses a realistic query', () => {
1582
+ const query = 'labels<{Label [aggbox]}> -[trash] [delivered] -<spam> -<bare> -<autoreply> -<draft> -<sent> limit:10 reverse:true';
1583
+ const [options, ...selectors] = queryParser({
1584
+ query,
1585
+ entityClass: Mail,
1586
+ defaultFields: ['subject', 'from', 'sender'],
1587
+ qrefMap: {
1588
+ Mail: {
1589
+ class: Mail,
1590
+ defaultFields: ['subject', 'from', 'sender'],
1591
+ },
1592
+ Headers: {
1593
+ class: Headers,
1594
+ defaultFields: ['Message-ID'],
1595
+ },
1596
+ Body: {
1597
+ class: Body,
1598
+ defaultFields: ['text'],
1599
+ },
1600
+ Label: {
1601
+ class: Label,
1602
+ defaultFields: ['name', 'id'],
1603
+ },
1604
+ Domain: {
1605
+ class: Domain,
1606
+ defaultFields: ['fqdn'],
1607
+ },
1608
+ },
1609
+ bareHandler: (input, entityClass, defaultFields = ['subject', 'from', 'sender']) => {
1610
+ if (entityClass === Mail) {
1611
+ return {
1612
+ type: '|',
1613
+ search: defaultFields.map((field) => [field, input]),
1614
+ qref: [
1615
+ [
1616
+ 'body',
1617
+ [
1618
+ { class: Body },
1619
+ {
1620
+ type: '&',
1621
+ search: ['text', input],
1622
+ },
1623
+ ],
1624
+ ],
1625
+ [
1626
+ 'body',
1627
+ [
1628
+ { class: Body },
1629
+ {
1630
+ type: '&',
1631
+ search: ['html', input],
1632
+ },
1633
+ ],
1634
+ ],
1635
+ [
1636
+ 'body',
1637
+ [
1638
+ { class: Body },
1639
+ {
1640
+ type: '&',
1641
+ search: ['attachments', input],
1642
+ },
1643
+ ],
1644
+ ],
1645
+ ],
1646
+ };
1647
+ }
1648
+ if (defaultFields.length) {
1649
+ return {
1650
+ type: '|',
1651
+ search: defaultFields.map((field) => [field, input]),
1652
+ };
1653
+ }
1654
+ return {};
1655
+ },
1656
+ });
1657
+ expect(options).toEqual({
1658
+ class: Mail,
1659
+ limit: 10,
1660
+ reverse: true,
1661
+ });
1662
+ expect(selectors).toEqual([
1663
+ {
1664
+ type: '&',
1665
+ '!tag': ['spam', 'bare', 'autoreply', 'draft', 'sent'],
1666
+ '!truthy': ['trash'],
1667
+ qref: [
1668
+ [
1669
+ 'labels',
1670
+ [
1671
+ {
1672
+ class: Label,
1673
+ },
1674
+ {
1675
+ truthy: ['aggbox'],
1676
+ type: '&',
1677
+ },
1678
+ ],
1679
+ ],
1680
+ ],
1681
+ truthy: ['delivered'],
1682
+ },
1683
+ ]);
1684
+ });
1685
+ });
1686
+ //# sourceMappingURL=queryParser.test.js.map