@nymphjs/query-parser 1.0.0-beta.6 → 1.0.0-beta.60
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 +222 -0
- package/README.md +5 -3
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/lib/queryParser.js +47 -14
- package/lib/queryParser.js.map +1 -1
- package/lib/queryParser.test.js +47 -1
- package/lib/queryParser.test.js.map +1 -1
- package/package.json +14 -14
- package/src/queryParser.test.ts +51 -1
- package/src/queryParser.ts +28 -18
- package/tsconfig.json +1 -1
- package/typedoc.json +4 -0
package/src/queryParser.test.ts
CHANGED
|
@@ -151,7 +151,7 @@ describe('queryParser', () => {
|
|
|
151
151
|
});
|
|
152
152
|
|
|
153
153
|
it('parses all options', () => {
|
|
154
|
-
const query = 'limit:10 offset:15 reverse:true search';
|
|
154
|
+
const query = 'limit:10 offset:15 sort:someProp reverse:true search';
|
|
155
155
|
const [options, ...selectors] = queryParser({
|
|
156
156
|
query,
|
|
157
157
|
entityClass: BlogPost,
|
|
@@ -162,6 +162,7 @@ describe('queryParser', () => {
|
|
|
162
162
|
class: BlogPost,
|
|
163
163
|
limit: 10,
|
|
164
164
|
offset: 15,
|
|
165
|
+
sort: 'someProp',
|
|
165
166
|
reverse: true,
|
|
166
167
|
});
|
|
167
168
|
|
|
@@ -995,4 +996,53 @@ describe('queryParser', () => {
|
|
|
995
996
|
},
|
|
996
997
|
]);
|
|
997
998
|
});
|
|
999
|
+
|
|
1000
|
+
it('parses nested qref clauses', () => {
|
|
1001
|
+
const query =
|
|
1002
|
+
'categories<{Category parent<{Category id="sort+newsletters"}>}> ';
|
|
1003
|
+
const [options, ...selectors] = queryParser({
|
|
1004
|
+
query,
|
|
1005
|
+
entityClass: BlogPost,
|
|
1006
|
+
defaultFields: ['title', 'body'],
|
|
1007
|
+
qrefMap: {
|
|
1008
|
+
Category: {
|
|
1009
|
+
class: Category,
|
|
1010
|
+
defaultFields: ['name'],
|
|
1011
|
+
},
|
|
1012
|
+
},
|
|
1013
|
+
});
|
|
1014
|
+
|
|
1015
|
+
expect(options).toEqual({
|
|
1016
|
+
class: BlogPost,
|
|
1017
|
+
});
|
|
1018
|
+
|
|
1019
|
+
expect(selectors).toEqual([
|
|
1020
|
+
{
|
|
1021
|
+
type: '&',
|
|
1022
|
+
qref: [
|
|
1023
|
+
[
|
|
1024
|
+
'categories',
|
|
1025
|
+
[
|
|
1026
|
+
{ class: Category },
|
|
1027
|
+
{
|
|
1028
|
+
type: '&',
|
|
1029
|
+
qref: [
|
|
1030
|
+
[
|
|
1031
|
+
'parent',
|
|
1032
|
+
[
|
|
1033
|
+
{ class: Category },
|
|
1034
|
+
{
|
|
1035
|
+
type: '&',
|
|
1036
|
+
equal: [['id', 'sort+newsletters']],
|
|
1037
|
+
},
|
|
1038
|
+
],
|
|
1039
|
+
],
|
|
1040
|
+
],
|
|
1041
|
+
},
|
|
1042
|
+
],
|
|
1043
|
+
],
|
|
1044
|
+
],
|
|
1045
|
+
},
|
|
1046
|
+
]);
|
|
1047
|
+
});
|
|
998
1048
|
});
|
package/src/queryParser.ts
CHANGED
|
@@ -4,7 +4,7 @@ import splitn from '@sciactive/splitn';
|
|
|
4
4
|
export type BareQueryHandler = (
|
|
5
5
|
input: string,
|
|
6
6
|
entityClass?: EntityConstructor,
|
|
7
|
-
defaultFields?: string[]
|
|
7
|
+
defaultFields?: string[],
|
|
8
8
|
) => Partial<Selector>;
|
|
9
9
|
|
|
10
10
|
export type QRefMap = {
|
|
@@ -12,7 +12,7 @@ export type QRefMap = {
|
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
export default function queryParser<
|
|
15
|
-
T extends EntityConstructor = EntityConstructor
|
|
15
|
+
T extends EntityConstructor = EntityConstructor,
|
|
16
16
|
>({
|
|
17
17
|
query,
|
|
18
18
|
entityClass,
|
|
@@ -27,7 +27,7 @@ export default function queryParser<
|
|
|
27
27
|
type: '|',
|
|
28
28
|
ilike: defaultFields.map((field) => [field, input]) as [
|
|
29
29
|
string,
|
|
30
|
-
string
|
|
30
|
+
string,
|
|
31
31
|
][],
|
|
32
32
|
};
|
|
33
33
|
}
|
|
@@ -144,7 +144,7 @@ function selectorsParser({
|
|
|
144
144
|
defaultFields,
|
|
145
145
|
qrefMap,
|
|
146
146
|
bareHandler,
|
|
147
|
-
})
|
|
147
|
+
}),
|
|
148
148
|
);
|
|
149
149
|
}
|
|
150
150
|
}
|
|
@@ -171,6 +171,16 @@ function selectorsParser({
|
|
|
171
171
|
}
|
|
172
172
|
curQuery = curQuery.replace(offsetRegex, '');
|
|
173
173
|
|
|
174
|
+
// JavaScript variable names are ridiculously infeasable to check
|
|
175
|
+
// thoroughly, so this is a "best attempt".
|
|
176
|
+
const sortRegex =
|
|
177
|
+
/(?: |^)sort:([_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*)(?= |$)/;
|
|
178
|
+
const sortMatch = curQuery.match(sortRegex);
|
|
179
|
+
if (sortMatch) {
|
|
180
|
+
options.sort = sortMatch[1];
|
|
181
|
+
}
|
|
182
|
+
curQuery = curQuery.replace(sortRegex, '');
|
|
183
|
+
|
|
174
184
|
const reverseRegex = /(?: |^)reverse:(true|false|1|0)(?= |$)/;
|
|
175
185
|
const reverseMatch = curQuery.match(reverseRegex);
|
|
176
186
|
if (reverseMatch) {
|
|
@@ -232,7 +242,7 @@ function selectorParser({
|
|
|
232
242
|
try {
|
|
233
243
|
let [name, value] = splitn(match.trim().slice(0, -1), '<', 2);
|
|
234
244
|
value = unQuoteCurlies(value.slice(1, -1));
|
|
235
|
-
let [className, qrefQuery] = value
|
|
245
|
+
let [className, qrefQuery] = splitn(value, ' ', 2);
|
|
236
246
|
const EntityClass = qrefMap[className].class;
|
|
237
247
|
if (EntityClass == null) {
|
|
238
248
|
continue;
|
|
@@ -270,7 +280,7 @@ function selectorParser({
|
|
|
270
280
|
selector['!equal'] = [];
|
|
271
281
|
for (let match of equalMatch) {
|
|
272
282
|
try {
|
|
273
|
-
let [name, value] = match.trim()
|
|
283
|
+
let [name, value] = splitn(match.trim(), '=', 2);
|
|
274
284
|
try {
|
|
275
285
|
if (name.endsWith('!')) {
|
|
276
286
|
selector['!equal'].push([name.slice(0, -1), JSON.parse(value)]);
|
|
@@ -305,7 +315,7 @@ function selectorParser({
|
|
|
305
315
|
selector['!ref'] = [];
|
|
306
316
|
for (let match of refMatch) {
|
|
307
317
|
try {
|
|
308
|
-
let [name, value] = match.trim().slice(0, -1)
|
|
318
|
+
let [name, value] = splitn(match.trim().slice(0, -1), '<', 2);
|
|
309
319
|
if (name.endsWith('!')) {
|
|
310
320
|
selector['!ref'].push([name.slice(0, -1), value.slice(1, -1)]);
|
|
311
321
|
} else {
|
|
@@ -332,7 +342,7 @@ function selectorParser({
|
|
|
332
342
|
selector['!contain'] = [];
|
|
333
343
|
for (let match of containMatch) {
|
|
334
344
|
try {
|
|
335
|
-
let [name, value] = match.trim().slice(0, -1)
|
|
345
|
+
let [name, value] = splitn(match.trim().slice(0, -1), '<', 2);
|
|
336
346
|
try {
|
|
337
347
|
if (name.endsWith('!')) {
|
|
338
348
|
selector['!contain'].push([
|
|
@@ -375,7 +385,7 @@ function selectorParser({
|
|
|
375
385
|
selector['!imatch'] = [];
|
|
376
386
|
for (let match of posixMatch) {
|
|
377
387
|
try {
|
|
378
|
-
let [name, value] = match.trim()
|
|
388
|
+
let [name, value] = splitn(match.trim(), '~', 2);
|
|
379
389
|
if (name.endsWith('!')) {
|
|
380
390
|
if (value.endsWith('i')) {
|
|
381
391
|
selector['!imatch'].push([
|
|
@@ -424,7 +434,7 @@ function selectorParser({
|
|
|
424
434
|
selector['!ilike'] = [];
|
|
425
435
|
for (let match of likeMatch) {
|
|
426
436
|
try {
|
|
427
|
-
let [name, value] = match.trim()
|
|
437
|
+
let [name, value] = splitn(match.trim(), '~', 2);
|
|
428
438
|
if (name.endsWith('!')) {
|
|
429
439
|
if (value.endsWith('"i')) {
|
|
430
440
|
selector['!ilike'].push([
|
|
@@ -548,7 +558,7 @@ function selectorParser({
|
|
|
548
558
|
selector.gt = [];
|
|
549
559
|
for (let match of gtMatch) {
|
|
550
560
|
try {
|
|
551
|
-
let [name, value] = match.trim()
|
|
561
|
+
let [name, value] = splitn(match.trim(), '>', 2);
|
|
552
562
|
selector.gt.push([name, Number(value)]);
|
|
553
563
|
} catch (e: any) {
|
|
554
564
|
continue;
|
|
@@ -569,7 +579,7 @@ function selectorParser({
|
|
|
569
579
|
}
|
|
570
580
|
for (let match of gtRelativeMatch) {
|
|
571
581
|
try {
|
|
572
|
-
let [name, value] = match.trim()
|
|
582
|
+
let [name, value] = splitn(match.trim(), '>', 2);
|
|
573
583
|
(selector.gt as [string, null, string][]).push([
|
|
574
584
|
name,
|
|
575
585
|
null,
|
|
@@ -592,7 +602,7 @@ function selectorParser({
|
|
|
592
602
|
selector.gte = [];
|
|
593
603
|
for (let match of gteMatch) {
|
|
594
604
|
try {
|
|
595
|
-
let [name, value] = match.trim()
|
|
605
|
+
let [name, value] = splitn(match.trim(), '>=', 2);
|
|
596
606
|
selector.gte.push([name, Number(value)]);
|
|
597
607
|
} catch (e: any) {
|
|
598
608
|
continue;
|
|
@@ -613,7 +623,7 @@ function selectorParser({
|
|
|
613
623
|
}
|
|
614
624
|
for (let match of gteRelativeMatch) {
|
|
615
625
|
try {
|
|
616
|
-
let [name, value] = match.trim()
|
|
626
|
+
let [name, value] = splitn(match.trim(), '>=', 2);
|
|
617
627
|
(selector.gte as [string, null, string][]).push([
|
|
618
628
|
name,
|
|
619
629
|
null,
|
|
@@ -636,7 +646,7 @@ function selectorParser({
|
|
|
636
646
|
selector.lt = [];
|
|
637
647
|
for (let match of ltMatch) {
|
|
638
648
|
try {
|
|
639
|
-
let [name, value] = match.trim()
|
|
649
|
+
let [name, value] = splitn(match.trim(), '<', 2);
|
|
640
650
|
selector.lt.push([name, Number(value)]);
|
|
641
651
|
} catch (e: any) {
|
|
642
652
|
continue;
|
|
@@ -657,7 +667,7 @@ function selectorParser({
|
|
|
657
667
|
}
|
|
658
668
|
for (let match of ltRelativeMatch) {
|
|
659
669
|
try {
|
|
660
|
-
let [name, value] = match.trim()
|
|
670
|
+
let [name, value] = splitn(match.trim(), '<', 2);
|
|
661
671
|
(selector.lt as [string, null, string][]).push([
|
|
662
672
|
name,
|
|
663
673
|
null,
|
|
@@ -680,7 +690,7 @@ function selectorParser({
|
|
|
680
690
|
selector.lte = [];
|
|
681
691
|
for (let match of lteMatch) {
|
|
682
692
|
try {
|
|
683
|
-
let [name, value] = match.trim()
|
|
693
|
+
let [name, value] = splitn(match.trim(), '<=', 2);
|
|
684
694
|
selector.lte.push([name, Number(value)]);
|
|
685
695
|
} catch (e: any) {
|
|
686
696
|
continue;
|
|
@@ -701,7 +711,7 @@ function selectorParser({
|
|
|
701
711
|
}
|
|
702
712
|
for (let match of lteRelativeMatch) {
|
|
703
713
|
try {
|
|
704
|
-
let [name, value] = match.trim()
|
|
714
|
+
let [name, value] = splitn(match.trim(), '<=', 2);
|
|
705
715
|
(selector.lte as [string, null, string][]).push([
|
|
706
716
|
name,
|
|
707
717
|
null,
|
package/tsconfig.json
CHANGED
package/typedoc.json
ADDED