@balena/abstract-sql-compiler 11.0.0-build-11-x-45529f014aa1c181f338c0f7348767f2990a9084-1 → 11.0.0
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/package.json +5 -2
- package/.github/workflows/flowzone.yml +0 -21
- package/.husky/pre-commit +0 -2
- package/.versionbot/CHANGELOG.yml +0 -10729
- package/CHANGELOG.md +0 -3515
- package/repo.yml +0 -12
- package/src/abstract-sql-compiler.ts +0 -1138
- package/src/abstract-sql-optimizer.ts +0 -1632
- package/src/abstract-sql-rules-to-sql.ts +0 -1730
- package/src/abstract-sql-schema-optimizer.ts +0 -172
- package/src/referenced-fields.ts +0 -600
- package/test/abstract-sql/aggregate-json.ts +0 -49
- package/test/abstract-sql/aggregate.ts +0 -161
- package/test/abstract-sql/and-or-boolean-optimisations.ts +0 -115
- package/test/abstract-sql/case-when-else.ts +0 -48
- package/test/abstract-sql/cast.ts +0 -25
- package/test/abstract-sql/coalesce.ts +0 -24
- package/test/abstract-sql/comparisons.ts +0 -360
- package/test/abstract-sql/dates.ts +0 -512
- package/test/abstract-sql/duration.ts +0 -56
- package/test/abstract-sql/empty-query-optimisations.ts +0 -54
- package/test/abstract-sql/functions-wrapper.ts +0 -70
- package/test/abstract-sql/get-referenced-fields.ts +0 -674
- package/test/abstract-sql/get-rule-referenced-fields.ts +0 -345
- package/test/abstract-sql/insert-query.ts +0 -22
- package/test/abstract-sql/is-distinct.ts +0 -102
- package/test/abstract-sql/joins.ts +0 -84
- package/test/abstract-sql/json.ts +0 -58
- package/test/abstract-sql/math.ts +0 -467
- package/test/abstract-sql/nested-in-optimisations.ts +0 -200
- package/test/abstract-sql/not-not-optimisations.ts +0 -15
- package/test/abstract-sql/schema-checks.ts +0 -168
- package/test/abstract-sql/schema-informative-reference.ts +0 -420
- package/test/abstract-sql/schema-rule-optimization.ts +0 -120
- package/test/abstract-sql/schema-rule-to-check.ts +0 -393
- package/test/abstract-sql/schema-views.ts +0 -73
- package/test/abstract-sql/test.ts +0 -192
- package/test/abstract-sql/text.ts +0 -168
- package/test/model.sbvr +0 -60
- package/test/odata/expand.ts +0 -674
- package/test/odata/fields.ts +0 -59
- package/test/odata/filterby.ts +0 -1517
- package/test/odata/orderby.ts +0 -96
- package/test/odata/paging.ts +0 -48
- package/test/odata/resource-parsing.ts +0 -568
- package/test/odata/select.ts +0 -119
- package/test/odata/stress.ts +0 -93
- package/test/odata/test.ts +0 -297
- package/test/sbvr/pilots.ts +0 -1097
- package/test/sbvr/reference-type.ts +0 -211
- package/test/sbvr/test.ts +0 -101
- package/tsconfig.build.json +0 -6
- package/tsconfig.json +0 -25
@@ -1,172 +0,0 @@
|
|
1
|
-
export const enum Engines {
|
2
|
-
postgres = 'postgres',
|
3
|
-
mysql = 'mysql',
|
4
|
-
websql = 'websql',
|
5
|
-
}
|
6
|
-
|
7
|
-
import { AbstractSQLOptimizer } from './abstract-sql-optimizer.js';
|
8
|
-
export { Binding, SqlResult } from './abstract-sql-rules-to-sql.js';
|
9
|
-
import $sbvrTypes from '@balena/sbvr-types';
|
10
|
-
const { default: sbvrTypes } = $sbvrTypes;
|
11
|
-
import type {
|
12
|
-
AbstractSqlField,
|
13
|
-
AbstractSqlModel,
|
14
|
-
AbstractSqlType,
|
15
|
-
BooleanTypeNodes,
|
16
|
-
WhereNode,
|
17
|
-
} from './abstract-sql-compiler.js';
|
18
|
-
import { isFromNode, isSelectQueryNode } from './abstract-sql-compiler.js';
|
19
|
-
|
20
|
-
const countFroms = (n: AbstractSqlType[]) => {
|
21
|
-
let count = 0;
|
22
|
-
n.forEach((p) => {
|
23
|
-
if (Array.isArray(p)) {
|
24
|
-
if (isFromNode(p)) {
|
25
|
-
count++;
|
26
|
-
} else {
|
27
|
-
count += countFroms(p as AbstractSqlType[]);
|
28
|
-
}
|
29
|
-
}
|
30
|
-
});
|
31
|
-
return count;
|
32
|
-
};
|
33
|
-
|
34
|
-
export const generateRuleSlug = (
|
35
|
-
tableName: string,
|
36
|
-
ruleBody: AbstractSqlType,
|
37
|
-
) => {
|
38
|
-
const sha = sbvrTypes.SHA.validateSync(
|
39
|
-
`${tableName}$${JSON.stringify(ruleBody)}`,
|
40
|
-
).replace(/^\$sha256\$/, '');
|
41
|
-
// Trim the trigger to a max of 63 characters, reserving at least 32 characters for the hash
|
42
|
-
return `${tableName.slice(0, 30)}$${sha}`.slice(0, 63);
|
43
|
-
};
|
44
|
-
|
45
|
-
export const optimizeSchema = (
|
46
|
-
abstractSqlModel: AbstractSqlModel,
|
47
|
-
{ createCheckConstraints = true } = {},
|
48
|
-
): AbstractSqlModel => {
|
49
|
-
for (const resourceName of Object.keys(abstractSqlModel.tables)) {
|
50
|
-
const table = abstractSqlModel.tables[resourceName];
|
51
|
-
if (typeof table === 'string') {
|
52
|
-
continue;
|
53
|
-
}
|
54
|
-
if (table.viewDefinition || table.definition) {
|
55
|
-
continue;
|
56
|
-
}
|
57
|
-
|
58
|
-
const computedFields: Array<
|
59
|
-
NonNullable<Exclude<AbstractSqlField['computed'], true>>
|
60
|
-
> = [];
|
61
|
-
for (const field of table.fields) {
|
62
|
-
const { fieldName, computed } = field;
|
63
|
-
if (computed != null && computed !== true) {
|
64
|
-
field.computed = true;
|
65
|
-
computedFields.push(['Alias', computed, fieldName]);
|
66
|
-
}
|
67
|
-
}
|
68
|
-
|
69
|
-
if (computedFields.length > 0) {
|
70
|
-
// If there are computed fields then set the `modifyFields` to only the non-computed fields, modifiable fields,
|
71
|
-
// and create a definition that computes them
|
72
|
-
table.modifyFields ??= table.fields.filter(({ computed }) => !computed);
|
73
|
-
table.definition = {
|
74
|
-
abstractSql: [
|
75
|
-
'SelectQuery',
|
76
|
-
['Select', [['Field', '*'], ...computedFields]],
|
77
|
-
['From', ['Table', table.name]],
|
78
|
-
],
|
79
|
-
};
|
80
|
-
}
|
81
|
-
}
|
82
|
-
|
83
|
-
abstractSqlModel.rules = abstractSqlModel.rules
|
84
|
-
.map((rule) => {
|
85
|
-
const [, ruleBodyNode, ruleSENode] = rule;
|
86
|
-
if (ruleBodyNode == null || ruleBodyNode[0] !== 'Body') {
|
87
|
-
throw new Error('Invalid rule');
|
88
|
-
}
|
89
|
-
let ruleBody = ruleBodyNode[1];
|
90
|
-
if (typeof ruleBody === 'string') {
|
91
|
-
throw new Error('Invalid rule');
|
92
|
-
}
|
93
|
-
if (ruleSENode == null || ruleSENode[0] !== 'StructuredEnglish') {
|
94
|
-
throw new Error('Invalid structured English');
|
95
|
-
}
|
96
|
-
const ruleSE = ruleSENode[1];
|
97
|
-
if (typeof ruleSE !== 'string') {
|
98
|
-
throw new Error('Invalid structured English');
|
99
|
-
}
|
100
|
-
|
101
|
-
// Optimize the rule body, this also normalizes it making the check constraint check easier
|
102
|
-
ruleBodyNode[1] = ruleBody = AbstractSQLOptimizer(ruleBody, true);
|
103
|
-
|
104
|
-
const count = countFroms(ruleBody);
|
105
|
-
if (
|
106
|
-
createCheckConstraints &&
|
107
|
-
count === 1 &&
|
108
|
-
(ruleBody[0] === 'NotExists' ||
|
109
|
-
(ruleBody[0] === 'Equals' &&
|
110
|
-
ruleBody[2][0] === 'Number' &&
|
111
|
-
ruleBody[2][1] === 0)) &&
|
112
|
-
isSelectQueryNode(ruleBody[1])
|
113
|
-
) {
|
114
|
-
const selectQueryNodes = ruleBody[1].slice(1);
|
115
|
-
if (
|
116
|
-
selectQueryNodes.every((n) =>
|
117
|
-
['Select', 'From', 'Where'].includes(n[0]),
|
118
|
-
)
|
119
|
-
) {
|
120
|
-
let fromNode = selectQueryNodes.find(isFromNode)![1];
|
121
|
-
if (fromNode[0] === 'Alias') {
|
122
|
-
fromNode = fromNode[1];
|
123
|
-
}
|
124
|
-
if (fromNode[0] === 'Table') {
|
125
|
-
const whereNodes = selectQueryNodes.filter(
|
126
|
-
(n): n is WhereNode => n[0] === 'Where',
|
127
|
-
);
|
128
|
-
let whereNode: BooleanTypeNodes;
|
129
|
-
if (whereNodes.length > 1) {
|
130
|
-
whereNode = ['And', ...whereNodes.map((n) => n[1])];
|
131
|
-
} else {
|
132
|
-
whereNode = whereNodes[0][1];
|
133
|
-
}
|
134
|
-
// This replaces the `Not` we stripped from the `NotExists`
|
135
|
-
whereNode = ['Not', whereNode];
|
136
|
-
|
137
|
-
const convertReferencedFieldsToFields = (n: AbstractSqlType[]) => {
|
138
|
-
n.forEach((p, i) => {
|
139
|
-
if (Array.isArray(p)) {
|
140
|
-
if (p[0] === 'ReferencedField') {
|
141
|
-
n[i] = ['Field', p[2]];
|
142
|
-
} else {
|
143
|
-
convertReferencedFieldsToFields(p as AbstractSqlType[]);
|
144
|
-
}
|
145
|
-
}
|
146
|
-
});
|
147
|
-
};
|
148
|
-
convertReferencedFieldsToFields(whereNode);
|
149
|
-
|
150
|
-
const tableName = fromNode[1];
|
151
|
-
const table = Object.values(abstractSqlModel.tables).find(
|
152
|
-
(t) => t.name === tableName,
|
153
|
-
);
|
154
|
-
if (table) {
|
155
|
-
table.checks ??= [];
|
156
|
-
table.checks.push({
|
157
|
-
description: ruleSE,
|
158
|
-
name: generateRuleSlug(tableName, ruleBody),
|
159
|
-
abstractSql: whereNode,
|
160
|
-
});
|
161
|
-
return;
|
162
|
-
}
|
163
|
-
}
|
164
|
-
}
|
165
|
-
}
|
166
|
-
|
167
|
-
return rule;
|
168
|
-
})
|
169
|
-
.filter((v): v is NonNullable<typeof v> => v != null);
|
170
|
-
|
171
|
-
return abstractSqlModel;
|
172
|
-
};
|