@balena/abstract-sql-compiler 10.2.8-build-lodash-08b051cf4150dfa99f3cfafeb3011244760e9d38-1 → 10.2.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.
- package/.versionbot/CHANGELOG.yml +1 -65
- package/CHANGELOG.md +0 -8
- package/out/AbstractSQLCompiler.d.ts +7 -6
- package/out/AbstractSQLCompiler.js +2 -7
- package/out/AbstractSQLCompiler.js.map +1 -1
- package/out/AbstractSQLOptimiser.js +23 -17
- package/out/AbstractSQLOptimiser.js.map +1 -1
- package/out/AbstractSQLRules2SQL.js +13 -9
- package/out/AbstractSQLRules2SQL.js.map +1 -1
- package/out/AbstractSQLSchemaOptimiser.js +3 -3
- package/out/AbstractSQLSchemaOptimiser.js.map +1 -1
- package/out/referenced-fields.js +10 -10
- package/out/referenced-fields.js.map +1 -1
- package/package.json +5 -3
- package/src/AbstractSQLCompiler.ts +14 -24
- package/src/AbstractSQLOptimiser.ts +24 -20
- package/src/AbstractSQLRules2SQL.ts +18 -11
- package/src/AbstractSQLSchemaOptimiser.ts +4 -3
- package/src/referenced-fields.ts +7 -10
@@ -1,3 +1,6 @@
|
|
1
|
+
import _ from 'lodash';
|
2
|
+
|
3
|
+
import type { Dictionary } from 'lodash';
|
1
4
|
import type {
|
2
5
|
AbstractSqlQuery,
|
3
6
|
AbstractSqlType,
|
@@ -123,8 +126,6 @@ type OptimisationMatchFn<T extends AnyTypeNodes> =
|
|
123
126
|
type MetaMatchFn<T extends AnyTypeNodes> = (args: AbstractSqlQuery) => T;
|
124
127
|
type MatchFn<T extends AnyTypeNodes> = (args: AbstractSqlType[]) => T;
|
125
128
|
|
126
|
-
const identity = <T>(x: T): T => x;
|
127
|
-
|
128
129
|
let helped = false;
|
129
130
|
let noBinds = false;
|
130
131
|
const Helper = <F extends (...args: any[]) => any>(fn: F) => {
|
@@ -419,7 +420,7 @@ const ConcatenateWithSeparator: MatchFn<ConcatenateWithSeparatorNode> = (
|
|
419
420
|
];
|
420
421
|
};
|
421
422
|
|
422
|
-
const Text = matchArgs<TextNode>('Text', identity);
|
423
|
+
const Text = matchArgs<TextNode>('Text', _.identity);
|
423
424
|
|
424
425
|
const Value = (arg: string | AbstractSqlQuery): ValuesNodeTypes => {
|
425
426
|
switch (arg) {
|
@@ -706,20 +707,20 @@ const typeRules = {
|
|
706
707
|
},
|
707
708
|
Average: matchArgs('Average', NumericValue),
|
708
709
|
Sum: matchArgs('Sum', NumericValue),
|
709
|
-
Field: matchArgs<FieldNode>('Field', identity),
|
710
|
+
Field: matchArgs<FieldNode>('Field', _.identity),
|
710
711
|
ReferencedField: matchArgs<ReferencedFieldNode>(
|
711
712
|
'ReferencedField',
|
712
|
-
identity,
|
713
|
-
identity,
|
713
|
+
_.identity,
|
714
|
+
_.identity,
|
714
715
|
),
|
715
|
-
Cast: matchArgs<CastNode>('Cast', AnyValue, identity),
|
716
|
+
Cast: matchArgs<CastNode>('Cast', AnyValue, _.identity),
|
716
717
|
// eslint-disable-next-line id-denylist
|
717
718
|
Number: NumberMatch('Number'),
|
718
719
|
Real: NumberMatch('Real'),
|
719
720
|
Integer: NumberMatch('Integer'),
|
720
721
|
// eslint-disable-next-line id-denylist
|
721
|
-
Boolean: matchArgs<BooleanNode>('Boolean', identity),
|
722
|
-
EmbeddedText: matchArgs('EmbeddedText', identity),
|
722
|
+
Boolean: matchArgs<BooleanNode>('Boolean', _.identity),
|
723
|
+
EmbeddedText: matchArgs('EmbeddedText', _.identity),
|
723
724
|
Null: matchArgs<NullNode>('Null'),
|
724
725
|
CurrentTimestamp: matchArgs<CurrentTimestampNode>('CurrentTimestamp'),
|
725
726
|
CurrentDate: matchArgs<CurrentDateNode>('CurrentDate'),
|
@@ -902,7 +903,7 @@ const typeRules = {
|
|
902
903
|
return ['TextArray', ...args.map(TextValue)];
|
903
904
|
},
|
904
905
|
ToJSON: matchArgs<ToJSONNode>('ToJSON', AnyValue),
|
905
|
-
Any: matchArgs<AnyNode>('Any', AnyValue, identity),
|
906
|
+
Any: matchArgs<AnyNode>('Any', AnyValue, _.identity),
|
906
907
|
Coalesce: (args): CoalesceNode => {
|
907
908
|
checkMinArgs('Coalesce', args, 2);
|
908
909
|
return [
|
@@ -955,7 +956,7 @@ const typeRules = {
|
|
955
956
|
checkMinArgs('And', args, 2);
|
956
957
|
// Collapse nested ANDs.
|
957
958
|
let maybeHelped = false;
|
958
|
-
const conditions =
|
959
|
+
const conditions = _.flatMap(args, (arg) => {
|
959
960
|
if (!isAbstractSqlQuery(arg)) {
|
960
961
|
throw new SyntaxError(
|
961
962
|
`Expected AbstractSqlQuery array but got ${typeof arg}`,
|
@@ -1058,7 +1059,7 @@ const typeRules = {
|
|
1058
1059
|
return [
|
1059
1060
|
'NotIn',
|
1060
1061
|
fieldBucket[0][1],
|
1061
|
-
...
|
1062
|
+
..._.flatMap(fieldBucket, (field) => field.slice(2)),
|
1062
1063
|
];
|
1063
1064
|
}
|
1064
1065
|
});
|
@@ -1090,7 +1091,7 @@ const typeRules = {
|
|
1090
1091
|
checkMinArgs('Or', args, 2);
|
1091
1092
|
// Collapse nested ORs.
|
1092
1093
|
let maybeHelped = false;
|
1093
|
-
const conditions =
|
1094
|
+
const conditions = _.flatMap(args, (arg) => {
|
1094
1095
|
if (!isAbstractSqlQuery(arg)) {
|
1095
1096
|
throw new SyntaxError(
|
1096
1097
|
`Expected AbstractSqlQuery array but got ${typeof arg}`,
|
@@ -1193,7 +1194,7 @@ const typeRules = {
|
|
1193
1194
|
return [
|
1194
1195
|
'In',
|
1195
1196
|
fieldBucket[0][1],
|
1196
|
-
...
|
1197
|
+
..._.flatMap(fieldBucket, (field) => field.slice(2)),
|
1197
1198
|
];
|
1198
1199
|
}
|
1199
1200
|
});
|
@@ -1231,21 +1232,24 @@ const typeRules = {
|
|
1231
1232
|
),
|
1232
1233
|
Text,
|
1233
1234
|
Value: Text,
|
1234
|
-
Date: matchArgs('Date', identity),
|
1235
|
+
Date: matchArgs('Date', _.identity),
|
1235
1236
|
Duration: (args): DurationNode => {
|
1236
1237
|
checkArgs('Duration', args, 1);
|
1237
1238
|
|
1238
|
-
|
1239
|
+
let duration = args[0] as DurationNode[1];
|
1239
1240
|
if (duration == null || typeof duration !== 'object') {
|
1240
1241
|
throw new SyntaxError(
|
1241
1242
|
`Duration must be an object, got ${typeof duration}`,
|
1242
1243
|
);
|
1243
1244
|
}
|
1244
|
-
|
1245
|
-
|
1245
|
+
duration = _(duration)
|
1246
|
+
.pick('negative', 'day', 'hour', 'minute', 'second')
|
1247
|
+
.omitBy(_.isNil)
|
1248
|
+
.value();
|
1249
|
+
if (_(duration).omit('negative').isEmpty()) {
|
1246
1250
|
throw new SyntaxError('Invalid duration');
|
1247
1251
|
}
|
1248
|
-
return ['Duration',
|
1252
|
+
return ['Duration', duration];
|
1249
1253
|
},
|
1250
1254
|
Exists: tryMatches<ExistsNode | BooleanNode>(
|
1251
1255
|
Helper<OptimisationMatchFn<BooleanNode>>((args) => {
|
@@ -1598,7 +1602,7 @@ const typeRules = {
|
|
1598
1602
|
],
|
1599
1603
|
),
|
1600
1604
|
),
|
1601
|
-
} satisfies
|
1605
|
+
} satisfies Dictionary<MatchFn<AnyTypeNodes>>;
|
1602
1606
|
|
1603
1607
|
export const AbstractSQLOptimiser = (
|
1604
1608
|
abstractSQL: AbstractSqlQuery,
|
@@ -1,4 +1,8 @@
|
|
1
|
+
import _ from 'lodash';
|
2
|
+
|
1
3
|
import sbvrTypes from '@balena/sbvr-types';
|
4
|
+
|
5
|
+
import type { Dictionary } from 'lodash';
|
2
6
|
import type {
|
3
7
|
AbstractSqlQuery,
|
4
8
|
AbstractSqlType,
|
@@ -32,7 +36,7 @@ type MetaMatchFn = (args: AbstractSqlQuery, indent: string) => string;
|
|
32
36
|
type MatchFn = (args: AbstractSqlType[], indent: string) => string;
|
33
37
|
|
34
38
|
let fieldOrderings: Binding[] = [];
|
35
|
-
let fieldOrderingsLookup:
|
39
|
+
let fieldOrderingsLookup: Dictionary<number> = {};
|
36
40
|
let engine: Engines = Engines.postgres;
|
37
41
|
let noBinds = false;
|
38
42
|
|
@@ -698,7 +702,7 @@ const AddBind = (bind: Binding): string => {
|
|
698
702
|
}
|
699
703
|
};
|
700
704
|
|
701
|
-
const typeRules:
|
705
|
+
const typeRules: Dictionary<MatchFn> = {
|
702
706
|
UnionQuery: (args, indent) => {
|
703
707
|
checkMinArgs('UnionQuery', args, 2);
|
704
708
|
return args
|
@@ -1336,28 +1340,31 @@ const typeRules: Record<string, MatchFn> = {
|
|
1336
1340
|
throw new SyntaxError('Durations not supported on: ' + engine);
|
1337
1341
|
}
|
1338
1342
|
// TODO: The abstract sql type should accommodate this
|
1339
|
-
|
1343
|
+
let duration = args[0] as DurationNode[1];
|
1340
1344
|
if (duration == null || typeof duration !== 'object') {
|
1341
1345
|
throw new SyntaxError(
|
1342
1346
|
`Duration must be an object, got ${typeof duration}`,
|
1343
1347
|
);
|
1344
1348
|
}
|
1345
|
-
|
1346
|
-
|
1349
|
+
duration = _(duration)
|
1350
|
+
.pick('negative', 'day', 'hour', 'minute', 'second')
|
1351
|
+
.omitBy(_.isNil)
|
1352
|
+
.value() as Dictionary<string>;
|
1353
|
+
if (_(duration).omit('negative').isEmpty()) {
|
1347
1354
|
throw new SyntaxError('Invalid duration');
|
1348
1355
|
}
|
1349
1356
|
return (
|
1350
1357
|
"INTERVAL '" +
|
1351
|
-
(negative ? '-' : '') +
|
1352
|
-
(day ?? '0') +
|
1358
|
+
(duration.negative ? '-' : '') +
|
1359
|
+
(duration.day ?? '0') +
|
1353
1360
|
' ' +
|
1354
|
-
(negative ? '-' : '') +
|
1355
|
-
(hour ?? '0') +
|
1361
|
+
(duration.negative ? '-' : '') +
|
1362
|
+
(duration.hour ?? '0') +
|
1356
1363
|
':' +
|
1357
|
-
(minute ?? '0') +
|
1364
|
+
(duration.minute ?? '0') +
|
1358
1365
|
':' +
|
1359
1366
|
// Force seconds to be at least 0.0 - required for mysql
|
1360
|
-
Number(second ?? 0).toLocaleString('en', {
|
1367
|
+
Number(duration.second ?? 0).toLocaleString('en', {
|
1361
1368
|
minimumFractionDigits: 1,
|
1362
1369
|
}) +
|
1363
1370
|
"'" +
|
@@ -7,6 +7,7 @@ export const enum Engines {
|
|
7
7
|
import { AbstractSQLOptimiser } from './AbstractSQLOptimiser';
|
8
8
|
export { Binding, SqlResult } from './AbstractSQLRules2SQL';
|
9
9
|
import sbvrTypes from '@balena/sbvr-types';
|
10
|
+
import _ from 'lodash';
|
10
11
|
import type {
|
11
12
|
AbstractSqlModel,
|
12
13
|
AbstractSqlQuery,
|
@@ -79,8 +80,7 @@ export const optimizeSchema = (
|
|
79
80
|
count === 1 &&
|
80
81
|
(ruleBody[0] === 'NotExists' ||
|
81
82
|
(ruleBody[0] === 'Equals' &&
|
82
|
-
ruleBody[2][
|
83
|
-
ruleBody[2][1] === 0)) &&
|
83
|
+
_.isEqual(ruleBody[2], ['Number', 0]))) &&
|
84
84
|
isSelectQueryNode(ruleBody[1])
|
85
85
|
) {
|
86
86
|
const selectQueryNodes = ruleBody[1].slice(1);
|
@@ -120,7 +120,8 @@ export const optimizeSchema = (
|
|
120
120
|
convertReferencedFieldsToFields(whereNode);
|
121
121
|
|
122
122
|
const tableName = fromNode[1];
|
123
|
-
const table =
|
123
|
+
const table = _.find(
|
124
|
+
abstractSqlModel.tables,
|
124
125
|
(t) => t.name === tableName,
|
125
126
|
);
|
126
127
|
if (table) {
|
package/src/referenced-fields.ts
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import _ from 'lodash';
|
1
2
|
import type {
|
2
3
|
AbstractSqlQuery,
|
3
4
|
AbstractSqlType,
|
@@ -75,11 +76,7 @@ export const getReferencedFields: EngineInstance['getReferencedFields'] = (
|
|
75
76
|
) => {
|
76
77
|
const referencedFields = getRuleReferencedFields(ruleBody);
|
77
78
|
|
78
|
-
|
79
|
-
for (const key of Object.keys(referencedFields)) {
|
80
|
-
result[key] = [...new Set(referencedFields[key].update)];
|
81
|
-
}
|
82
|
-
return result;
|
79
|
+
return _.mapValues(referencedFields, ({ update }) => _.uniq(update));
|
83
80
|
};
|
84
81
|
|
85
82
|
export interface RuleReferencedFields {
|
@@ -270,8 +267,7 @@ export const getRuleReferencedFields: EngineInstance['getRuleReferencedFields']
|
|
270
267
|
const referencedFields: RuleReferencedFields = {};
|
271
268
|
if (
|
272
269
|
ruleBody[0] === 'Equals' &&
|
273
|
-
ruleBody[2][
|
274
|
-
ruleBody[2][1] === 0 &&
|
270
|
+
_.isEqual(ruleBody[2], ['Number', 0]) &&
|
275
271
|
isSelectQueryNode(ruleBody[1])
|
276
272
|
) {
|
277
273
|
const select = ruleBody[1].find(isSelectNode)!;
|
@@ -285,7 +281,7 @@ export const getRuleReferencedFields: EngineInstance['getRuleReferencedFields']
|
|
285
281
|
for (const method of Object.keys(tableRefs) as Array<
|
286
282
|
keyof typeof tableRefs
|
287
283
|
>) {
|
288
|
-
tableRefs[method] =
|
284
|
+
tableRefs[method] = _.uniq(tableRefs[method]);
|
289
285
|
}
|
290
286
|
}
|
291
287
|
|
@@ -325,9 +321,10 @@ const checkQuery = (query: AbstractSqlQuery): ModifiedFields | undefined => {
|
|
325
321
|
return { table: tableName, action: 'delete' };
|
326
322
|
}
|
327
323
|
|
328
|
-
const fields = query
|
324
|
+
const fields = _<FieldsNode | AbstractSqlType>(query)
|
329
325
|
.filter((v): v is FieldsNode => v != null && v[0] === 'Fields')
|
330
|
-
.flatMap((v) => v[1])
|
326
|
+
.flatMap((v) => v[1])
|
327
|
+
.value();
|
331
328
|
return { table: tableName, action: 'update', fields };
|
332
329
|
};
|
333
330
|
export const getModifiedFields: EngineInstance['getModifiedFields'] = (
|