@nymphjs/query-parser 1.0.0-alpha.4 → 1.0.0-alpha.40
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 +160 -0
- package/README.md +20 -11
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/lib/queryParser.d.ts +9 -1
- package/lib/queryParser.js +79 -16
- package/lib/queryParser.js.map +1 -1
- package/lib/queryParser.test.d.ts +1 -0
- package/lib/queryParser.test.js +856 -0
- package/lib/queryParser.test.js.map +1 -0
- package/package.json +13 -12
- package/src/queryParser.test.ts +998 -0
- package/src/queryParser.ts +128 -42
package/src/queryParser.ts
CHANGED
|
@@ -1,31 +1,77 @@
|
|
|
1
1
|
import type { EntityConstructor, Options, Selector } from '@nymphjs/client';
|
|
2
|
+
import splitn from '@sciactive/splitn';
|
|
3
|
+
|
|
4
|
+
export type BareQueryHandler = (
|
|
5
|
+
input: string,
|
|
6
|
+
entityClass?: EntityConstructor,
|
|
7
|
+
defaultFields?: string[]
|
|
8
|
+
) => Partial<Selector>;
|
|
9
|
+
|
|
10
|
+
export type QRefMap = {
|
|
11
|
+
[k: string]: { class: EntityConstructor; defaultFields?: string[] };
|
|
12
|
+
};
|
|
2
13
|
|
|
3
14
|
export default function queryParser<
|
|
4
15
|
T extends EntityConstructor = EntityConstructor
|
|
5
|
-
>(
|
|
6
|
-
query
|
|
7
|
-
entityClass
|
|
8
|
-
defaultFields
|
|
9
|
-
qrefMap
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
>({
|
|
17
|
+
query,
|
|
18
|
+
entityClass,
|
|
19
|
+
defaultFields = ['name'],
|
|
20
|
+
qrefMap = {},
|
|
21
|
+
bareHandler = (input, _class, defaultFields = ['name']) => {
|
|
22
|
+
if (!input.match(/[_%]/)) {
|
|
23
|
+
input = `%${input}%`;
|
|
24
|
+
}
|
|
25
|
+
if (defaultFields.length) {
|
|
26
|
+
return {
|
|
27
|
+
type: '|',
|
|
28
|
+
ilike: defaultFields.map((field) => [field, input]) as [
|
|
29
|
+
string,
|
|
30
|
+
string
|
|
31
|
+
][],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return {};
|
|
35
|
+
},
|
|
36
|
+
}: {
|
|
37
|
+
query: string;
|
|
38
|
+
entityClass: T;
|
|
39
|
+
defaultFields?: string[];
|
|
40
|
+
qrefMap?: QRefMap;
|
|
41
|
+
bareHandler?: BareQueryHandler;
|
|
42
|
+
}): [Options<T>, ...Selector[]] {
|
|
13
43
|
const options: Options<T> = { class: entityClass };
|
|
14
44
|
return [
|
|
15
45
|
options,
|
|
16
|
-
...selectorsParser(
|
|
46
|
+
...selectorsParser({
|
|
47
|
+
query,
|
|
48
|
+
entityClass,
|
|
49
|
+
type: '&',
|
|
50
|
+
defaultFields,
|
|
51
|
+
qrefMap,
|
|
52
|
+
options,
|
|
53
|
+
bareHandler,
|
|
54
|
+
}),
|
|
17
55
|
];
|
|
18
56
|
}
|
|
19
57
|
|
|
20
|
-
function selectorsParser(
|
|
21
|
-
query
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
58
|
+
function selectorsParser({
|
|
59
|
+
query,
|
|
60
|
+
entityClass,
|
|
61
|
+
type,
|
|
62
|
+
defaultFields,
|
|
63
|
+
qrefMap,
|
|
64
|
+
options,
|
|
65
|
+
bareHandler,
|
|
66
|
+
}: {
|
|
67
|
+
query: string;
|
|
68
|
+
entityClass: EntityConstructor;
|
|
69
|
+
type: '&' | '|' | '!&' | '!|';
|
|
70
|
+
defaultFields: string[];
|
|
71
|
+
qrefMap: QRefMap;
|
|
72
|
+
options?: Options;
|
|
73
|
+
bareHandler: BareQueryHandler;
|
|
74
|
+
}): Selector[] {
|
|
29
75
|
const selector: Selector = { type };
|
|
30
76
|
let curQuery = query;
|
|
31
77
|
|
|
@@ -91,12 +137,24 @@ function selectorsParser(
|
|
|
91
137
|
selectorQuery = selectorQuery.slice(1);
|
|
92
138
|
}
|
|
93
139
|
selector.selector.push(
|
|
94
|
-
...selectorsParser(
|
|
140
|
+
...selectorsParser({
|
|
141
|
+
query: selectorQuery,
|
|
142
|
+
entityClass,
|
|
143
|
+
type,
|
|
144
|
+
defaultFields,
|
|
145
|
+
qrefMap,
|
|
146
|
+
bareHandler,
|
|
147
|
+
})
|
|
95
148
|
);
|
|
96
149
|
}
|
|
97
150
|
}
|
|
98
151
|
|
|
99
|
-
curQuery = selectorParser(
|
|
152
|
+
curQuery = selectorParser({
|
|
153
|
+
query: curQuery,
|
|
154
|
+
selector,
|
|
155
|
+
qrefMap,
|
|
156
|
+
bareHandler,
|
|
157
|
+
});
|
|
100
158
|
|
|
101
159
|
if (options) {
|
|
102
160
|
const limitRegex = /(?: |^)limit:(\d+)(?= |$)/;
|
|
@@ -124,18 +182,14 @@ function selectorsParser(
|
|
|
124
182
|
curQuery = curQuery.trim();
|
|
125
183
|
|
|
126
184
|
if (curQuery.length) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (defaultFields.length) {
|
|
185
|
+
const bareSelector = bareHandler(curQuery, entityClass, defaultFields);
|
|
186
|
+
|
|
187
|
+
if (Object.keys(bareSelector).length) {
|
|
131
188
|
return [
|
|
132
189
|
...(Object.keys(selector).length > 1 ? [selector] : []),
|
|
133
190
|
{
|
|
134
191
|
type: '|',
|
|
135
|
-
|
|
136
|
-
string,
|
|
137
|
-
string
|
|
138
|
-
][],
|
|
192
|
+
...bareSelector,
|
|
139
193
|
},
|
|
140
194
|
];
|
|
141
195
|
}
|
|
@@ -155,13 +209,17 @@ function selectorsParser(
|
|
|
155
209
|
return [selector];
|
|
156
210
|
}
|
|
157
211
|
|
|
158
|
-
function selectorParser(
|
|
159
|
-
query
|
|
160
|
-
selector
|
|
161
|
-
qrefMap
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
212
|
+
function selectorParser({
|
|
213
|
+
query,
|
|
214
|
+
selector,
|
|
215
|
+
qrefMap,
|
|
216
|
+
bareHandler,
|
|
217
|
+
}: {
|
|
218
|
+
query: string;
|
|
219
|
+
selector: Selector;
|
|
220
|
+
qrefMap: QRefMap;
|
|
221
|
+
bareHandler: BareQueryHandler;
|
|
222
|
+
}): string {
|
|
165
223
|
let curQuery = query;
|
|
166
224
|
|
|
167
225
|
// eg. user<{User name="Hunter"}> or user!<{User name="Hunter"}>
|
|
@@ -172,19 +230,20 @@ function selectorParser(
|
|
|
172
230
|
selector['!qref'] = [];
|
|
173
231
|
for (let match of qrefMatch) {
|
|
174
232
|
try {
|
|
175
|
-
let [name, value] = match.trim().slice(0, -1)
|
|
233
|
+
let [name, value] = splitn(match.trim().slice(0, -1), '<', 2);
|
|
176
234
|
value = unQuoteCurlies(value.slice(1, -1));
|
|
177
235
|
let [className, qrefQuery] = value.split(' ', 2);
|
|
178
236
|
const EntityClass = qrefMap[className].class;
|
|
179
237
|
if (EntityClass == null) {
|
|
180
238
|
continue;
|
|
181
239
|
}
|
|
182
|
-
const qref = queryParser(
|
|
183
|
-
qrefQuery,
|
|
184
|
-
EntityClass,
|
|
185
|
-
qrefMap[className].defaultFields,
|
|
186
|
-
qrefMap
|
|
187
|
-
|
|
240
|
+
const qref = queryParser({
|
|
241
|
+
query: qrefQuery,
|
|
242
|
+
entityClass: EntityClass,
|
|
243
|
+
defaultFields: qrefMap[className].defaultFields,
|
|
244
|
+
qrefMap,
|
|
245
|
+
bareHandler,
|
|
246
|
+
});
|
|
188
247
|
if (name.endsWith('!')) {
|
|
189
248
|
selector['!qref'].push([name.slice(0, -1), qref]);
|
|
190
249
|
} else {
|
|
@@ -455,6 +514,33 @@ function selectorParser(
|
|
|
455
514
|
}
|
|
456
515
|
curQuery = curQuery.replace(truthyRegex, '');
|
|
457
516
|
|
|
517
|
+
// eg. <archived> or <!archived>
|
|
518
|
+
const tagRegex = /(?: |^)<(!?\w+)>(?= |$)/g;
|
|
519
|
+
const tagMatch = curQuery.match(tagRegex);
|
|
520
|
+
if (tagMatch) {
|
|
521
|
+
selector.tag = [];
|
|
522
|
+
selector['!tag'] = [];
|
|
523
|
+
for (let match of tagMatch) {
|
|
524
|
+
try {
|
|
525
|
+
let name = match.trim().replace(/^<|>$/g, '');
|
|
526
|
+
if (name.startsWith('!')) {
|
|
527
|
+
selector['!tag'].push(name.slice(1));
|
|
528
|
+
} else {
|
|
529
|
+
selector.tag.push(name);
|
|
530
|
+
}
|
|
531
|
+
} catch (e: any) {
|
|
532
|
+
continue;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
if (!selector.tag.length) {
|
|
536
|
+
delete selector.tag;
|
|
537
|
+
}
|
|
538
|
+
if (!selector['!tag'].length) {
|
|
539
|
+
delete selector['!tag'];
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
curQuery = curQuery.replace(tagRegex, '');
|
|
543
|
+
|
|
458
544
|
// eg. cdate>15
|
|
459
545
|
const gtRegex = /(?: |^)(\w+)>(-?\d+(?:\.\d+)?)(?= |$)/g;
|
|
460
546
|
const gtMatch = curQuery.match(gtRegex);
|