@balena/abstract-sql-compiler 10.6.3-build-tests-update-66ee93652310d4add5b0c8c09843dc052d796f5e-1 → 11.0.0-build-11-x-9f16483079cd561a9fdaa741cd830c2c5eb2065a-1
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/.versionbot/CHANGELOG.yml +57 -2
- package/CHANGELOG.md +8 -2
- package/out/AbstractSQLCompiler.d.ts +15 -16
- package/out/AbstractSQLCompiler.js +50 -62
- package/out/AbstractSQLCompiler.js.map +1 -1
- package/out/AbstractSQLOptimiser.d.ts +1 -1
- package/out/AbstractSQLOptimiser.js +9 -54
- package/out/AbstractSQLOptimiser.js.map +1 -1
- package/out/AbstractSQLRules2SQL.d.ts +2 -2
- package/out/AbstractSQLRules2SQL.js +206 -224
- package/out/AbstractSQLRules2SQL.js.map +1 -1
- package/out/AbstractSQLSchemaOptimiser.d.ts +5 -3
- package/out/AbstractSQLSchemaOptimiser.js +14 -21
- package/out/AbstractSQLSchemaOptimiser.js.map +1 -1
- package/out/referenced-fields.d.ts +1 -1
- package/out/referenced-fields.js +17 -24
- package/out/referenced-fields.js.map +1 -1
- package/package.json +4 -4
- package/src/AbstractSQLCompiler.ts +28 -30
- package/src/AbstractSQLOptimiser.ts +11 -27
- package/src/AbstractSQLRules2SQL.ts +4 -3
- package/src/AbstractSQLSchemaOptimiser.ts +7 -6
- package/src/referenced-fields.ts +4 -4
- package/test/abstract-sql/aggregate-json.ts +1 -1
- package/test/abstract-sql/aggregate.ts +25 -10
- package/test/abstract-sql/and-or-boolean-optimisations.ts +1 -1
- package/test/abstract-sql/case-when-else.ts +5 -2
- package/test/abstract-sql/cast.ts +1 -1
- package/test/abstract-sql/coalesce.ts +1 -1
- package/test/abstract-sql/comparisons.ts +1 -1
- package/test/abstract-sql/dates.ts +10 -4
- package/test/abstract-sql/duration.ts +1 -1
- package/test/abstract-sql/empty-query-optimisations.ts +2 -2
- package/test/abstract-sql/functions_wrapper.ts +1 -1
- package/test/abstract-sql/get-referenced-fields.ts +1 -1
- package/test/abstract-sql/get-rule-referenced-fields.ts +1 -1
- package/test/abstract-sql/insert-query.ts +1 -1
- package/test/abstract-sql/is-distinct.ts +1 -1
- package/test/abstract-sql/joins.ts +1 -1
- package/test/abstract-sql/json.ts +1 -1
- package/test/abstract-sql/math.ts +1 -1
- package/test/abstract-sql/nested-in-optimisations.ts +1 -1
- package/test/abstract-sql/not-not-optimisations.ts +1 -1
- package/test/abstract-sql/schema-checks.ts +1 -1
- package/test/abstract-sql/schema-informative-reference.ts +1 -1
- package/test/abstract-sql/schema-rule-optimization.ts +1 -1
- package/test/abstract-sql/schema-rule-to-check.ts +1 -1
- package/test/abstract-sql/schema-views.ts +37 -2
- package/test/abstract-sql/test.ts +1 -1
- package/test/abstract-sql/text.ts +1 -1
- package/test/odata/expand.ts +3 -3
- package/test/odata/filterby.ts +8 -4
- package/test/odata/orderby.ts +2 -2
- package/test/odata/paging.ts +2 -2
- package/test/odata/resource_parsing.ts +5 -5
- package/test/odata/select.ts +2 -2
- package/test/odata/stress.ts +2 -2
- package/test/odata/test.ts +24 -20
- package/test/sbvr/pilots.ts +3 -3
- package/test/sbvr/reference-type.ts +3 -3
- package/test/sbvr/test.ts +12 -10
@@ -1,17 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
};
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.checkMinArgs = exports.checkArgs = exports.getAbstractSqlQuery = exports.isAbstractSqlQuery = exports.isNotNullable = exports.isDurationValue = exports.isJSONValue = exports.isArrayValue = exports.isDateValue = exports.isBooleanValue = exports.isNumericValue = exports.isTextValue = exports.comparisons = void 0;
|
7
|
-
exports.AbstractSQLRules2SQL = AbstractSQLRules2SQL;
|
8
|
-
const sbvr_types_1 = __importDefault(require("@balena/sbvr-types"));
|
9
|
-
const AbstractSQLCompiler_1 = require("./AbstractSQLCompiler");
|
1
|
+
import $sbvrTypes from '@balena/sbvr-types';
|
2
|
+
const { default: sbvrTypes } = $sbvrTypes;
|
3
|
+
import { isFieldTypeNode } from './AbstractSQLCompiler.js';
|
10
4
|
let fieldOrderings = [];
|
11
5
|
let fieldOrderingsLookup = {};
|
12
6
|
let engine = "postgres" /* Engines.postgres */;
|
13
7
|
let noBinds = false;
|
14
|
-
|
8
|
+
export const comparisons = {
|
15
9
|
Equals: ' = ',
|
16
10
|
GreaterThan: ' > ',
|
17
11
|
GreaterThanOrEqual: ' >= ',
|
@@ -25,12 +19,12 @@ const escapeField = (field) => field === '*' ? '*' : `"${field}"`;
|
|
25
19
|
const AnyValue = (args, indent) => {
|
26
20
|
const [type, ...rest] = args;
|
27
21
|
for (const matcher of [
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
22
|
+
isJSONValue,
|
23
|
+
isDateValue,
|
24
|
+
isTextValue,
|
25
|
+
isNumericValue,
|
26
|
+
isBooleanValue,
|
27
|
+
isDurationValue,
|
34
28
|
]) {
|
35
29
|
if (matcher(type)) {
|
36
30
|
return typeRules[type](rest, indent);
|
@@ -69,7 +63,7 @@ const MatchValue = (matcher) => (args, indent) => {
|
|
69
63
|
}
|
70
64
|
return UnknownValue(args, indent);
|
71
65
|
};
|
72
|
-
const isTextValue = (type) => {
|
66
|
+
export const isTextValue = (type) => {
|
73
67
|
return (type === 'Text' ||
|
74
68
|
type === 'EmbeddedText' ||
|
75
69
|
type === 'Concatenate' ||
|
@@ -83,9 +77,8 @@ const isTextValue = (type) => {
|
|
83
77
|
type === 'Right' ||
|
84
78
|
type === 'EscapeForLike');
|
85
79
|
};
|
86
|
-
|
87
|
-
const
|
88
|
-
const isNumericValue = (type) => {
|
80
|
+
const TextValue = MatchValue(isTextValue);
|
81
|
+
export const isNumericValue = (type) => {
|
89
82
|
return (type === 'Number' ||
|
90
83
|
type === 'Real' ||
|
91
84
|
type === 'Integer' ||
|
@@ -113,9 +106,8 @@ const isNumericValue = (type) => {
|
|
113
106
|
type === 'Sum' ||
|
114
107
|
type === 'SubtractDateDate');
|
115
108
|
};
|
116
|
-
|
117
|
-
const
|
118
|
-
const isBooleanValue = (type) => {
|
109
|
+
const NumericValue = MatchValue(isNumericValue);
|
110
|
+
export const isBooleanValue = (type) => {
|
119
111
|
return (type === 'Boolean' ||
|
120
112
|
type === 'Not' ||
|
121
113
|
type === 'And' ||
|
@@ -137,9 +129,8 @@ const isBooleanValue = (type) => {
|
|
137
129
|
type === 'StartsWith' ||
|
138
130
|
type === 'EqualsAny');
|
139
131
|
};
|
140
|
-
|
141
|
-
const
|
142
|
-
const isDateValue = (type) => {
|
132
|
+
const BooleanValue = MatchValue(isBooleanValue);
|
133
|
+
export const isDateValue = (type) => {
|
143
134
|
return (type === 'Date' ||
|
144
135
|
type === 'ToDate' ||
|
145
136
|
type === 'ToTime' ||
|
@@ -151,24 +142,20 @@ const isDateValue = (type) => {
|
|
151
142
|
type === 'SubtractDateDuration' ||
|
152
143
|
type === 'SubtractDateNumber');
|
153
144
|
};
|
154
|
-
|
155
|
-
const
|
156
|
-
const isArrayValue = (type) => {
|
145
|
+
const DateValue = MatchValue(isDateValue);
|
146
|
+
export const isArrayValue = (type) => {
|
157
147
|
return type === 'TextArray';
|
158
148
|
};
|
159
|
-
|
160
|
-
const isJSONValue = (type) => {
|
149
|
+
export const isJSONValue = (type) => {
|
161
150
|
return type === 'AggregateJSON' || type === 'ToJSON';
|
162
151
|
};
|
163
|
-
|
164
|
-
const
|
165
|
-
const isDurationValue = (type) => {
|
152
|
+
const JSONValue = MatchValue(isJSONValue);
|
153
|
+
export const isDurationValue = (type) => {
|
166
154
|
return type === 'Duration';
|
167
155
|
};
|
168
|
-
|
169
|
-
const DurationValue = MatchValue(exports.isDurationValue);
|
156
|
+
const DurationValue = MatchValue(isDurationValue);
|
170
157
|
const Field = (args, indent) => {
|
171
|
-
if (
|
158
|
+
if (isFieldTypeNode(args)) {
|
172
159
|
const [type, ...rest] = args;
|
173
160
|
return typeRules[type](rest, indent);
|
174
161
|
}
|
@@ -176,7 +163,7 @@ const Field = (args, indent) => {
|
|
176
163
|
throw new SyntaxError(`Invalid field type: ${args[0]}`);
|
177
164
|
}
|
178
165
|
};
|
179
|
-
const isNotNullable = (node) => {
|
166
|
+
export const isNotNullable = (node) => {
|
180
167
|
switch (node[0]) {
|
181
168
|
case 'EmbeddedText':
|
182
169
|
case 'Boolean':
|
@@ -196,14 +183,13 @@ const isNotNullable = (node) => {
|
|
196
183
|
case 'NotExists':
|
197
184
|
return true;
|
198
185
|
case 'Coalesce':
|
199
|
-
return node.slice(1).some((n) =>
|
186
|
+
return node.slice(1).some((n) => isNotNullable(n));
|
200
187
|
case 'Not':
|
201
|
-
return
|
188
|
+
return isNotNullable(node[1]);
|
202
189
|
}
|
203
190
|
return false;
|
204
191
|
};
|
205
|
-
|
206
|
-
const isAtomicNode = (n) => (0, AbstractSQLCompiler_1.isFieldTypeNode)(n) ||
|
192
|
+
const isAtomicNode = (n) => isFieldTypeNode(n) ||
|
207
193
|
n[0] === 'Bind' ||
|
208
194
|
n[0] === 'Null' ||
|
209
195
|
n[0] === 'Value' ||
|
@@ -213,8 +199,8 @@ const isAtomicNode = (n) => (0, AbstractSQLCompiler_1.isFieldTypeNode)(n) ||
|
|
213
199
|
n[0] === 'Integer' ||
|
214
200
|
n[0] === 'Boolean';
|
215
201
|
const isNotDistinctFrom = (args, indent) => {
|
216
|
-
const a =
|
217
|
-
const b =
|
202
|
+
const a = getAbstractSqlQuery(args, 0);
|
203
|
+
const b = getAbstractSqlQuery(args, 1);
|
218
204
|
let aSql = AnyValue(a, indent);
|
219
205
|
let bSql = AnyValue(b, indent);
|
220
206
|
// We can omit the parens if the value is a atomic type node, for slightly smaller/more readable sql
|
@@ -225,8 +211,8 @@ const isNotDistinctFrom = (args, indent) => {
|
|
225
211
|
bSql = `(${bSql})`;
|
226
212
|
}
|
227
213
|
if (engine === "postgres" /* Engines.postgres */) {
|
228
|
-
const aIsNotNullable =
|
229
|
-
const bIsNotNullable =
|
214
|
+
const aIsNotNullable = isNotNullable(a);
|
215
|
+
const bIsNotNullable = isNotNullable(b);
|
230
216
|
if (aIsNotNullable && bIsNotNullable) {
|
231
217
|
return `${aSql} = ${bSql}`;
|
232
218
|
}
|
@@ -252,29 +238,27 @@ const isNotDistinctFrom = (args, indent) => {
|
|
252
238
|
throw new SyntaxError(`IsDistinctFrom/IsNotDistinctFrom not supported on: ${engine}`);
|
253
239
|
}
|
254
240
|
};
|
255
|
-
const isAbstractSqlQuery = (x) => {
|
241
|
+
export const isAbstractSqlQuery = (x) => {
|
256
242
|
return Array.isArray(x);
|
257
243
|
};
|
258
|
-
|
259
|
-
const getAbstractSqlQuery = (args, index) => {
|
244
|
+
export const getAbstractSqlQuery = (args, index) => {
|
260
245
|
const abstractSqlQuery = args[index];
|
261
|
-
if (!
|
246
|
+
if (!isAbstractSqlQuery(abstractSqlQuery)) {
|
262
247
|
throw new SyntaxError(`Expected AbstractSqlQuery array but got ${typeof abstractSqlQuery}`);
|
263
248
|
}
|
264
249
|
return abstractSqlQuery;
|
265
250
|
};
|
266
|
-
exports.getAbstractSqlQuery = getAbstractSqlQuery;
|
267
251
|
const Comparison = (comparison) => {
|
268
252
|
return (args, indent) => {
|
269
|
-
|
253
|
+
checkArgs(comparison, args, 2);
|
270
254
|
const a = precedenceSafeOpValue(comparison, AnyValue, args, 0, indent);
|
271
255
|
const b = precedenceSafeOpValue(comparison, AnyValue, args, 1, indent);
|
272
|
-
return a +
|
256
|
+
return a + comparisons[comparison] + b;
|
273
257
|
};
|
274
258
|
};
|
275
259
|
const NumberMatch = (type) => {
|
276
260
|
return (args) => {
|
277
|
-
|
261
|
+
checkArgs(type, args, 1);
|
278
262
|
const n = args[0];
|
279
263
|
if (typeof n !== 'number') {
|
280
264
|
throw new SyntaxError(`${type} expected number but got ${typeof n}`);
|
@@ -307,15 +291,15 @@ const JoinMatch = (joinType) => {
|
|
307
291
|
if (args.length !== 1 && args.length !== 2) {
|
308
292
|
throw new SyntaxError(`"${joinType}" requires 1/2 arg(s)`);
|
309
293
|
}
|
310
|
-
const from = MaybeAlias(
|
294
|
+
const from = MaybeAlias(getAbstractSqlQuery(args, 0), indent, FromMatch);
|
311
295
|
if (args.length === 1) {
|
312
296
|
return sqlJoinType + from;
|
313
297
|
}
|
314
|
-
const [type, ...rest] =
|
298
|
+
const [type, ...rest] = getAbstractSqlQuery(args, 1);
|
315
299
|
switch (type) {
|
316
300
|
case 'On': {
|
317
|
-
|
318
|
-
const ruleBody = BooleanValue(
|
301
|
+
checkArgs('On', rest, 1);
|
302
|
+
const ruleBody = BooleanValue(getAbstractSqlQuery(rest, 0), NestedIndent(indent));
|
319
303
|
return sqlJoinType + from + ' ON ' + ruleBody;
|
320
304
|
}
|
321
305
|
default:
|
@@ -340,20 +324,20 @@ const mathOperatorNodeTypes = new Set([
|
|
340
324
|
'SubtractDateNumber',
|
341
325
|
]);
|
342
326
|
const precedenceSafeOpValue = (parentNodeType, valueMatchFn, args, index, indent) => {
|
343
|
-
const operandAbstractSql =
|
327
|
+
const operandAbstractSql = getAbstractSqlQuery(args, index);
|
344
328
|
const valueExpr = valueMatchFn(operandAbstractSql, indent);
|
345
329
|
const [childNodeType] = operandAbstractSql;
|
346
330
|
if ((mathOperatorNodeTypes.has(parentNodeType) &&
|
347
331
|
mathOperatorNodeTypes.has(childNodeType)) ||
|
348
332
|
// We need parenthesis for chained boolean comparisons, otherwise PostgreSQL complains.
|
349
|
-
(parentNodeType in
|
333
|
+
(parentNodeType in comparisons && childNodeType in comparisons)) {
|
350
334
|
return `(${valueExpr})`;
|
351
335
|
}
|
352
336
|
return valueExpr;
|
353
337
|
};
|
354
338
|
const MathOp = (type) => {
|
355
339
|
return (args, indent) => {
|
356
|
-
|
340
|
+
checkArgs(type, args, 2);
|
357
341
|
const a = precedenceSafeOpValue(type, NumericValue, args, 0, indent);
|
358
342
|
const b = precedenceSafeOpValue(type, NumericValue, args, 1, indent);
|
359
343
|
return `${a} ${mathOps[type]} ${b}`;
|
@@ -390,8 +374,8 @@ const dateFormats = {
|
|
390
374
|
};
|
391
375
|
const ExtractNumericDatePart = (type) => {
|
392
376
|
return (args, indent) => {
|
393
|
-
|
394
|
-
const date = DateValue(
|
377
|
+
checkArgs(type, args, 1);
|
378
|
+
const date = DateValue(getAbstractSqlQuery(args, 0), indent);
|
395
379
|
if (engine === "websql" /* Engines.websql */) {
|
396
380
|
return websqlDateFormats[type](date);
|
397
381
|
}
|
@@ -401,7 +385,7 @@ const ExtractNumericDatePart = (type) => {
|
|
401
385
|
};
|
402
386
|
};
|
403
387
|
const Text = (args) => {
|
404
|
-
|
388
|
+
checkArgs('Text', args, 1);
|
405
389
|
if (noBinds) {
|
406
390
|
return `'${args[0]}'`;
|
407
391
|
}
|
@@ -409,20 +393,18 @@ const Text = (args) => {
|
|
409
393
|
return AddBind(['Text', args[0]]);
|
410
394
|
}
|
411
395
|
};
|
412
|
-
const checkArgs = (matchName, args, num) => {
|
396
|
+
export const checkArgs = (matchName, args, num) => {
|
413
397
|
if (args.length !== num) {
|
414
398
|
throw new SyntaxError(`"${matchName}" requires ${num} arg(s)`);
|
415
399
|
}
|
416
400
|
};
|
417
|
-
|
418
|
-
const checkMinArgs = (matchName, args, num) => {
|
401
|
+
export const checkMinArgs = (matchName, args, num) => {
|
419
402
|
if (args.length < num) {
|
420
403
|
throw new SyntaxError(`"${matchName}" requires at least ${num} arg(s)`);
|
421
404
|
}
|
422
405
|
};
|
423
|
-
exports.checkMinArgs = checkMinArgs;
|
424
406
|
const AddDateNumber = (args, indent) => {
|
425
|
-
|
407
|
+
checkArgs('AddDateNumber', args, 2);
|
426
408
|
const a = precedenceSafeOpValue('AddDateNumber', DateValue, args, 0, indent);
|
427
409
|
const b = precedenceSafeOpValue('AddDateNumber', NumericValue, args, 1, indent);
|
428
410
|
if (engine === "postgres" /* Engines.postgres */) {
|
@@ -436,7 +418,7 @@ const AddDateNumber = (args, indent) => {
|
|
436
418
|
}
|
437
419
|
};
|
438
420
|
const AddDateDuration = (args, indent) => {
|
439
|
-
|
421
|
+
checkArgs('AddDateDuration', args, 2);
|
440
422
|
const a = precedenceSafeOpValue('AddDateDuration', DateValue, args, 0, indent);
|
441
423
|
const b = precedenceSafeOpValue('AddDateDuration', DurationValue, args, 1, indent);
|
442
424
|
if (engine === "postgres" /* Engines.postgres */) {
|
@@ -450,7 +432,7 @@ const AddDateDuration = (args, indent) => {
|
|
450
432
|
}
|
451
433
|
};
|
452
434
|
const SubtractDateDuration = (args, indent) => {
|
453
|
-
|
435
|
+
checkArgs('SubtractDateDuration', args, 2);
|
454
436
|
const a = precedenceSafeOpValue('SubtractDateDuration', DateValue, args, 0, indent);
|
455
437
|
const b = precedenceSafeOpValue('SubtractDateDuration', DurationValue, args, 1, indent);
|
456
438
|
if (engine === "postgres" /* Engines.postgres */) {
|
@@ -464,7 +446,7 @@ const SubtractDateDuration = (args, indent) => {
|
|
464
446
|
}
|
465
447
|
};
|
466
448
|
const SubtractDateNumber = (args, indent) => {
|
467
|
-
|
449
|
+
checkArgs('SubtractDateNumber', args, 2);
|
468
450
|
const a = precedenceSafeOpValue('SubtractDateNumber', DateValue, args, 0, indent);
|
469
451
|
const b = precedenceSafeOpValue('SubtractDateNumber', NumericValue, args, 1, indent);
|
470
452
|
if (engine === "postgres" /* Engines.postgres */) {
|
@@ -478,7 +460,7 @@ const SubtractDateNumber = (args, indent) => {
|
|
478
460
|
}
|
479
461
|
};
|
480
462
|
const SubtractDateDate = (args, indent) => {
|
481
|
-
|
463
|
+
checkArgs('SubtractDateDate', args, 2);
|
482
464
|
const a = precedenceSafeOpValue('SubtractDateDate', DateValue, args, 0, indent);
|
483
465
|
const b = precedenceSafeOpValue('SubtractDateDate', DateValue, args, 1, indent);
|
484
466
|
if (engine === "postgres" /* Engines.postgres */) {
|
@@ -532,7 +514,7 @@ const FromMatch = (args, indent) => {
|
|
532
514
|
return '(' + nestedindent + query + indent + ')';
|
533
515
|
}
|
534
516
|
case 'Table': {
|
535
|
-
|
517
|
+
checkArgs('Table', rest, 1);
|
536
518
|
const [table] = rest;
|
537
519
|
if (typeof table !== 'string') {
|
538
520
|
throw new SyntaxError('`Table` table must be a string');
|
@@ -547,8 +529,8 @@ const MaybeAlias = (args, indent, matchFn) => {
|
|
547
529
|
const [type, ...rest] = args;
|
548
530
|
switch (type) {
|
549
531
|
case 'Alias': {
|
550
|
-
|
551
|
-
const field = matchFn(
|
532
|
+
checkArgs('Alias', rest, 2);
|
533
|
+
const field = matchFn(getAbstractSqlQuery(rest, 0), indent);
|
552
534
|
return `${field} AS "${rest[1]}"`;
|
553
535
|
}
|
554
536
|
default:
|
@@ -580,10 +562,10 @@ const AddBind = (bind) => {
|
|
580
562
|
};
|
581
563
|
const typeRules = {
|
582
564
|
UnionQuery: (args, indent) => {
|
583
|
-
|
565
|
+
checkMinArgs('UnionQuery', args, 2);
|
584
566
|
return args
|
585
567
|
.map((arg) => {
|
586
|
-
if (!
|
568
|
+
if (!isAbstractSqlQuery(arg)) {
|
587
569
|
throw new SyntaxError(`Expected AbstractSqlQuery array but got ${typeof arg}`);
|
588
570
|
}
|
589
571
|
const [type, ...rest] = arg;
|
@@ -610,7 +592,7 @@ const typeRules = {
|
|
610
592
|
Offset: '',
|
611
593
|
};
|
612
594
|
for (const arg of args) {
|
613
|
-
if (!
|
595
|
+
if (!isAbstractSqlQuery(arg)) {
|
614
596
|
throw new SyntaxError('`SelectQuery` args must all be arrays');
|
615
597
|
}
|
616
598
|
const [type, ...rest] = arg;
|
@@ -665,15 +647,15 @@ const typeRules = {
|
|
665
647
|
groups.Offset);
|
666
648
|
},
|
667
649
|
Select: (args, indent) => {
|
668
|
-
|
669
|
-
args =
|
650
|
+
checkArgs('Select', args, 1);
|
651
|
+
args = getAbstractSqlQuery(args, 0);
|
670
652
|
if (args.length === 0) {
|
671
653
|
// Empty select fields are converted to `SELECT 1`
|
672
654
|
return '1';
|
673
655
|
}
|
674
656
|
return args
|
675
657
|
.map((arg) => {
|
676
|
-
if (!
|
658
|
+
if (!isAbstractSqlQuery(arg)) {
|
677
659
|
throw new SyntaxError(`Expected AbstractSqlQuery array but got ${typeof arg}`);
|
678
660
|
}
|
679
661
|
return MaybeAlias(arg, indent, SelectMatch);
|
@@ -681,21 +663,21 @@ const typeRules = {
|
|
681
663
|
.join(', ');
|
682
664
|
},
|
683
665
|
From: (args, indent) => {
|
684
|
-
|
685
|
-
return MaybeAlias(
|
666
|
+
checkArgs('From', args, 1);
|
667
|
+
return MaybeAlias(getAbstractSqlQuery(args, 0), indent, FromMatch);
|
686
668
|
},
|
687
669
|
Join: JoinMatch('Join'),
|
688
670
|
LeftJoin: JoinMatch('LeftJoin'),
|
689
671
|
RightJoin: JoinMatch('RightJoin'),
|
690
672
|
FullJoin: JoinMatch('FullJoin'),
|
691
673
|
CrossJoin: (args, indent) => {
|
692
|
-
|
693
|
-
const from = MaybeAlias(
|
674
|
+
checkArgs('CrossJoin', args, 1);
|
675
|
+
const from = MaybeAlias(getAbstractSqlQuery(args, 0), indent, FromMatch);
|
694
676
|
return `CROSS JOIN ${from}`;
|
695
677
|
},
|
696
678
|
Where: (args, indent) => {
|
697
|
-
|
698
|
-
const boolNode =
|
679
|
+
checkArgs('Where', args, 1);
|
680
|
+
const boolNode = getAbstractSqlQuery(args, 0);
|
699
681
|
if (boolNode[0] === 'Boolean') {
|
700
682
|
// This is designed to avoid cases of `WHERE 0`/`WHERE 1` which are invalid, ideally
|
701
683
|
// we need to convert booleans to always use true/false but that's a major change
|
@@ -705,61 +687,61 @@ const typeRules = {
|
|
705
687
|
return 'WHERE ' + ruleBody;
|
706
688
|
},
|
707
689
|
GroupBy: (args, indent) => {
|
708
|
-
|
709
|
-
const groups =
|
710
|
-
|
690
|
+
checkArgs('GroupBy', args, 1);
|
691
|
+
const groups = getAbstractSqlQuery(args, 0);
|
692
|
+
checkMinArgs('GroupBy groups', groups, 1);
|
711
693
|
return ('GROUP BY ' +
|
712
694
|
groups.map((arg) => AnyValue(arg, indent)).join(', '));
|
713
695
|
},
|
714
696
|
Having: (args, indent) => {
|
715
|
-
|
716
|
-
const havingBody = BooleanValue(
|
697
|
+
checkArgs('Having', args, 1);
|
698
|
+
const havingBody = BooleanValue(getAbstractSqlQuery(args, 0), indent);
|
717
699
|
return `HAVING ${havingBody}`;
|
718
700
|
},
|
719
701
|
OrderBy: (args, indent) => {
|
720
|
-
|
702
|
+
checkMinArgs('OrderBy', args, 1);
|
721
703
|
return ('ORDER BY ' +
|
722
704
|
args
|
723
705
|
.map((arg) => {
|
724
|
-
|
706
|
+
checkMinArgs('OrderBy ordering', arg, 2);
|
725
707
|
const order = arg[0];
|
726
708
|
if (order !== 'ASC' && order !== 'DESC') {
|
727
709
|
throw new SyntaxError(`Can only order by "ASC" or "DESC"`);
|
728
710
|
}
|
729
|
-
const value = AnyValue(
|
711
|
+
const value = AnyValue(getAbstractSqlQuery(arg, 1), indent);
|
730
712
|
return `${value} ${order}`;
|
731
713
|
})
|
732
714
|
.join(',' + NestedIndent(indent)));
|
733
715
|
},
|
734
716
|
Limit: (args, indent) => {
|
735
|
-
|
736
|
-
const num = NumericValue(
|
717
|
+
checkArgs('Limit', args, 1);
|
718
|
+
const num = NumericValue(getAbstractSqlQuery(args, 0), indent);
|
737
719
|
return `LIMIT ${num}`;
|
738
720
|
},
|
739
721
|
Offset: (args, indent) => {
|
740
|
-
|
741
|
-
const num = NumericValue(
|
722
|
+
checkArgs('Offset', args, 1);
|
723
|
+
const num = NumericValue(getAbstractSqlQuery(args, 0), indent);
|
742
724
|
return `OFFSET ${num}`;
|
743
725
|
},
|
744
726
|
Count: (args) => {
|
745
|
-
|
727
|
+
checkArgs('Count', args, 1);
|
746
728
|
if (args[0] !== '*') {
|
747
729
|
throw new SyntaxError('"Count" only supports "*"');
|
748
730
|
}
|
749
731
|
return 'COUNT(*)';
|
750
732
|
},
|
751
733
|
Average: (args, indent) => {
|
752
|
-
|
753
|
-
const num = NumericValue(
|
734
|
+
checkArgs('Average', args, 1);
|
735
|
+
const num = NumericValue(getAbstractSqlQuery(args, 0), indent);
|
754
736
|
return `AVG(${num})`;
|
755
737
|
},
|
756
738
|
Sum: (args, indent) => {
|
757
|
-
|
758
|
-
const num = NumericValue(
|
739
|
+
checkArgs('Sum', args, 1);
|
740
|
+
const num = NumericValue(getAbstractSqlQuery(args, 0), indent);
|
759
741
|
return `SUM(${num})`;
|
760
742
|
},
|
761
743
|
Field: (args) => {
|
762
|
-
|
744
|
+
checkArgs('Field', args, 1);
|
763
745
|
const [field] = args;
|
764
746
|
if (typeof field !== 'string') {
|
765
747
|
throw new SyntaxError('`Field` field must be a string');
|
@@ -767,7 +749,7 @@ const typeRules = {
|
|
767
749
|
return escapeField(field);
|
768
750
|
},
|
769
751
|
ReferencedField: (args) => {
|
770
|
-
|
752
|
+
checkArgs('ReferencedField', args, 2);
|
771
753
|
const [table, field] = args;
|
772
754
|
if (typeof table !== 'string') {
|
773
755
|
throw new SyntaxError('`ReferencedField` table must be a string');
|
@@ -778,14 +760,14 @@ const typeRules = {
|
|
778
760
|
return `"${table}".${escapeField(field)}`;
|
779
761
|
},
|
780
762
|
Cast: (args, indent) => {
|
781
|
-
|
782
|
-
const value = AnyValue(
|
763
|
+
checkArgs('Cast', args, 2);
|
764
|
+
const value = AnyValue(getAbstractSqlQuery(args, 0), indent);
|
783
765
|
const typeName = args[1];
|
784
|
-
if (!
|
766
|
+
if (!sbvrTypes[typeName]?.types[engine]) {
|
785
767
|
throw new SyntaxError(`Invalid cast type: ${typeName}`);
|
786
768
|
}
|
787
769
|
let type;
|
788
|
-
const dbType =
|
770
|
+
const dbType = sbvrTypes[typeName].types[engine];
|
789
771
|
if (typeof dbType === 'function') {
|
790
772
|
type = dbType.castType;
|
791
773
|
}
|
@@ -810,7 +792,7 @@ const typeRules = {
|
|
810
792
|
Integer: NumberMatch('Integer'),
|
811
793
|
// eslint-disable-next-line id-denylist
|
812
794
|
Boolean: (args) => {
|
813
|
-
|
795
|
+
checkArgs('Boolean', args, 1);
|
814
796
|
const b = args[0];
|
815
797
|
if (typeof b !== 'boolean') {
|
816
798
|
throw new SyntaxError(`Boolean expected boolean but got ${typeof b}`);
|
@@ -818,12 +800,12 @@ const typeRules = {
|
|
818
800
|
return b ? 'TRUE' : 'FALSE';
|
819
801
|
},
|
820
802
|
EmbeddedText: (args) => {
|
821
|
-
|
803
|
+
checkArgs('EmbeddedText', args, 1);
|
822
804
|
return `'${args[0]}'`;
|
823
805
|
},
|
824
806
|
TextArray: (args, indent) => {
|
825
807
|
const values = args.map((arg) => {
|
826
|
-
if (!
|
808
|
+
if (!isAbstractSqlQuery(arg)) {
|
827
809
|
throw new SyntaxError(`Expected AbstractSqlQuery array but got ${typeof arg}`);
|
828
810
|
}
|
829
811
|
return TextValue(arg, indent);
|
@@ -833,29 +815,29 @@ const typeRules = {
|
|
833
815
|
: 'CAST(ARRAY[] as TEXT[])';
|
834
816
|
},
|
835
817
|
Null: (args) => {
|
836
|
-
|
818
|
+
checkArgs('Null', args, 0);
|
837
819
|
return 'NULL';
|
838
820
|
},
|
839
821
|
CurrentTimestamp: (args) => {
|
840
|
-
|
822
|
+
checkArgs('CurrentTimestamp', args, 0);
|
841
823
|
return 'CURRENT_TIMESTAMP';
|
842
824
|
},
|
843
825
|
CurrentDate: (args) => {
|
844
|
-
|
826
|
+
checkArgs('CurrentDate', args, 0);
|
845
827
|
return 'CURRENT_DATE';
|
846
828
|
},
|
847
829
|
AggregateJSON: (args, indent) => {
|
848
|
-
|
830
|
+
checkArgs('AggregateJSON', args, 1);
|
849
831
|
if (engine !== "postgres" /* Engines.postgres */) {
|
850
832
|
throw new SyntaxError('AggregateJSON not supported on: ' + engine);
|
851
833
|
}
|
852
|
-
const field = Field(
|
834
|
+
const field = Field(getAbstractSqlQuery(args, 0), indent);
|
853
835
|
return `COALESCE(JSON_AGG(${field}), '[]')`;
|
854
836
|
},
|
855
837
|
Equals: Comparison('Equals'),
|
856
838
|
EqualsAny: (args, indent) => {
|
857
|
-
|
858
|
-
return `${AnyValue(
|
839
|
+
checkArgs('EqualsAny', args, 2);
|
840
|
+
return `${AnyValue(getAbstractSqlQuery(args, 0), indent)} = ANY(${AnyValue(getAbstractSqlQuery(args, 1), indent)})`;
|
859
841
|
},
|
860
842
|
GreaterThan: Comparison('GreaterThan'),
|
861
843
|
GreaterThanOrEqual: Comparison('GreaterThanOrEqual'),
|
@@ -864,18 +846,18 @@ const typeRules = {
|
|
864
846
|
NotEquals: Comparison('NotEquals'),
|
865
847
|
Like: Comparison('Like'),
|
866
848
|
IsNotDistinctFrom: (args, indent) => {
|
867
|
-
|
849
|
+
checkArgs('IsNotDistinctFrom', args, 2);
|
868
850
|
return isNotDistinctFrom(args, indent);
|
869
851
|
},
|
870
852
|
IsDistinctFrom: (args, indent) => {
|
871
|
-
|
853
|
+
checkArgs('IsDistinctFrom', args, 2);
|
872
854
|
return 'NOT(' + isNotDistinctFrom(args, indent) + ')';
|
873
855
|
},
|
874
856
|
Between: (args, indent) => {
|
875
|
-
|
876
|
-
const v = AnyValue(
|
877
|
-
const a = AnyValue(
|
878
|
-
const b = AnyValue(
|
857
|
+
checkArgs('Between', args, 3);
|
858
|
+
const v = AnyValue(getAbstractSqlQuery(args, 0), indent);
|
859
|
+
const a = AnyValue(getAbstractSqlQuery(args, 1), indent);
|
860
|
+
const b = AnyValue(getAbstractSqlQuery(args, 2), indent);
|
879
861
|
return `${v} BETWEEN ${a} AND (${b})`;
|
880
862
|
},
|
881
863
|
Add: MathOp('Add'),
|
@@ -897,8 +879,8 @@ const typeRules = {
|
|
897
879
|
Second: ExtractNumericDatePart('Second'),
|
898
880
|
Fractionalseconds: ExtractNumericDatePart('Fractionalseconds'),
|
899
881
|
Totalseconds: (args, indent) => {
|
900
|
-
|
901
|
-
const duration = DurationValue(
|
882
|
+
checkArgs('Totalseconds', args, 1);
|
883
|
+
const duration = DurationValue(getAbstractSqlQuery(args, 0), indent);
|
902
884
|
if (engine === "postgres" /* Engines.postgres */) {
|
903
885
|
return `EXTRACT(EPOCH FROM ${duration})`;
|
904
886
|
}
|
@@ -910,9 +892,9 @@ const typeRules = {
|
|
910
892
|
}
|
911
893
|
},
|
912
894
|
Concatenate: (args, indent) => {
|
913
|
-
|
895
|
+
checkMinArgs('Concatenate', args, 1);
|
914
896
|
const comparators = args.map((arg) => {
|
915
|
-
if (!
|
897
|
+
if (!isAbstractSqlQuery(arg)) {
|
916
898
|
throw new SyntaxError(`Expected AbstractSqlQuery array but got ${typeof arg}`);
|
917
899
|
}
|
918
900
|
return TextValue(arg, indent);
|
@@ -925,9 +907,9 @@ const typeRules = {
|
|
925
907
|
}
|
926
908
|
},
|
927
909
|
ConcatenateWithSeparator: (args, indent) => {
|
928
|
-
|
910
|
+
checkMinArgs('ConcatenateWithSeparator', args, 2);
|
929
911
|
const textParts = args.map((arg) => {
|
930
|
-
if (!
|
912
|
+
if (!isAbstractSqlQuery(arg)) {
|
931
913
|
throw new SyntaxError(`Expected AbstractSqlQuery array but got ${typeof arg}`);
|
932
914
|
}
|
933
915
|
return TextValue(arg, indent);
|
@@ -938,24 +920,24 @@ const typeRules = {
|
|
938
920
|
return `CONCAT_WS(${textParts.join(', ')})`;
|
939
921
|
},
|
940
922
|
Replace: (args, indent) => {
|
941
|
-
|
942
|
-
const str = TextValue(
|
943
|
-
const find = TextValue(
|
944
|
-
const replacement = TextValue(
|
923
|
+
checkArgs('Replace', args, 3);
|
924
|
+
const str = TextValue(getAbstractSqlQuery(args, 0), indent);
|
925
|
+
const find = TextValue(getAbstractSqlQuery(args, 1), indent);
|
926
|
+
const replacement = TextValue(getAbstractSqlQuery(args, 2), indent);
|
945
927
|
return `REPLACE(${str}, ${find}, ${replacement})`;
|
946
928
|
},
|
947
929
|
ExtractJSONPathAsText: (args, indent) => {
|
948
|
-
|
930
|
+
checkMinArgs('ExtractJSONPathAsText', args, 1);
|
949
931
|
if (engine !== "postgres" /* Engines.postgres */) {
|
950
932
|
throw new SyntaxError('ExtractJSONPathAsText not supported on: ' + engine);
|
951
933
|
}
|
952
|
-
const json = JSONValue(
|
953
|
-
const path = TextValue(
|
934
|
+
const json = JSONValue(getAbstractSqlQuery(args, 0), indent);
|
935
|
+
const path = TextValue(getAbstractSqlQuery(args, 1), indent);
|
954
936
|
return `${json} #>> ${path}`;
|
955
937
|
},
|
956
938
|
CharacterLength: (args, indent) => {
|
957
|
-
|
958
|
-
const text = TextValue(
|
939
|
+
checkArgs('CharacterLength', args, 1);
|
940
|
+
const text = TextValue(getAbstractSqlQuery(args, 0), indent);
|
959
941
|
if (engine === "mysql" /* Engines.mysql */) {
|
960
942
|
return `CHAR_LENGTH(${text})`;
|
961
943
|
}
|
@@ -964,9 +946,9 @@ const typeRules = {
|
|
964
946
|
}
|
965
947
|
},
|
966
948
|
StrPos: (args, indent) => {
|
967
|
-
|
968
|
-
const haystack = TextValue(
|
969
|
-
const needle = TextValue(
|
949
|
+
checkArgs('StrPos', args, 2);
|
950
|
+
const haystack = TextValue(getAbstractSqlQuery(args, 0), indent);
|
951
|
+
const needle = TextValue(getAbstractSqlQuery(args, 1), indent);
|
970
952
|
if (engine === "postgres" /* Engines.postgres */) {
|
971
953
|
return `STRPOS(${haystack}, ${needle})`;
|
972
954
|
}
|
@@ -975,9 +957,9 @@ const typeRules = {
|
|
975
957
|
}
|
976
958
|
},
|
977
959
|
StartsWith: (args, indent) => {
|
978
|
-
|
979
|
-
const haystack = TextValue(
|
980
|
-
const needle = TextValue(
|
960
|
+
checkArgs('StartsWith', args, 2);
|
961
|
+
const haystack = TextValue(getAbstractSqlQuery(args, 0), indent);
|
962
|
+
const needle = TextValue(getAbstractSqlQuery(args, 1), indent);
|
981
963
|
if (engine === "postgres" /* Engines.postgres */) {
|
982
964
|
return `STARTS_WITH(${haystack}, ${needle})`;
|
983
965
|
}
|
@@ -989,10 +971,10 @@ const typeRules = {
|
|
989
971
|
}
|
990
972
|
},
|
991
973
|
Substring: (args, indent) => {
|
992
|
-
|
993
|
-
const str = TextValue(
|
974
|
+
checkMinArgs('Substring', args, 2);
|
975
|
+
const str = TextValue(getAbstractSqlQuery(args, 0), indent);
|
994
976
|
const nums = args.slice(1).map((arg) => {
|
995
|
-
if (!
|
977
|
+
if (!isAbstractSqlQuery(arg)) {
|
996
978
|
throw new SyntaxError(`Expected AbstractSqlQuery array but got ${typeof arg}`);
|
997
979
|
}
|
998
980
|
return NumericValue(arg, indent);
|
@@ -1000,9 +982,9 @@ const typeRules = {
|
|
1000
982
|
return `SUBSTRING(${[str, ...nums].join(', ')})`;
|
1001
983
|
},
|
1002
984
|
Right: (args, indent) => {
|
1003
|
-
|
1004
|
-
const str = TextValue(
|
1005
|
-
const n = NumericValue(
|
985
|
+
checkArgs('Right', args, 2);
|
986
|
+
const str = TextValue(getAbstractSqlQuery(args, 0), indent);
|
987
|
+
const n = NumericValue(getAbstractSqlQuery(args, 1), indent);
|
1006
988
|
if (engine === "websql" /* Engines.websql */) {
|
1007
989
|
return `SUBSTRING(${str}, -${n})`;
|
1008
990
|
}
|
@@ -1011,51 +993,51 @@ const typeRules = {
|
|
1011
993
|
}
|
1012
994
|
},
|
1013
995
|
Lower: (args, indent) => {
|
1014
|
-
|
1015
|
-
const str = TextValue(
|
996
|
+
checkArgs('Lower', args, 1);
|
997
|
+
const str = TextValue(getAbstractSqlQuery(args, 0), indent);
|
1016
998
|
return `LOWER(${str})`;
|
1017
999
|
},
|
1018
1000
|
Upper: (args, indent) => {
|
1019
|
-
|
1020
|
-
const str = TextValue(
|
1001
|
+
checkArgs('Upper', args, 1);
|
1002
|
+
const str = TextValue(getAbstractSqlQuery(args, 0), indent);
|
1021
1003
|
return `UPPER(${str})`;
|
1022
1004
|
},
|
1023
1005
|
Trim: (args, indent) => {
|
1024
|
-
|
1025
|
-
const str = TextValue(
|
1006
|
+
checkArgs('Trim', args, 1);
|
1007
|
+
const str = TextValue(getAbstractSqlQuery(args, 0), indent);
|
1026
1008
|
return `TRIM(${str})`;
|
1027
1009
|
},
|
1028
1010
|
Round: (args, indent) => {
|
1029
|
-
|
1030
|
-
const num = NumericValue(
|
1011
|
+
checkArgs('Round', args, 1);
|
1012
|
+
const num = NumericValue(getAbstractSqlQuery(args, 0), indent);
|
1031
1013
|
return `ROUND(${num})`;
|
1032
1014
|
},
|
1033
1015
|
Floor: (args, indent) => {
|
1034
|
-
|
1035
|
-
const num = NumericValue(
|
1016
|
+
checkArgs('Floor', args, 1);
|
1017
|
+
const num = NumericValue(getAbstractSqlQuery(args, 0), indent);
|
1036
1018
|
return `FLOOR(${num})`;
|
1037
1019
|
},
|
1038
1020
|
Ceiling: (args, indent) => {
|
1039
|
-
|
1040
|
-
const num = NumericValue(
|
1021
|
+
checkArgs('Ceiling', args, 1);
|
1022
|
+
const num = NumericValue(getAbstractSqlQuery(args, 0), indent);
|
1041
1023
|
return `CEILING(${num})`;
|
1042
1024
|
},
|
1043
1025
|
ToDate: (args, indent) => {
|
1044
|
-
|
1045
|
-
const date = DateValue(
|
1026
|
+
checkArgs('ToDate', args, 1);
|
1027
|
+
const date = DateValue(getAbstractSqlQuery(args, 0), indent);
|
1046
1028
|
return `DATE(${date})`;
|
1047
1029
|
},
|
1048
1030
|
DateTrunc: (args, indent) => {
|
1049
|
-
|
1050
|
-
const precision = TextValue(
|
1051
|
-
const date = DateValue(
|
1031
|
+
checkMinArgs('DateTrunc', args, 2);
|
1032
|
+
const precision = TextValue(getAbstractSqlQuery(args, 0), indent);
|
1033
|
+
const date = DateValue(getAbstractSqlQuery(args, 1), indent);
|
1052
1034
|
// Postgres generated timestamps have a microseconds precision
|
1053
1035
|
// these timestamps will fail on comparisons: eq, ne, gt, lt with
|
1054
1036
|
// js timestamps that have only milliseconds precision
|
1055
1037
|
// thus supporting for truncating to a given precision
|
1056
1038
|
if (engine === "postgres" /* Engines.postgres */) {
|
1057
1039
|
const timeZone = args.length === 3
|
1058
|
-
? TextValue(
|
1040
|
+
? TextValue(getAbstractSqlQuery(args, 2), indent)
|
1059
1041
|
: undefined;
|
1060
1042
|
return timeZone
|
1061
1043
|
? `DATE_TRUNC(${precision}, ${date}, ${timeZone})`
|
@@ -1073,8 +1055,8 @@ const typeRules = {
|
|
1073
1055
|
}
|
1074
1056
|
},
|
1075
1057
|
ToTime: (args, indent) => {
|
1076
|
-
|
1077
|
-
const date = DateValue(
|
1058
|
+
checkArgs('ToTime', args, 1);
|
1059
|
+
const date = DateValue(getAbstractSqlQuery(args, 0), indent);
|
1078
1060
|
if (engine === "postgres" /* Engines.postgres */) {
|
1079
1061
|
return `CAST(${date} AS TIME)`;
|
1080
1062
|
}
|
@@ -1083,26 +1065,26 @@ const typeRules = {
|
|
1083
1065
|
}
|
1084
1066
|
},
|
1085
1067
|
ToJSON: (args, indent) => {
|
1086
|
-
|
1068
|
+
checkMinArgs('ToJSON', args, 1);
|
1087
1069
|
if (engine !== "postgres" /* Engines.postgres */) {
|
1088
1070
|
throw new SyntaxError('ToJSON not supported on: ' + engine);
|
1089
1071
|
}
|
1090
|
-
const value = AnyValue(
|
1072
|
+
const value = AnyValue(getAbstractSqlQuery(args, 0), indent);
|
1091
1073
|
return `TO_JSON(${value})`;
|
1092
1074
|
},
|
1093
1075
|
Any: (args, indent) => {
|
1094
|
-
|
1076
|
+
checkArgs('Any', args, 2);
|
1095
1077
|
if (engine !== "postgres" /* Engines.postgres */) {
|
1096
1078
|
throw new SyntaxError('Any not supported on: ' + engine);
|
1097
1079
|
}
|
1098
|
-
const value = AnyValue(
|
1099
|
-
const innerType =
|
1080
|
+
const value = AnyValue(getAbstractSqlQuery(args, 0), indent);
|
1081
|
+
const innerType = sbvrTypes[args[1]].types[engine];
|
1100
1082
|
return `ANY(CAST(${value} AS ${innerType}[]))`;
|
1101
1083
|
},
|
1102
1084
|
Coalesce: (args, indent) => {
|
1103
|
-
|
1085
|
+
checkMinArgs('Coalesce', args, 2);
|
1104
1086
|
const comparators = args.map((arg) => {
|
1105
|
-
if (!
|
1087
|
+
if (!isAbstractSqlQuery(arg)) {
|
1106
1088
|
throw new SyntaxError(`Expected AbstractSqlQuery array but got ${typeof arg}`);
|
1107
1089
|
}
|
1108
1090
|
return AnyValue(arg, indent);
|
@@ -1110,27 +1092,27 @@ const typeRules = {
|
|
1110
1092
|
return 'COALESCE(' + comparators.join(', ') + ')';
|
1111
1093
|
},
|
1112
1094
|
Case: (args, indent) => {
|
1113
|
-
|
1095
|
+
checkMinArgs('Case', args, 1);
|
1114
1096
|
const nestedIndent = NestedIndent(indent);
|
1115
1097
|
const clauses = args
|
1116
1098
|
.map((arg, index) => {
|
1117
|
-
if (!
|
1099
|
+
if (!isAbstractSqlQuery(arg)) {
|
1118
1100
|
throw new SyntaxError(`Expected AbstractSqlQuery array but got ${typeof arg}`);
|
1119
1101
|
}
|
1120
1102
|
const [type, ...rest] = arg;
|
1121
1103
|
switch (type) {
|
1122
1104
|
case 'When': {
|
1123
|
-
|
1124
|
-
const matches = BooleanValue(
|
1125
|
-
const resultValue = AnyValue(
|
1105
|
+
checkArgs('When', rest, 2);
|
1106
|
+
const matches = BooleanValue(getAbstractSqlQuery(rest, 0), NestedIndent(nestedIndent));
|
1107
|
+
const resultValue = AnyValue(getAbstractSqlQuery(rest, 1), nestedIndent);
|
1126
1108
|
return 'WHEN ' + matches + ' THEN ' + resultValue;
|
1127
1109
|
}
|
1128
1110
|
case 'Else':
|
1129
1111
|
if (index !== args.length - 1) {
|
1130
1112
|
throw new SyntaxError('Else must be the last element of a Case');
|
1131
1113
|
}
|
1132
|
-
|
1133
|
-
return ('ELSE ' + AnyValue(
|
1114
|
+
checkArgs('Else', rest, 1);
|
1115
|
+
return ('ELSE ' + AnyValue(getAbstractSqlQuery(rest, 0), nestedIndent));
|
1134
1116
|
default:
|
1135
1117
|
throw new SyntaxError('Case can only contain When/Else');
|
1136
1118
|
}
|
@@ -1139,10 +1121,10 @@ const typeRules = {
|
|
1139
1121
|
return 'CASE' + nestedIndent + clauses + indent + 'END';
|
1140
1122
|
},
|
1141
1123
|
And: (args, indent) => {
|
1142
|
-
|
1124
|
+
checkMinArgs('And', args, 2);
|
1143
1125
|
return args
|
1144
1126
|
.map((arg) => {
|
1145
|
-
if (!
|
1127
|
+
if (!isAbstractSqlQuery(arg)) {
|
1146
1128
|
throw new SyntaxError(`Expected AbstractSqlQuery array but got ${typeof arg}`);
|
1147
1129
|
}
|
1148
1130
|
return BooleanValue(arg, indent);
|
@@ -1150,11 +1132,11 @@ const typeRules = {
|
|
1150
1132
|
.join(indent + 'AND ');
|
1151
1133
|
},
|
1152
1134
|
Or: (args, indent) => {
|
1153
|
-
|
1135
|
+
checkMinArgs('Or', args, 2);
|
1154
1136
|
return ('(' +
|
1155
1137
|
args
|
1156
1138
|
.map((arg) => {
|
1157
|
-
if (!
|
1139
|
+
if (!isAbstractSqlQuery(arg)) {
|
1158
1140
|
throw new SyntaxError(`Expected AbstractSqlQuery array but got ${typeof arg}`);
|
1159
1141
|
}
|
1160
1142
|
return BooleanValue(arg, indent);
|
@@ -1163,17 +1145,17 @@ const typeRules = {
|
|
1163
1145
|
')');
|
1164
1146
|
},
|
1165
1147
|
Bind: (args) => {
|
1166
|
-
|
1148
|
+
checkArgs('Bind', args, 1);
|
1167
1149
|
const bind = args[0];
|
1168
1150
|
return AddBind(['Bind', bind]);
|
1169
1151
|
},
|
1170
1152
|
Text,
|
1171
1153
|
Date: (args) => {
|
1172
|
-
|
1154
|
+
checkArgs('Date', args, 1);
|
1173
1155
|
return AddBind(['Date', args[0]]);
|
1174
1156
|
},
|
1175
1157
|
Duration: (args) => {
|
1176
|
-
|
1158
|
+
checkArgs('Duration', args, 1);
|
1177
1159
|
if (engine === "websql" /* Engines.websql */) {
|
1178
1160
|
throw new SyntaxError('Durations not supported on: ' + engine);
|
1179
1161
|
}
|
@@ -1203,8 +1185,8 @@ const typeRules = {
|
|
1203
1185
|
(engine === "mysql" /* Engines.mysql */ ? ' DAY_MICROSECOND' : ''));
|
1204
1186
|
},
|
1205
1187
|
Exists: (args, indent) => {
|
1206
|
-
|
1207
|
-
const arg =
|
1188
|
+
checkArgs('Exists', args, 1);
|
1189
|
+
const arg = getAbstractSqlQuery(args, 0);
|
1208
1190
|
const [type, ...rest] = arg;
|
1209
1191
|
switch (type) {
|
1210
1192
|
case 'SelectQuery':
|
@@ -1218,8 +1200,8 @@ const typeRules = {
|
|
1218
1200
|
}
|
1219
1201
|
},
|
1220
1202
|
NotExists: (args, indent) => {
|
1221
|
-
|
1222
|
-
const arg =
|
1203
|
+
checkArgs('NotExists', args, 1);
|
1204
|
+
const arg = getAbstractSqlQuery(args, 0);
|
1223
1205
|
const [type, ...rest] = arg;
|
1224
1206
|
switch (type) {
|
1225
1207
|
case 'SelectQuery':
|
@@ -1233,16 +1215,16 @@ const typeRules = {
|
|
1233
1215
|
}
|
1234
1216
|
},
|
1235
1217
|
Not: (args, indent) => {
|
1236
|
-
|
1218
|
+
checkArgs('Not', args, 1);
|
1237
1219
|
const nestedIndent = NestedIndent(indent);
|
1238
|
-
const bool = BooleanValue(
|
1220
|
+
const bool = BooleanValue(getAbstractSqlQuery(args, 0), nestedIndent);
|
1239
1221
|
return 'NOT (' + nestedIndent + bool + indent + ')';
|
1240
1222
|
},
|
1241
1223
|
In: (args, indent) => {
|
1242
|
-
|
1243
|
-
const field = Field(
|
1224
|
+
checkMinArgs('In', args, 2);
|
1225
|
+
const field = Field(getAbstractSqlQuery(args, 0), indent);
|
1244
1226
|
const vals = args.slice(1).map((arg) => {
|
1245
|
-
if (!
|
1227
|
+
if (!isAbstractSqlQuery(arg)) {
|
1246
1228
|
throw new SyntaxError(`Expected AbstractSqlQuery array but got ${typeof arg}`);
|
1247
1229
|
}
|
1248
1230
|
return AnyValue(arg, indent);
|
@@ -1250,10 +1232,10 @@ const typeRules = {
|
|
1250
1232
|
return field + ' IN (' + vals.join(', ') + ')';
|
1251
1233
|
},
|
1252
1234
|
NotIn: (args, indent) => {
|
1253
|
-
|
1254
|
-
const field = Field(
|
1235
|
+
checkMinArgs('NotIn', args, 2);
|
1236
|
+
const field = Field(getAbstractSqlQuery(args, 0), indent);
|
1255
1237
|
const vals = args.slice(1).map((arg) => {
|
1256
|
-
if (!
|
1238
|
+
if (!isAbstractSqlQuery(arg)) {
|
1257
1239
|
throw new SyntaxError(`Expected AbstractSqlQuery array but got ${typeof arg}`);
|
1258
1240
|
}
|
1259
1241
|
return AnyValue(arg, indent);
|
@@ -1265,7 +1247,7 @@ const typeRules = {
|
|
1265
1247
|
let fields = [];
|
1266
1248
|
let values = [];
|
1267
1249
|
for (const arg of args) {
|
1268
|
-
if (!
|
1250
|
+
if (!isAbstractSqlQuery(arg)) {
|
1269
1251
|
throw new SyntaxError('`InsertQuery` args must all be arrays');
|
1270
1252
|
}
|
1271
1253
|
const [type, ...rest] = arg;
|
@@ -1274,14 +1256,14 @@ const typeRules = {
|
|
1274
1256
|
if (fields.length !== 0) {
|
1275
1257
|
throw new SyntaxError(`'InsertQuery' can only accept one '${type}'`);
|
1276
1258
|
}
|
1277
|
-
|
1278
|
-
fields =
|
1259
|
+
checkMinArgs('Update fields', rest, 1);
|
1260
|
+
fields = getAbstractSqlQuery(rest, 0).map(escapeField);
|
1279
1261
|
break;
|
1280
1262
|
case 'Values': {
|
1281
1263
|
if (values.length !== 0) {
|
1282
1264
|
throw new SyntaxError(`'InsertQuery' can only accept one '${type}'`);
|
1283
1265
|
}
|
1284
|
-
const valuesArray =
|
1266
|
+
const valuesArray = getAbstractSqlQuery(rest, 0);
|
1285
1267
|
if (valuesArray.length > 0) {
|
1286
1268
|
const [valuesType, ...valuesRest] = valuesArray;
|
1287
1269
|
switch (valuesType) {
|
@@ -1327,7 +1309,7 @@ const typeRules = {
|
|
1327
1309
|
let values = [];
|
1328
1310
|
let where = '';
|
1329
1311
|
for (const arg of args) {
|
1330
|
-
if (!
|
1312
|
+
if (!isAbstractSqlQuery(arg)) {
|
1331
1313
|
throw new SyntaxError('`UpdateQuery` args must all be arrays');
|
1332
1314
|
}
|
1333
1315
|
const [type, ...rest] = arg;
|
@@ -1336,16 +1318,16 @@ const typeRules = {
|
|
1336
1318
|
if (fields.length !== 0) {
|
1337
1319
|
throw new SyntaxError(`'UpdateQuery' can only accept one '${type}'`);
|
1338
1320
|
}
|
1339
|
-
|
1340
|
-
fields =
|
1321
|
+
checkMinArgs('Update fields', rest, 1);
|
1322
|
+
fields = getAbstractSqlQuery(rest, 0).map(escapeField);
|
1341
1323
|
break;
|
1342
1324
|
case 'Values': {
|
1343
1325
|
if (values.length !== 0) {
|
1344
1326
|
throw new SyntaxError(`'UpdateQuery' can only accept one '${type}'`);
|
1345
1327
|
}
|
1346
|
-
|
1347
|
-
const valuesArray =
|
1348
|
-
|
1328
|
+
checkArgs('Update values', rest, 1);
|
1329
|
+
const valuesArray = getAbstractSqlQuery(rest, 0);
|
1330
|
+
checkMinArgs('Update values array', valuesArray, 1);
|
1349
1331
|
values = valuesArray.map((v) => Value(v, indent));
|
1350
1332
|
break;
|
1351
1333
|
}
|
@@ -1377,7 +1359,7 @@ const typeRules = {
|
|
1377
1359
|
const tables = [];
|
1378
1360
|
let where = '';
|
1379
1361
|
for (const arg of args) {
|
1380
|
-
if (!
|
1362
|
+
if (!isAbstractSqlQuery(arg)) {
|
1381
1363
|
throw new SyntaxError('`DeleteQuery` args must all be arrays');
|
1382
1364
|
}
|
1383
1365
|
const [type, ...rest] = arg;
|
@@ -1398,8 +1380,8 @@ const typeRules = {
|
|
1398
1380
|
return 'DELETE FROM ' + tables.join(', ') + where;
|
1399
1381
|
},
|
1400
1382
|
EscapeForLike: (args, indent) => {
|
1401
|
-
|
1402
|
-
const textTypeNode =
|
1383
|
+
checkArgs('EscapeForLike', args, 1);
|
1384
|
+
const textTypeNode = getAbstractSqlQuery(args, 0);
|
1403
1385
|
return typeRules.Replace([
|
1404
1386
|
[
|
1405
1387
|
'Replace',
|
@@ -1426,7 +1408,7 @@ const toSqlResult = (query) => {
|
|
1426
1408
|
bindings: fieldOrderings,
|
1427
1409
|
};
|
1428
1410
|
};
|
1429
|
-
function AbstractSQLRules2SQL(abstractSQL, $engine, $noBinds = false) {
|
1411
|
+
export function AbstractSQLRules2SQL(abstractSQL, $engine, $noBinds = false) {
|
1430
1412
|
engine = $engine;
|
1431
1413
|
noBinds = $noBinds;
|
1432
1414
|
fieldOrderings = [];
|
@@ -1443,9 +1425,9 @@ function AbstractSQLRules2SQL(abstractSQL, $engine, $noBinds = false) {
|
|
1443
1425
|
return toSqlResult(query);
|
1444
1426
|
}
|
1445
1427
|
case 'UpsertQuery': {
|
1446
|
-
|
1447
|
-
const insertQuery =
|
1448
|
-
const updateQuery =
|
1428
|
+
checkArgs('UpsertQuery', rest, 2);
|
1429
|
+
const insertQuery = getAbstractSqlQuery(rest, 0);
|
1430
|
+
const updateQuery = getAbstractSqlQuery(rest, 1);
|
1449
1431
|
if (insertQuery[0] !== 'InsertQuery' ||
|
1450
1432
|
updateQuery[0] !== 'UpdateQuery') {
|
1451
1433
|
throw new SyntaxError('UpsertQuery must have [InsertQuery, UpdateQuery] provided');
|