@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.
@@ -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<{cat search}>';
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
- cat: {
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<{cat Tech}>';
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
- cat: {
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!=string';
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!="a string"';
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!=true';
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 = '{!111111111111111111111111}';
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 = '<!tagname>';
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 = '[!truthyname]';
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!<{111111111111111111111111}>';
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!<string>';
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!<true>';
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!~/regex/';
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!~/regex/i';
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!~pattern';
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!~"a pattern"';
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!~"a pattern"i';
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
- ['cdate', null, '6 months ago'],
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
- ['cdate', null, '6 months ago'],
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