@nymphjs/query-parser 1.0.0-beta.122 → 1.0.0-beta.124
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 +12 -0
- package/README.md +48 -46
- package/dist/queryParser.js +285 -120
- package/dist/queryParser.js.map +1 -1
- package/dist/queryParser.test.js +511 -29
- package/dist/queryParser.test.js.map +1 -1
- package/package.json +3 -3
- package/src/queryParser.test.ts +578 -29
- package/src/queryParser.ts +300 -120
package/dist/queryParser.test.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import queryParser from './queryParser.js';
|
|
2
2
|
const BlogPost = function () { };
|
|
3
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 () { };
|
|
4
10
|
describe('queryParser', () => {
|
|
5
11
|
it('parses a basic query', () => {
|
|
6
12
|
const query = 'search';
|
|
@@ -45,13 +51,13 @@ describe('queryParser', () => {
|
|
|
45
51
|
]);
|
|
46
52
|
});
|
|
47
53
|
it('gives the correct entity and default fields to bare queries', () => {
|
|
48
|
-
const query = 'category<{
|
|
54
|
+
const query = 'category<{Cat search}>';
|
|
49
55
|
const [options, ...selectors] = queryParser({
|
|
50
56
|
query,
|
|
51
57
|
entityClass: BlogPost,
|
|
52
58
|
defaultFields: ['text'],
|
|
53
59
|
qrefMap: {
|
|
54
|
-
|
|
60
|
+
Cat: {
|
|
55
61
|
class: Category,
|
|
56
62
|
defaultFields: ['name'],
|
|
57
63
|
},
|
|
@@ -82,13 +88,13 @@ describe('queryParser', () => {
|
|
|
82
88
|
]);
|
|
83
89
|
});
|
|
84
90
|
it('parses the example query from the readme', () => {
|
|
85
|
-
const query = 'limit:4 foobar (| [archived] mdate<"2 weeks ago") category<{
|
|
91
|
+
const query = 'limit:4 foobar (| [archived] mdate<"2 weeks ago") category<{Cat Tech}>';
|
|
86
92
|
const [options, ...selectors] = queryParser({
|
|
87
93
|
query,
|
|
88
94
|
entityClass: BlogPost,
|
|
89
95
|
defaultFields: ['title', 'body'],
|
|
90
96
|
qrefMap: {
|
|
91
|
-
|
|
97
|
+
Cat: {
|
|
92
98
|
class: Category,
|
|
93
99
|
defaultFields: ['name'],
|
|
94
100
|
},
|
|
@@ -254,6 +260,99 @@ describe('queryParser', () => {
|
|
|
254
260
|
},
|
|
255
261
|
]);
|
|
256
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
|
+
});
|
|
257
356
|
it('parses a query with search in a selector', () => {
|
|
258
357
|
const query = 'limit:4 foobar (| prop(a search string) prop2("another search string"))';
|
|
259
358
|
const [options, ...selectors] = queryParser({
|
|
@@ -293,6 +392,49 @@ describe('queryParser', () => {
|
|
|
293
392
|
},
|
|
294
393
|
]);
|
|
295
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
|
+
});
|
|
296
438
|
it('parses a query with lt and tag', () => {
|
|
297
439
|
const query = 'limit:4 foobar mdate<"2 weeks ago" <tag>';
|
|
298
440
|
const [options, ...selectors] = queryParser({
|
|
@@ -477,7 +619,7 @@ describe('queryParser', () => {
|
|
|
477
619
|
]);
|
|
478
620
|
});
|
|
479
621
|
it('parses simple not equal clauses', () => {
|
|
480
|
-
const query = 'prop
|
|
622
|
+
const query = '-prop=string';
|
|
481
623
|
const [options, ...selectors] = queryParser({
|
|
482
624
|
query,
|
|
483
625
|
entityClass: BlogPost,
|
|
@@ -509,7 +651,7 @@ describe('queryParser', () => {
|
|
|
509
651
|
]);
|
|
510
652
|
});
|
|
511
653
|
it('parses quoted not equal clauses', () => {
|
|
512
|
-
const query = 'prop
|
|
654
|
+
const query = '-prop="a string"';
|
|
513
655
|
const [options, ...selectors] = queryParser({
|
|
514
656
|
query,
|
|
515
657
|
entityClass: BlogPost,
|
|
@@ -541,7 +683,7 @@ describe('queryParser', () => {
|
|
|
541
683
|
]);
|
|
542
684
|
});
|
|
543
685
|
it('parses json not equal clauses', () => {
|
|
544
|
-
const query = 'prop
|
|
686
|
+
const query = '-prop=true';
|
|
545
687
|
const [options, ...selectors] = queryParser({
|
|
546
688
|
query,
|
|
547
689
|
entityClass: BlogPost,
|
|
@@ -573,7 +715,7 @@ describe('queryParser', () => {
|
|
|
573
715
|
]);
|
|
574
716
|
});
|
|
575
717
|
it('parses not guid clauses', () => {
|
|
576
|
-
const query = '{
|
|
718
|
+
const query = '-{111111111111111111111111}';
|
|
577
719
|
const [options, ...selectors] = queryParser({
|
|
578
720
|
query,
|
|
579
721
|
entityClass: BlogPost,
|
|
@@ -605,7 +747,7 @@ describe('queryParser', () => {
|
|
|
605
747
|
]);
|
|
606
748
|
});
|
|
607
749
|
it('parses not tag clauses', () => {
|
|
608
|
-
const query = '
|
|
750
|
+
const query = '-<tagname>';
|
|
609
751
|
const [options, ...selectors] = queryParser({
|
|
610
752
|
query,
|
|
611
753
|
entityClass: BlogPost,
|
|
@@ -637,7 +779,7 @@ describe('queryParser', () => {
|
|
|
637
779
|
]);
|
|
638
780
|
});
|
|
639
781
|
it('parses not truthy clauses', () => {
|
|
640
|
-
const query = '[
|
|
782
|
+
const query = '-[truthyname]';
|
|
641
783
|
const [options, ...selectors] = queryParser({
|
|
642
784
|
query,
|
|
643
785
|
entityClass: BlogPost,
|
|
@@ -669,7 +811,7 @@ describe('queryParser', () => {
|
|
|
669
811
|
]);
|
|
670
812
|
});
|
|
671
813
|
it('parses not ref clauses', () => {
|
|
672
|
-
const query = 'prop
|
|
814
|
+
const query = '-prop<{111111111111111111111111}>';
|
|
673
815
|
const [options, ...selectors] = queryParser({
|
|
674
816
|
query,
|
|
675
817
|
entityClass: BlogPost,
|
|
@@ -701,7 +843,7 @@ describe('queryParser', () => {
|
|
|
701
843
|
]);
|
|
702
844
|
});
|
|
703
845
|
it('parses simple not contain clauses', () => {
|
|
704
|
-
const query = 'prop
|
|
846
|
+
const query = '-prop<string>';
|
|
705
847
|
const [options, ...selectors] = queryParser({
|
|
706
848
|
query,
|
|
707
849
|
entityClass: BlogPost,
|
|
@@ -733,7 +875,7 @@ describe('queryParser', () => {
|
|
|
733
875
|
]);
|
|
734
876
|
});
|
|
735
877
|
it('parses json not contain clauses', () => {
|
|
736
|
-
const query = 'prop
|
|
878
|
+
const query = '-prop<true>';
|
|
737
879
|
const [options, ...selectors] = queryParser({
|
|
738
880
|
query,
|
|
739
881
|
entityClass: BlogPost,
|
|
@@ -765,7 +907,7 @@ describe('queryParser', () => {
|
|
|
765
907
|
]);
|
|
766
908
|
});
|
|
767
909
|
it('parses not match clauses', () => {
|
|
768
|
-
const query = 'prop
|
|
910
|
+
const query = '-prop~/regex/';
|
|
769
911
|
const [options, ...selectors] = queryParser({
|
|
770
912
|
query,
|
|
771
913
|
entityClass: BlogPost,
|
|
@@ -797,7 +939,7 @@ describe('queryParser', () => {
|
|
|
797
939
|
]);
|
|
798
940
|
});
|
|
799
941
|
it('parses not imatch clauses', () => {
|
|
800
|
-
const query = 'prop
|
|
942
|
+
const query = '-prop~/regex/i';
|
|
801
943
|
const [options, ...selectors] = queryParser({
|
|
802
944
|
query,
|
|
803
945
|
entityClass: BlogPost,
|
|
@@ -829,7 +971,7 @@ describe('queryParser', () => {
|
|
|
829
971
|
]);
|
|
830
972
|
});
|
|
831
973
|
it('parses simple not like clauses', () => {
|
|
832
|
-
const query = 'prop
|
|
974
|
+
const query = '-prop~pattern';
|
|
833
975
|
const [options, ...selectors] = queryParser({
|
|
834
976
|
query,
|
|
835
977
|
entityClass: BlogPost,
|
|
@@ -861,7 +1003,7 @@ describe('queryParser', () => {
|
|
|
861
1003
|
]);
|
|
862
1004
|
});
|
|
863
1005
|
it('parses quoted not like clauses', () => {
|
|
864
|
-
const query = 'prop
|
|
1006
|
+
const query = '-prop~"a pattern"';
|
|
865
1007
|
const [options, ...selectors] = queryParser({
|
|
866
1008
|
query,
|
|
867
1009
|
entityClass: BlogPost,
|
|
@@ -893,7 +1035,7 @@ describe('queryParser', () => {
|
|
|
893
1035
|
]);
|
|
894
1036
|
});
|
|
895
1037
|
it('parses not ilike clauses', () => {
|
|
896
|
-
const query = 'prop
|
|
1038
|
+
const query = '-prop~"a pattern"i';
|
|
897
1039
|
const [options, ...selectors] = queryParser({
|
|
898
1040
|
query,
|
|
899
1041
|
entityClass: BlogPost,
|
|
@@ -924,6 +1066,22 @@ describe('queryParser', () => {
|
|
|
924
1066
|
},
|
|
925
1067
|
]);
|
|
926
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
|
+
});
|
|
927
1085
|
it('parses simple relative gt clauses', () => {
|
|
928
1086
|
const query = 'prop>yesterday';
|
|
929
1087
|
const [options, ...selectors] = queryParser({
|
|
@@ -940,6 +1098,22 @@ describe('queryParser', () => {
|
|
|
940
1098
|
},
|
|
941
1099
|
]);
|
|
942
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
|
+
});
|
|
943
1117
|
it('parses quote relative gt clauses', () => {
|
|
944
1118
|
const query = 'prop>"3 weeks ago"';
|
|
945
1119
|
const [options, ...selectors] = queryParser({
|
|
@@ -956,6 +1130,22 @@ describe('queryParser', () => {
|
|
|
956
1130
|
},
|
|
957
1131
|
]);
|
|
958
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
|
+
});
|
|
959
1149
|
it('parses simple gte clauses', () => {
|
|
960
1150
|
const query = 'prop>=30.5';
|
|
961
1151
|
const [options, ...selectors] = queryParser({
|
|
@@ -972,6 +1162,22 @@ describe('queryParser', () => {
|
|
|
972
1162
|
},
|
|
973
1163
|
]);
|
|
974
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
|
+
});
|
|
975
1181
|
it('parses simple relative gte clauses', () => {
|
|
976
1182
|
const query = 'prop>=yesterday';
|
|
977
1183
|
const [options, ...selectors] = queryParser({
|
|
@@ -988,6 +1194,22 @@ describe('queryParser', () => {
|
|
|
988
1194
|
},
|
|
989
1195
|
]);
|
|
990
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
|
+
});
|
|
991
1213
|
it('parses quote relative gte clauses', () => {
|
|
992
1214
|
const query = 'prop>="3 weeks ago"';
|
|
993
1215
|
const [options, ...selectors] = queryParser({
|
|
@@ -1004,6 +1226,22 @@ describe('queryParser', () => {
|
|
|
1004
1226
|
},
|
|
1005
1227
|
]);
|
|
1006
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
|
+
});
|
|
1007
1245
|
it('parses simple lt clauses', () => {
|
|
1008
1246
|
const query = 'prop<30.5';
|
|
1009
1247
|
const [options, ...selectors] = queryParser({
|
|
@@ -1020,6 +1258,22 @@ describe('queryParser', () => {
|
|
|
1020
1258
|
},
|
|
1021
1259
|
]);
|
|
1022
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
|
+
});
|
|
1023
1277
|
it('parses simple relative lt clauses', () => {
|
|
1024
1278
|
const query = 'prop<yesterday';
|
|
1025
1279
|
const [options, ...selectors] = queryParser({
|
|
@@ -1036,6 +1290,22 @@ describe('queryParser', () => {
|
|
|
1036
1290
|
},
|
|
1037
1291
|
]);
|
|
1038
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
|
+
});
|
|
1039
1309
|
it('parses quote relative lt clauses', () => {
|
|
1040
1310
|
const query = 'prop<"3 weeks ago"';
|
|
1041
1311
|
const [options, ...selectors] = queryParser({
|
|
@@ -1052,6 +1322,22 @@ describe('queryParser', () => {
|
|
|
1052
1322
|
},
|
|
1053
1323
|
]);
|
|
1054
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
|
+
});
|
|
1055
1341
|
it('parses simple lte clauses', () => {
|
|
1056
1342
|
const query = 'prop<=30.5';
|
|
1057
1343
|
const [options, ...selectors] = queryParser({
|
|
@@ -1068,6 +1354,22 @@ describe('queryParser', () => {
|
|
|
1068
1354
|
},
|
|
1069
1355
|
]);
|
|
1070
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
|
+
});
|
|
1071
1373
|
it('parses simple relative lte clauses', () => {
|
|
1072
1374
|
const query = 'prop<=yesterday';
|
|
1073
1375
|
const [options, ...selectors] = queryParser({
|
|
@@ -1084,6 +1386,22 @@ describe('queryParser', () => {
|
|
|
1084
1386
|
},
|
|
1085
1387
|
]);
|
|
1086
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
|
+
});
|
|
1087
1405
|
it('parses quote relative lte clauses', () => {
|
|
1088
1406
|
const query = 'prop<="3 weeks ago"';
|
|
1089
1407
|
const [options, ...selectors] = queryParser({
|
|
@@ -1100,8 +1418,24 @@ describe('queryParser', () => {
|
|
|
1100
1418
|
},
|
|
1101
1419
|
]);
|
|
1102
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
|
+
});
|
|
1103
1437
|
it('parses complex selectors', () => {
|
|
1104
|
-
const query = '(! [published] <draft>) (| cdate>"6 months ago" mdate>"1 month ago")';
|
|
1438
|
+
const query = '(! [published] <draft>) (| -cdate>"6 months ago" mdate>"1 month ago")';
|
|
1105
1439
|
const [options, ...selectors] = queryParser({
|
|
1106
1440
|
query,
|
|
1107
1441
|
entityClass: BlogPost,
|
|
@@ -1115,10 +1449,8 @@ describe('queryParser', () => {
|
|
|
1115
1449
|
selector: [
|
|
1116
1450
|
{
|
|
1117
1451
|
type: '|',
|
|
1118
|
-
gt: [
|
|
1119
|
-
|
|
1120
|
-
['mdate', null, '1 month ago'],
|
|
1121
|
-
],
|
|
1452
|
+
'!gt': [['cdate', null, '6 months ago']],
|
|
1453
|
+
gt: [['mdate', null, '1 month ago']],
|
|
1122
1454
|
},
|
|
1123
1455
|
{
|
|
1124
1456
|
type: '!&',
|
|
@@ -1130,7 +1462,7 @@ describe('queryParser', () => {
|
|
|
1130
1462
|
]);
|
|
1131
1463
|
});
|
|
1132
1464
|
it('parses nested selectors', () => {
|
|
1133
|
-
const query = '(! [published] <draft> (| cdate>"6 months ago" mdate>"1 month ago"))';
|
|
1465
|
+
const query = '(! [published] <draft> (| -cdate>"6 months ago" mdate>"1 month ago"))';
|
|
1134
1466
|
const [options, ...selectors] = queryParser({
|
|
1135
1467
|
query,
|
|
1136
1468
|
entityClass: BlogPost,
|
|
@@ -1146,17 +1478,15 @@ describe('queryParser', () => {
|
|
|
1146
1478
|
selector: [
|
|
1147
1479
|
{
|
|
1148
1480
|
type: '|',
|
|
1149
|
-
gt: [
|
|
1150
|
-
|
|
1151
|
-
['mdate', null, '1 month ago'],
|
|
1152
|
-
],
|
|
1481
|
+
'!gt': [['cdate', null, '6 months ago']],
|
|
1482
|
+
gt: [['mdate', null, '1 month ago']],
|
|
1153
1483
|
},
|
|
1154
1484
|
],
|
|
1155
1485
|
},
|
|
1156
1486
|
]);
|
|
1157
1487
|
});
|
|
1158
1488
|
it('parses nested qref clauses', () => {
|
|
1159
|
-
const query = 'categories<{Category parent<{Category id="sort+newsletters"}>}>
|
|
1489
|
+
const query = 'categories<{Category parent<{Category list<{List frosting name(favorite)}>}> -parent<{Category id="sort+newsletters"}>}>';
|
|
1160
1490
|
const [options, ...selectors] = queryParser({
|
|
1161
1491
|
query,
|
|
1162
1492
|
entityClass: BlogPost,
|
|
@@ -1166,6 +1496,10 @@ describe('queryParser', () => {
|
|
|
1166
1496
|
class: Category,
|
|
1167
1497
|
defaultFields: ['name'],
|
|
1168
1498
|
},
|
|
1499
|
+
List: {
|
|
1500
|
+
class: List,
|
|
1501
|
+
defaultFields: ['name'],
|
|
1502
|
+
},
|
|
1169
1503
|
},
|
|
1170
1504
|
});
|
|
1171
1505
|
expect(options).toEqual({
|
|
@@ -1182,6 +1516,33 @@ describe('queryParser', () => {
|
|
|
1182
1516
|
{
|
|
1183
1517
|
type: '&',
|
|
1184
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': [
|
|
1185
1546
|
[
|
|
1186
1547
|
'parent',
|
|
1187
1548
|
[
|
|
@@ -1200,5 +1561,126 @@ describe('queryParser', () => {
|
|
|
1200
1561
|
},
|
|
1201
1562
|
]);
|
|
1202
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
|
+
});
|
|
1203
1685
|
});
|
|
1204
1686
|
//# sourceMappingURL=queryParser.test.js.map
|