@webda/ql 4.0.0-beta.6 → 4.0.0-beta.8

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.
Files changed (52) hide show
  1. package/README.md +42 -4
  2. package/lib/WebdaQLLexer.d.ts +10 -9
  3. package/lib/WebdaQLLexer.d.ts.map +1 -1
  4. package/lib/WebdaQLLexer.js +227 -363
  5. package/lib/WebdaQLLexer.js.map +1 -1
  6. package/lib/WebdaQLParserLexer.d.ts +10 -9
  7. package/lib/WebdaQLParserLexer.d.ts.map +1 -1
  8. package/lib/WebdaQLParserLexer.js +227 -363
  9. package/lib/WebdaQLParserLexer.js.map +1 -1
  10. package/lib/WebdaQLParserListener.d.ts +26 -2
  11. package/lib/WebdaQLParserListener.d.ts.map +1 -1
  12. package/lib/WebdaQLParserParser.d.ts +34 -9
  13. package/lib/WebdaQLParserParser.d.ts.map +1 -1
  14. package/lib/WebdaQLParserParser.js +585 -732
  15. package/lib/WebdaQLParserParser.js.map +1 -1
  16. package/lib/WebdaQLParserVisitor.d.ts +16 -1
  17. package/lib/WebdaQLParserVisitor.d.ts.map +1 -1
  18. package/lib/aggregation-select.spec.js +4 -3
  19. package/lib/aggregation-select.spec.js.map +1 -1
  20. package/lib/completion.d.ts +84 -0
  21. package/lib/completion.d.ts.map +1 -0
  22. package/lib/completion.js +467 -0
  23. package/lib/completion.js.map +1 -0
  24. package/lib/completion.spec.d.ts +25 -0
  25. package/lib/completion.spec.d.ts.map +1 -0
  26. package/lib/completion.spec.js +409 -0
  27. package/lib/completion.spec.js.map +1 -0
  28. package/lib/filter.d.ts +54 -0
  29. package/lib/filter.d.ts.map +1 -0
  30. package/lib/filter.js +135 -0
  31. package/lib/filter.js.map +1 -0
  32. package/lib/filter.spec.d.ts +2 -0
  33. package/lib/filter.spec.d.ts.map +1 -0
  34. package/lib/filter.spec.js +124 -0
  35. package/lib/filter.spec.js.map +1 -0
  36. package/lib/index.d.ts +2 -0
  37. package/lib/index.d.ts.map +1 -1
  38. package/lib/index.js +2 -0
  39. package/lib/index.js.map +1 -1
  40. package/lib/now.spec.d.ts +2 -0
  41. package/lib/now.spec.d.ts.map +1 -0
  42. package/lib/now.spec.js +258 -0
  43. package/lib/now.spec.js.map +1 -0
  44. package/lib/query.d.ts +134 -8
  45. package/lib/query.d.ts.map +1 -1
  46. package/lib/query.js +314 -39
  47. package/lib/query.js.map +1 -1
  48. package/lib/query.spec.js +1 -0
  49. package/lib/query.spec.js.map +1 -1
  50. package/lib/statements.spec.js +1 -0
  51. package/lib/statements.spec.js.map +1 -1
  52. package/package.json +3 -2
@@ -0,0 +1,409 @@
1
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
2
+ var useValue = arguments.length > 2;
3
+ for (var i = 0; i < initializers.length; i++) {
4
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
5
+ }
6
+ return useValue ? value : void 0;
7
+ };
8
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
9
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
10
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
11
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
12
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
13
+ var _, done = false;
14
+ for (var i = decorators.length - 1; i >= 0; i--) {
15
+ var context = {};
16
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
17
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
18
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
19
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
20
+ if (kind === "accessor") {
21
+ if (result === void 0) continue;
22
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
23
+ if (_ = accept(result.get)) descriptor.get = _;
24
+ if (_ = accept(result.set)) descriptor.set = _;
25
+ if (_ = accept(result.init)) initializers.unshift(_);
26
+ }
27
+ else if (_ = accept(result)) {
28
+ if (kind === "field") initializers.unshift(_);
29
+ else descriptor[key] = _;
30
+ }
31
+ }
32
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
+ done = true;
34
+ };
35
+ import { suite, test } from "@webda/test";
36
+ import * as assert from "assert";
37
+ import { getCompletions, fieldsFromSchema } from "./completion.js";
38
+ const TEST_FIELDS = [
39
+ { name: "status", type: "string", enum: ["open", "closed"] },
40
+ { name: "priority", type: "integer" },
41
+ { name: "done", type: "boolean" },
42
+ { name: "profile.email", type: "string" }
43
+ ];
44
+ /**
45
+ * Helper that takes a query string containing '|' as caret marker,
46
+ * runs getCompletions, and returns the result.
47
+ */
48
+ function complete(markedQuery, options = { fields: TEST_FIELDS }) {
49
+ const caret = markedQuery.indexOf("|");
50
+ if (caret === -1) {
51
+ throw new Error(`Test query must contain '|' to mark caret: "${markedQuery}"`);
52
+ }
53
+ const cleanQuery = markedQuery.slice(0, caret) + markedQuery.slice(caret + 1);
54
+ return getCompletions(cleanQuery, caret, options);
55
+ }
56
+ let CompletionTest = (() => {
57
+ let _classDecorators = [suite];
58
+ let _classDescriptor;
59
+ let _classExtraInitializers = [];
60
+ let _classThis;
61
+ let _instanceExtraInitializers = [];
62
+ let _caretAtStart_decorators;
63
+ let _partialIdentifier_decorators;
64
+ let _afterIdentifier_decorators;
65
+ let _afterComparisonOnEnumField_decorators;
66
+ let _afterComparisonOnBooleanField_decorators;
67
+ let _afterCompleteComparison_decorators;
68
+ let _afterCompleteComparisonWithPrefix_decorators;
69
+ let _afterOrderByField_decorators;
70
+ let _afterSelect_decorators;
71
+ let _afterSelectCountStar_decorators;
72
+ let _afterUpdate_decorators;
73
+ let _afterUpdateSet_decorators;
74
+ let _dottedPathPrefix_decorators;
75
+ let _insideStringLiteral_decorators;
76
+ let _insideUnclosedStringLiteral_decorators;
77
+ let _afterLimit_decorators;
78
+ let _syntaxErrorAndCaretBoundsNoThrow_decorators;
79
+ let _noFieldsOption_decorators;
80
+ let _namedParameters_decorators;
81
+ let _candidateLimit_decorators;
82
+ let _fieldsFromSchema_decorators;
83
+ let _performanceCheck_decorators;
84
+ var CompletionTest = class {
85
+ static { _classThis = this; }
86
+ static {
87
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
88
+ _caretAtStart_decorators = [test];
89
+ _partialIdentifier_decorators = [test];
90
+ _afterIdentifier_decorators = [test];
91
+ _afterComparisonOnEnumField_decorators = [test];
92
+ _afterComparisonOnBooleanField_decorators = [test];
93
+ _afterCompleteComparison_decorators = [test];
94
+ _afterCompleteComparisonWithPrefix_decorators = [test];
95
+ _afterOrderByField_decorators = [test];
96
+ _afterSelect_decorators = [test];
97
+ _afterSelectCountStar_decorators = [test];
98
+ _afterUpdate_decorators = [test];
99
+ _afterUpdateSet_decorators = [test];
100
+ _dottedPathPrefix_decorators = [test];
101
+ _insideStringLiteral_decorators = [test];
102
+ _insideUnclosedStringLiteral_decorators = [test];
103
+ _afterLimit_decorators = [test];
104
+ _syntaxErrorAndCaretBoundsNoThrow_decorators = [test];
105
+ _noFieldsOption_decorators = [test];
106
+ _namedParameters_decorators = [test];
107
+ _candidateLimit_decorators = [test];
108
+ _fieldsFromSchema_decorators = [test];
109
+ _performanceCheck_decorators = [test];
110
+ __esDecorate(this, null, _caretAtStart_decorators, { kind: "method", name: "caretAtStart", static: false, private: false, access: { has: obj => "caretAtStart" in obj, get: obj => obj.caretAtStart }, metadata: _metadata }, null, _instanceExtraInitializers);
111
+ __esDecorate(this, null, _partialIdentifier_decorators, { kind: "method", name: "partialIdentifier", static: false, private: false, access: { has: obj => "partialIdentifier" in obj, get: obj => obj.partialIdentifier }, metadata: _metadata }, null, _instanceExtraInitializers);
112
+ __esDecorate(this, null, _afterIdentifier_decorators, { kind: "method", name: "afterIdentifier", static: false, private: false, access: { has: obj => "afterIdentifier" in obj, get: obj => obj.afterIdentifier }, metadata: _metadata }, null, _instanceExtraInitializers);
113
+ __esDecorate(this, null, _afterComparisonOnEnumField_decorators, { kind: "method", name: "afterComparisonOnEnumField", static: false, private: false, access: { has: obj => "afterComparisonOnEnumField" in obj, get: obj => obj.afterComparisonOnEnumField }, metadata: _metadata }, null, _instanceExtraInitializers);
114
+ __esDecorate(this, null, _afterComparisonOnBooleanField_decorators, { kind: "method", name: "afterComparisonOnBooleanField", static: false, private: false, access: { has: obj => "afterComparisonOnBooleanField" in obj, get: obj => obj.afterComparisonOnBooleanField }, metadata: _metadata }, null, _instanceExtraInitializers);
115
+ __esDecorate(this, null, _afterCompleteComparison_decorators, { kind: "method", name: "afterCompleteComparison", static: false, private: false, access: { has: obj => "afterCompleteComparison" in obj, get: obj => obj.afterCompleteComparison }, metadata: _metadata }, null, _instanceExtraInitializers);
116
+ __esDecorate(this, null, _afterCompleteComparisonWithPrefix_decorators, { kind: "method", name: "afterCompleteComparisonWithPrefix", static: false, private: false, access: { has: obj => "afterCompleteComparisonWithPrefix" in obj, get: obj => obj.afterCompleteComparisonWithPrefix }, metadata: _metadata }, null, _instanceExtraInitializers);
117
+ __esDecorate(this, null, _afterOrderByField_decorators, { kind: "method", name: "afterOrderByField", static: false, private: false, access: { has: obj => "afterOrderByField" in obj, get: obj => obj.afterOrderByField }, metadata: _metadata }, null, _instanceExtraInitializers);
118
+ __esDecorate(this, null, _afterSelect_decorators, { kind: "method", name: "afterSelect", static: false, private: false, access: { has: obj => "afterSelect" in obj, get: obj => obj.afterSelect }, metadata: _metadata }, null, _instanceExtraInitializers);
119
+ __esDecorate(this, null, _afterSelectCountStar_decorators, { kind: "method", name: "afterSelectCountStar", static: false, private: false, access: { has: obj => "afterSelectCountStar" in obj, get: obj => obj.afterSelectCountStar }, metadata: _metadata }, null, _instanceExtraInitializers);
120
+ __esDecorate(this, null, _afterUpdate_decorators, { kind: "method", name: "afterUpdate", static: false, private: false, access: { has: obj => "afterUpdate" in obj, get: obj => obj.afterUpdate }, metadata: _metadata }, null, _instanceExtraInitializers);
121
+ __esDecorate(this, null, _afterUpdateSet_decorators, { kind: "method", name: "afterUpdateSet", static: false, private: false, access: { has: obj => "afterUpdateSet" in obj, get: obj => obj.afterUpdateSet }, metadata: _metadata }, null, _instanceExtraInitializers);
122
+ __esDecorate(this, null, _dottedPathPrefix_decorators, { kind: "method", name: "dottedPathPrefix", static: false, private: false, access: { has: obj => "dottedPathPrefix" in obj, get: obj => obj.dottedPathPrefix }, metadata: _metadata }, null, _instanceExtraInitializers);
123
+ __esDecorate(this, null, _insideStringLiteral_decorators, { kind: "method", name: "insideStringLiteral", static: false, private: false, access: { has: obj => "insideStringLiteral" in obj, get: obj => obj.insideStringLiteral }, metadata: _metadata }, null, _instanceExtraInitializers);
124
+ __esDecorate(this, null, _insideUnclosedStringLiteral_decorators, { kind: "method", name: "insideUnclosedStringLiteral", static: false, private: false, access: { has: obj => "insideUnclosedStringLiteral" in obj, get: obj => obj.insideUnclosedStringLiteral }, metadata: _metadata }, null, _instanceExtraInitializers);
125
+ __esDecorate(this, null, _afterLimit_decorators, { kind: "method", name: "afterLimit", static: false, private: false, access: { has: obj => "afterLimit" in obj, get: obj => obj.afterLimit }, metadata: _metadata }, null, _instanceExtraInitializers);
126
+ __esDecorate(this, null, _syntaxErrorAndCaretBoundsNoThrow_decorators, { kind: "method", name: "syntaxErrorAndCaretBoundsNoThrow", static: false, private: false, access: { has: obj => "syntaxErrorAndCaretBoundsNoThrow" in obj, get: obj => obj.syntaxErrorAndCaretBoundsNoThrow }, metadata: _metadata }, null, _instanceExtraInitializers);
127
+ __esDecorate(this, null, _noFieldsOption_decorators, { kind: "method", name: "noFieldsOption", static: false, private: false, access: { has: obj => "noFieldsOption" in obj, get: obj => obj.noFieldsOption }, metadata: _metadata }, null, _instanceExtraInitializers);
128
+ __esDecorate(this, null, _namedParameters_decorators, { kind: "method", name: "namedParameters", static: false, private: false, access: { has: obj => "namedParameters" in obj, get: obj => obj.namedParameters }, metadata: _metadata }, null, _instanceExtraInitializers);
129
+ __esDecorate(this, null, _candidateLimit_decorators, { kind: "method", name: "candidateLimit", static: false, private: false, access: { has: obj => "candidateLimit" in obj, get: obj => obj.candidateLimit }, metadata: _metadata }, null, _instanceExtraInitializers);
130
+ __esDecorate(this, null, _fieldsFromSchema_decorators, { kind: "method", name: "fieldsFromSchema", static: false, private: false, access: { has: obj => "fieldsFromSchema" in obj, get: obj => obj.fieldsFromSchema }, metadata: _metadata }, null, _instanceExtraInitializers);
131
+ __esDecorate(this, null, _performanceCheck_decorators, { kind: "method", name: "performanceCheck", static: false, private: false, access: { has: obj => "performanceCheck" in obj, get: obj => obj.performanceCheck }, metadata: _metadata }, null, _instanceExtraInitializers);
132
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
133
+ CompletionTest = _classThis = _classDescriptor.value;
134
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
135
+ __runInitializers(_classThis, _classExtraInitializers);
136
+ }
137
+ caretAtStart() {
138
+ // "|" -> fields, SELECT, DELETE, UPDATE, ORDER BY, LIMIT
139
+ const res = complete("|");
140
+ const labels = res.items.map(i => i.label);
141
+ assert.ok(labels.includes("status"), "Should include status field");
142
+ assert.ok(labels.includes("priority"), "Should include priority field");
143
+ assert.ok(labels.includes("done"), "Should include done field");
144
+ assert.ok(labels.includes("profile.email"), "Should include profile.email field");
145
+ assert.ok(labels.includes("SELECT"), "Should include SELECT");
146
+ assert.ok(labels.includes("DELETE"), "Should include DELETE");
147
+ assert.ok(labels.includes("UPDATE"), "Should include UPDATE");
148
+ assert.ok(labels.includes("ORDER BY"), "Should include ORDER BY");
149
+ assert.ok(labels.includes("LIMIT"), "Should include LIMIT");
150
+ // with filterOnly: no SELECT/DELETE/UPDATE
151
+ const filterRes = complete("|", { fields: TEST_FIELDS, filterOnly: true });
152
+ const filterLabels = filterRes.items.map(i => i.label);
153
+ assert.ok(!filterLabels.includes("SELECT"), "filterOnly should exclude SELECT");
154
+ assert.ok(!filterLabels.includes("DELETE"), "filterOnly should exclude DELETE");
155
+ assert.ok(!filterLabels.includes("UPDATE"), "filterOnly should exclude UPDATE");
156
+ assert.ok(filterLabels.includes("status"), "filterOnly should still include fields");
157
+ assert.ok(filterLabels.includes("ORDER BY"), "filterOnly should still include ORDER BY");
158
+ assert.ok(filterLabels.includes("LIMIT"), "filterOnly should still include LIMIT");
159
+ }
160
+ partialIdentifier() {
161
+ // "sta|" -> status with range [0,3]
162
+ const res = complete("sta|");
163
+ assert.strictEqual(res.prefix, "sta");
164
+ const statusItem = res.items.find(i => i.label === "status");
165
+ assert.ok(statusItem, "Should offer status");
166
+ assert.deepStrictEqual(statusItem.range, [0, 3]);
167
+ assert.strictEqual(statusItem.kind, "field");
168
+ }
169
+ afterIdentifier() {
170
+ // "status |" -> =, !=, IN, LIKE, CONTAINS, IS NULL, IS NOT NULL; no fields
171
+ const res = complete("status |");
172
+ const labels = res.items.map(i => i.label);
173
+ assert.ok(labels.includes("="), "Should include =");
174
+ assert.ok(labels.includes("!="), "Should include !=");
175
+ assert.ok(labels.includes("IN"), "Should include IN");
176
+ assert.ok(labels.includes("LIKE"), "Should include LIKE");
177
+ assert.ok(labels.includes("CONTAINS"), "Should include CONTAINS");
178
+ assert.ok(labels.includes("IS NULL"), "Should include IS NULL");
179
+ assert.ok(labels.includes("IS NOT NULL"), "Should include IS NOT NULL");
180
+ // no fields
181
+ assert.ok(!labels.includes("status"), "Should not include status field");
182
+ assert.ok(!labels.includes("priority"), "Should not include priority field");
183
+ assert.ok(!labels.includes("done"), "Should not include done field");
184
+ }
185
+ afterComparisonOnEnumField() {
186
+ // "status = |" -> 'open', 'closed', ?; no TRUE
187
+ const res = complete("status = |");
188
+ const labels = res.items.map(i => i.label);
189
+ assert.ok(labels.includes("'open'"), "Should include 'open'");
190
+ assert.ok(labels.includes("'closed'"), "Should include 'closed'");
191
+ assert.ok(labels.includes("?"), "Should include ?");
192
+ assert.ok(!labels.includes("TRUE"), "Should NOT include TRUE");
193
+ assert.ok(!labels.includes("FALSE"), "Should NOT include FALSE");
194
+ }
195
+ afterComparisonOnBooleanField() {
196
+ // "done = |" -> TRUE, FALSE
197
+ const res = complete("done = |");
198
+ const labels = res.items.map(i => i.label);
199
+ assert.ok(labels.includes("TRUE"), "Should include TRUE");
200
+ assert.ok(labels.includes("FALSE"), "Should include FALSE");
201
+ }
202
+ afterCompleteComparison() {
203
+ // "status = 'open' |" -> AND, OR, ORDER BY, LIMIT, OFFSET
204
+ const res = complete("status = 'open' |");
205
+ const labels = res.items.map(i => i.label);
206
+ assert.ok(labels.includes("AND"), "Should include AND");
207
+ assert.ok(labels.includes("OR"), "Should include OR");
208
+ assert.ok(labels.includes("ORDER BY"), "Should include ORDER BY");
209
+ assert.ok(labels.includes("LIMIT"), "Should include LIMIT");
210
+ assert.ok(labels.includes("OFFSET"), "Should include OFFSET");
211
+ }
212
+ afterCompleteComparisonWithPrefix() {
213
+ // "status = 'open' ord|" -> ORDER BY
214
+ const res = complete("status = 'open' ord|");
215
+ const labels = res.items.map(i => i.label);
216
+ assert.strictEqual(res.prefix, "ord");
217
+ assert.ok(labels.includes("ORDER BY"), "Should include ORDER BY");
218
+ assert.ok(!labels.includes("AND"), "Should not include AND");
219
+ }
220
+ afterOrderByField() {
221
+ // "ORDER BY priority |" -> ASC, DESC, ,, LIMIT
222
+ const res = complete("ORDER BY priority |");
223
+ const labels = res.items.map(i => i.label);
224
+ assert.ok(labels.includes("ASC"), "Should include ASC");
225
+ assert.ok(labels.includes("DESC"), "Should include DESC");
226
+ assert.ok(labels.includes(","), "Should include ,");
227
+ assert.ok(labels.includes("LIMIT"), "Should include LIMIT");
228
+ }
229
+ afterSelect() {
230
+ // "SELECT |" -> fields, COUNT, SUM, AVG, MIN, MAX
231
+ const res = complete("SELECT |");
232
+ const labels = res.items.map(i => i.label);
233
+ assert.ok(labels.includes("status"), "Should include status");
234
+ assert.ok(labels.includes("priority"), "Should include priority");
235
+ assert.ok(labels.includes("COUNT"), "Should include COUNT");
236
+ assert.ok(labels.includes("SUM"), "Should include SUM");
237
+ assert.ok(labels.includes("AVG"), "Should include AVG");
238
+ assert.ok(labels.includes("MIN"), "Should include MIN");
239
+ assert.ok(labels.includes("MAX"), "Should include MAX");
240
+ }
241
+ afterSelectCountStar() {
242
+ // "SELECT COUNT(*) |" -> AS
243
+ const res = complete("SELECT COUNT(*) |");
244
+ const labels = res.items.map(i => i.label);
245
+ assert.ok(labels.includes("AS"), "Should include AS");
246
+ }
247
+ afterUpdate() {
248
+ // "UPDATE |" -> SET only
249
+ const res = complete("UPDATE |");
250
+ const labels = res.items.map(i => i.label);
251
+ assert.deepStrictEqual(labels, ["SET"]);
252
+ }
253
+ afterUpdateSet() {
254
+ // "UPDATE SET |" -> fields
255
+ const res = complete("UPDATE SET |");
256
+ const labels = res.items.map(i => i.label);
257
+ assert.ok(labels.includes("status"), "Should include status");
258
+ assert.ok(labels.includes("priority"), "Should include priority");
259
+ assert.ok(labels.includes("done"), "Should include done");
260
+ assert.ok(labels.includes("profile.email"), "Should include profile.email");
261
+ }
262
+ dottedPathPrefix() {
263
+ // "profile.|" -> profile.email only, range covers profile.
264
+ const res = complete("profile.|");
265
+ const labels = res.items.map(i => i.label);
266
+ assert.deepStrictEqual(labels, ["profile.email"]);
267
+ assert.strictEqual(res.prefix, "profile.");
268
+ assert.deepStrictEqual(res.items[0].range, [0, 8]);
269
+ }
270
+ insideStringLiteral() {
271
+ // "status = 'op|'" -> 'open' (inside a string)
272
+ const res = complete("status = 'op|'");
273
+ const labels = res.items.map(i => i.label);
274
+ assert.deepStrictEqual(labels, ["'open'"]);
275
+ assert.strictEqual(res.prefix, "op");
276
+ assert.deepStrictEqual(res.items[0].range, [9, 13]);
277
+ }
278
+ insideUnclosedStringLiteral() {
279
+ const res = complete("status = 'op|");
280
+ const labels = res.items.map(i => i.label);
281
+ assert.deepStrictEqual(labels, ["'open'"]);
282
+ assert.strictEqual(res.prefix, "op");
283
+ }
284
+ afterLimit() {
285
+ // "LIMIT |" -> ? (no fields)
286
+ const res = complete("LIMIT |");
287
+ const labels = res.items.map(i => i.label);
288
+ assert.ok(labels.includes("?"), "Should include ?");
289
+ assert.ok(!labels.includes("status"), "Should not include fields");
290
+ assert.ok(!labels.includes("priority"), "Should not include fields");
291
+ }
292
+ syntaxErrorAndCaretBoundsNoThrow() {
293
+ // "x = #|", caret -1, caret 999 -> no throw
294
+ assert.doesNotThrow(() => complete("x = #|"));
295
+ assert.doesNotThrow(() => {
296
+ const res = getCompletions("status =", -1, { fields: TEST_FIELDS });
297
+ assert.ok(Array.isArray(res.items));
298
+ });
299
+ assert.doesNotThrow(() => {
300
+ const res = getCompletions("status =", 999, { fields: TEST_FIELDS });
301
+ assert.ok(Array.isArray(res.items));
302
+ });
303
+ assert.doesNotThrow(() => {
304
+ const res = getCompletions(null, 0);
305
+ assert.deepStrictEqual(res, { items: [], prefix: "" });
306
+ });
307
+ }
308
+ noFieldsOption() {
309
+ // no fields option -> no field items, keywords still offered
310
+ const res = complete("sta|", { fields: undefined });
311
+ assert.strictEqual(res.items.filter(i => i.kind === "field").length, 0);
312
+ const emptyRes = complete("|", { fields: undefined });
313
+ const labels = emptyRes.items.map(i => i.label);
314
+ assert.ok(labels.includes("SELECT"), "Keywords still offered when fields undefined");
315
+ assert.ok(labels.includes("ORDER BY"), "Keywords still offered when fields undefined");
316
+ }
317
+ namedParameters() {
318
+ const res = complete("status = |", {
319
+ fields: TEST_FIELDS,
320
+ parameters: ["myStatus", ":other"]
321
+ });
322
+ const labels = res.items.map(i => i.label);
323
+ assert.ok(labels.includes(":myStatus"));
324
+ assert.ok(labels.includes(":other"));
325
+ assert.ok(labels.includes("?"));
326
+ }
327
+ candidateLimit() {
328
+ const res = complete("|", { fields: TEST_FIELDS, limit: 3 });
329
+ assert.strictEqual(res.items.length, 3);
330
+ }
331
+ fieldsFromSchema() {
332
+ const schema = {
333
+ type: "object",
334
+ properties: {
335
+ title: { type: "string", description: "Post title" },
336
+ status: { type: "string", enum: ["draft", "published"], description: "Post status" },
337
+ count: { type: "integer" },
338
+ active: { type: "boolean" },
339
+ author: {
340
+ type: "object",
341
+ description: "Author info",
342
+ properties: {
343
+ name: { type: "string" },
344
+ contact: {
345
+ type: "object",
346
+ properties: {
347
+ email: { type: "string" },
348
+ deep: {
349
+ type: "object",
350
+ properties: {
351
+ level4: { type: "string" }
352
+ }
353
+ }
354
+ }
355
+ }
356
+ }
357
+ },
358
+ ignoredRef: {
359
+ $ref: "#/definitions/SomeType"
360
+ },
361
+ booleanTrueProp: true,
362
+ booleanFalseProp: false
363
+ }
364
+ };
365
+ const fields = fieldsFromSchema(schema);
366
+ const names = fields.map(f => f.name);
367
+ assert.ok(names.includes("title"), "Should include title");
368
+ assert.ok(names.includes("status"), "Should include status");
369
+ assert.ok(names.includes("count"), "Should include count");
370
+ assert.ok(names.includes("active"), "Should include active");
371
+ assert.ok(names.includes("author.name"), "Should include author.name");
372
+ assert.ok(names.includes("author.contact.email"), "Should include author.contact.email");
373
+ assert.ok(names.includes("booleanTrueProp"), "Should include boolean true property");
374
+ assert.ok(!names.includes("booleanFalseProp"), "Should exclude boolean false property");
375
+ assert.ok(!names.includes("ignoredRef"), "Should skip $ref property");
376
+ // Check depth limit (maxDepth = 3: author(1) -> contact(2) -> deep(3), level4 is at depth 4)
377
+ assert.ok(names.includes("author.contact.deep"), "Deep object should be included as object at depth limit");
378
+ assert.ok(!names.includes("author.contact.deep.level4"), "Should not recurse past maxDepth 3");
379
+ // Check enum/type/description copied
380
+ const statusField = fields.find(f => f.name === "status");
381
+ assert.deepStrictEqual(statusField?.enum, ["draft", "published"]);
382
+ assert.strictEqual(statusField?.type, "string");
383
+ assert.strictEqual(statusField?.description, "Post status");
384
+ // Empty or non-object schema
385
+ assert.deepStrictEqual(fieldsFromSchema({}), []);
386
+ assert.deepStrictEqual(fieldsFromSchema(null), []);
387
+ }
388
+ performanceCheck() {
389
+ const query = "SELECT title, content, author, createdAt WHERE status = 'published' AND priority > 10 AND done = TRUE AND category IN ['tech', 'news'] ORDER BY createdAt DESC LIMIT 20 OFFSET 'token123'";
390
+ assert.ok(query.length >= 180, "Query should be around 200 characters");
391
+ const start = Date.now();
392
+ for (let i = 0; i < 1000; i++) {
393
+ getCompletions(query, 50, { fields: TEST_FIELDS });
394
+ }
395
+ const elapsed = Date.now() - start;
396
+ console.log(`1,000 getCompletions calls completed in ${elapsed}ms`);
397
+ if (elapsed > 1000) {
398
+ console.warn(`Performance warning: 1000 calls took ${elapsed}ms (target <1000ms)`);
399
+ }
400
+ assert.ok(elapsed < 5000, `Expected 1000 calls to complete within reasonable time, took ${elapsed}ms`);
401
+ }
402
+ constructor() {
403
+ __runInitializers(this, _instanceExtraInitializers);
404
+ }
405
+ };
406
+ return CompletionTest = _classThis;
407
+ })();
408
+ export { CompletionTest };
409
+ //# sourceMappingURL=completion.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion.spec.js","sourceRoot":"","sources":["../src/completion.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import { type Expression } from "./query.js";
2
+ import type { WebdaQLString } from "./webdaql-string.js";
3
+ type Primitive = string | number | boolean | bigint | symbol | null | undefined;
4
+ type PropertyPaths<T extends object> = {
5
+ [K in Extract<keyof T, string>]: T[K] extends Function ? never : NonNullable<T[K]> extends Primitive | Date | RegExp | Array<any> | Map<any, any> | Set<any> ? K : NonNullable<T[K]> extends object ? K | `${K}.${PropertyPaths<NonNullable<T[K]>>}` : K;
6
+ }[Extract<keyof T, string>];
7
+ type PathValue<T, K extends string> = K extends `${infer H}.${infer R}` ? H extends keyof T ? PathValue<NonNullable<T[H]>, R> : never : K extends keyof T ? T[K] : never;
8
+ type PropertyPathType<T extends object, K extends PropertyPaths<T>> = PathValue<T, K>;
9
+ export type FilterOperators<V> = {
10
+ $eq?: V | null;
11
+ $ne?: V | null;
12
+ $gt?: V;
13
+ $gte?: V;
14
+ $lt?: V;
15
+ $lte?: V;
16
+ $in?: V[];
17
+ $like?: string;
18
+ $contains?: V extends readonly (infer E)[] ? Extract<E, string> : never;
19
+ $exists?: boolean;
20
+ };
21
+ export type ModelFilter<T extends object = any> = {
22
+ [K in PropertyPaths<T>]?: PropertyPathType<T, K> | null | FilterOperators<PropertyPathType<T, K>>;
23
+ } & {
24
+ $or?: ModelFilter<T>[];
25
+ $and?: ModelFilter<T>[];
26
+ };
27
+ export interface FindOptions<T extends object> {
28
+ orderBy?: {
29
+ field: PropertyPaths<T>;
30
+ direction: "ASC" | "DESC";
31
+ }[];
32
+ limit?: number;
33
+ continuationToken?: string;
34
+ }
35
+ /**
36
+ * Convert a JSON filter to a WebdaQL expression
37
+ *
38
+ * Keys set to `undefined` are ignored, so optional criteria can be spread in. A plain object without
39
+ * operators matches its nested fields: `{ address: { city: "Paris" } }` is `address.city = "Paris"`.
40
+ * @param filter - the JSON filter
41
+ * @returns the expression
42
+ * @throws {WebdaQLError} for an invalid filter
43
+ */
44
+ export declare function filterToExpression(filter: ModelFilter): Expression;
45
+ /**
46
+ * Convert a JSON filter and its find options to a WebdaQL query string
47
+ * @param filter - the JSON filter
48
+ * @param options - ordering, limit and continuation token
49
+ * @returns the WebdaQL query
50
+ * @throws {WebdaQLError} for an invalid filter
51
+ */
52
+ export declare function toWebdaQL<T extends object = any>(filter: ModelFilter<T>, options?: FindOptions<T>): WebdaQLString<T>;
53
+ export {};
54
+ //# sourceMappingURL=filter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"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"}
package/lib/filter.js ADDED
@@ -0,0 +1,135 @@
1
+ import { AndExpression, ComparisonExpression, OrExpression, checkFieldPath, normalizeQuery } from "./query.js";
2
+ import { WebdaQLError } from "./webdaql-string.js";
3
+ const operators = {
4
+ $eq: "=",
5
+ $ne: "!=",
6
+ $gt: ">",
7
+ $gte: ">=",
8
+ $lt: "<",
9
+ $lte: "<=",
10
+ $in: "IN",
11
+ $like: "LIKE",
12
+ $contains: "CONTAINS"
13
+ };
14
+ /**
15
+ * WebdaQL has no date literal: dates are compared as ISO 8601 strings, the way they are serialized
16
+ * @param value - the filter value
17
+ * @returns the value, with dates as ISO strings
18
+ */
19
+ function toFilterValue(value) {
20
+ if (Array.isArray(value))
21
+ return value.map(toFilterValue);
22
+ if (!(value instanceof Date))
23
+ return value;
24
+ if (isNaN(value.getTime()))
25
+ throw new WebdaQLError("Invalid date in filter");
26
+ return value.toISOString();
27
+ }
28
+ /**
29
+ * Convert a JSON filter to a WebdaQL expression
30
+ *
31
+ * Keys set to `undefined` are ignored, so optional criteria can be spread in. A plain object without
32
+ * operators matches its nested fields: `{ address: { city: "Paris" } }` is `address.city = "Paris"`.
33
+ * @param filter - the JSON filter
34
+ * @returns the expression
35
+ * @throws {WebdaQLError} for an invalid filter
36
+ */
37
+ export function filterToExpression(filter) {
38
+ if (!filter || typeof filter !== "object" || Array.isArray(filter))
39
+ throw new WebdaQLError("Filter must be an object");
40
+ const parts = [];
41
+ for (const key of Object.keys(filter)) {
42
+ const value = filter[key];
43
+ if (value === undefined)
44
+ continue;
45
+ if (key === "$or" || key === "$and") {
46
+ if (!Array.isArray(value) || !value.length)
47
+ throw new WebdaQLError(`${key} requires a non-empty array`);
48
+ parts.push(key === "$or"
49
+ ? new OrExpression(value.map(filterToExpression))
50
+ : new AndExpression(value.map(filterToExpression)));
51
+ continue;
52
+ }
53
+ if (key.startsWith("$"))
54
+ throw new WebdaQLError(`Unknown filter operator '${key}'`);
55
+ fieldToExpressions(key, value, parts);
56
+ }
57
+ return new AndExpression(parts);
58
+ }
59
+ /**
60
+ * Add the conditions on one field
61
+ * @param key - the field path
62
+ * @param value - a plain value, an operator object or a nested object
63
+ * @param parts - the conditions to add to
64
+ */
65
+ function fieldToExpressions(key, value, parts) {
66
+ checkFieldPath(key);
67
+ if (value === null) {
68
+ parts.push(new ComparisonExpression("IS NULL", key, true));
69
+ return;
70
+ }
71
+ if (typeof value !== "object" || Array.isArray(value) || value instanceof Date) {
72
+ parts.push(new ComparisonExpression("=", key, toFilterValue(value)));
73
+ return;
74
+ }
75
+ const keys = Object.keys(value);
76
+ if (!keys.length)
77
+ throw new WebdaQLError(`Empty filter object for '${key}'`);
78
+ const operatorKeys = keys.filter(k => k.startsWith("$"));
79
+ if (!operatorKeys.length) {
80
+ // Nested object: match each of its fields
81
+ const before = parts.length;
82
+ for (const sub of keys) {
83
+ if (value[sub] !== undefined)
84
+ fieldToExpressions(`${key}.${sub}`, value[sub], parts);
85
+ }
86
+ if (parts.length === before)
87
+ throw new WebdaQLError(`Empty filter object for '${key}'`);
88
+ return;
89
+ }
90
+ if (operatorKeys.length !== keys.length)
91
+ throw new WebdaQLError(`Cannot mix operators and fields in '${key}'`);
92
+ for (const op of keys) {
93
+ const operand = value[op];
94
+ if (operand === undefined)
95
+ continue;
96
+ if (op === "$exists") {
97
+ if (typeof operand !== "boolean")
98
+ throw new WebdaQLError("$exists must be a boolean");
99
+ parts.push(new ComparisonExpression(operand ? "IS NOT NULL" : "IS NULL", key, true));
100
+ }
101
+ else if ((op === "$eq" || op === "$ne") && operand === null) {
102
+ parts.push(new ComparisonExpression(op === "$eq" ? "IS NULL" : "IS NOT NULL", key, true));
103
+ }
104
+ else {
105
+ const mapped = operators[op];
106
+ if (!mapped)
107
+ throw new WebdaQLError(`Unknown filter operator '${op}'`);
108
+ if (operand === null)
109
+ throw new WebdaQLError("null is only supported with $eq, $ne, or $exists");
110
+ if (op === "$in" && (!Array.isArray(operand) || !operand.length))
111
+ throw new WebdaQLError("$in requires a non-empty array");
112
+ if (op === "$contains" && typeof operand !== "string")
113
+ throw new WebdaQLError("$contains takes a string");
114
+ parts.push(new ComparisonExpression(mapped, key, toFilterValue(operand)));
115
+ }
116
+ }
117
+ }
118
+ /**
119
+ * Convert a JSON filter and its find options to a WebdaQL query string
120
+ * @param filter - the JSON filter
121
+ * @param options - ordering, limit and continuation token
122
+ * @returns the WebdaQL query
123
+ * @throws {WebdaQLError} for an invalid filter
124
+ */
125
+ export function toWebdaQL(filter, options) {
126
+ const q = normalizeQuery({
127
+ type: "SELECT",
128
+ filter: filterToExpression(filter),
129
+ orderBy: options?.orderBy,
130
+ limit: options?.limit,
131
+ continuationToken: options?.continuationToken
132
+ });
133
+ return q.toString();
134
+ }
135
+ //# sourceMappingURL=filter.js.map