@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.
@@ -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
  });
@@ -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.split(' ', 2);
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().split('=', 2);
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).split('<', 2);
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).split('<', 2);
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().split('~', 2);
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().split('~', 2);
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().split('>', 2);
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().split('>', 2);
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().split('>=', 2);
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().split('>=', 2);
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().split('<', 2);
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().split('<', 2);
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().split('<=', 2);
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().split('<=', 2);
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
@@ -5,7 +5,7 @@
5
5
  "lib": ["DOM", "ES2021"],
6
6
  "target": "ES2021",
7
7
  "noImplicitAny": true,
8
- "removeComments": true,
8
+ "removeComments": false,
9
9
  "sourceMap": true,
10
10
  "outDir": "lib",
11
11
  "resolveJsonModule": true,
package/typedoc.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": ["../../typedoc.base.json"],
3
+ "entryPoints": ["src/index.ts"]
4
+ }