@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.
Files changed (53) hide show
  1. package/package.json +5 -2
  2. package/.github/workflows/flowzone.yml +0 -21
  3. package/.husky/pre-commit +0 -2
  4. package/.versionbot/CHANGELOG.yml +0 -10729
  5. package/CHANGELOG.md +0 -3515
  6. package/repo.yml +0 -12
  7. package/src/abstract-sql-compiler.ts +0 -1138
  8. package/src/abstract-sql-optimizer.ts +0 -1632
  9. package/src/abstract-sql-rules-to-sql.ts +0 -1730
  10. package/src/abstract-sql-schema-optimizer.ts +0 -172
  11. package/src/referenced-fields.ts +0 -600
  12. package/test/abstract-sql/aggregate-json.ts +0 -49
  13. package/test/abstract-sql/aggregate.ts +0 -161
  14. package/test/abstract-sql/and-or-boolean-optimisations.ts +0 -115
  15. package/test/abstract-sql/case-when-else.ts +0 -48
  16. package/test/abstract-sql/cast.ts +0 -25
  17. package/test/abstract-sql/coalesce.ts +0 -24
  18. package/test/abstract-sql/comparisons.ts +0 -360
  19. package/test/abstract-sql/dates.ts +0 -512
  20. package/test/abstract-sql/duration.ts +0 -56
  21. package/test/abstract-sql/empty-query-optimisations.ts +0 -54
  22. package/test/abstract-sql/functions-wrapper.ts +0 -70
  23. package/test/abstract-sql/get-referenced-fields.ts +0 -674
  24. package/test/abstract-sql/get-rule-referenced-fields.ts +0 -345
  25. package/test/abstract-sql/insert-query.ts +0 -22
  26. package/test/abstract-sql/is-distinct.ts +0 -102
  27. package/test/abstract-sql/joins.ts +0 -84
  28. package/test/abstract-sql/json.ts +0 -58
  29. package/test/abstract-sql/math.ts +0 -467
  30. package/test/abstract-sql/nested-in-optimisations.ts +0 -200
  31. package/test/abstract-sql/not-not-optimisations.ts +0 -15
  32. package/test/abstract-sql/schema-checks.ts +0 -168
  33. package/test/abstract-sql/schema-informative-reference.ts +0 -420
  34. package/test/abstract-sql/schema-rule-optimization.ts +0 -120
  35. package/test/abstract-sql/schema-rule-to-check.ts +0 -393
  36. package/test/abstract-sql/schema-views.ts +0 -73
  37. package/test/abstract-sql/test.ts +0 -192
  38. package/test/abstract-sql/text.ts +0 -168
  39. package/test/model.sbvr +0 -60
  40. package/test/odata/expand.ts +0 -674
  41. package/test/odata/fields.ts +0 -59
  42. package/test/odata/filterby.ts +0 -1517
  43. package/test/odata/orderby.ts +0 -96
  44. package/test/odata/paging.ts +0 -48
  45. package/test/odata/resource-parsing.ts +0 -568
  46. package/test/odata/select.ts +0 -119
  47. package/test/odata/stress.ts +0 -93
  48. package/test/odata/test.ts +0 -297
  49. package/test/sbvr/pilots.ts +0 -1097
  50. package/test/sbvr/reference-type.ts +0 -211
  51. package/test/sbvr/test.ts +0 -101
  52. package/tsconfig.build.json +0 -6
  53. package/tsconfig.json +0 -25
@@ -1,119 +0,0 @@
1
- import test from './test.js';
2
- import { pilotFields } from './fields.js';
3
- const pilotFieldsStr = pilotFields.join(', ');
4
-
5
- test('/pilot?$select=name', (result, sqlEquals) => {
6
- it('should select name from pilot', () => {
7
- sqlEquals(
8
- result,
9
- `\
10
- SELECT "pilot"."name"
11
- FROM "pilot"`,
12
- );
13
- });
14
- });
15
-
16
- test('/pilot?$select=favourite_colour', (result, sqlEquals) => {
17
- it('should select favourite_colour from pilot', () => {
18
- sqlEquals(
19
- result,
20
- `\
21
- SELECT "pilot"."favourite colour" AS "favourite_colour"
22
- FROM "pilot"`,
23
- );
24
- });
25
- });
26
-
27
- test(
28
- '/pilot(1)?$select=favourite_colour',
29
- 'GET',
30
- [['Bind', 0]],
31
- (result, sqlEquals) => {
32
- it('should select from pilot with id', () => {
33
- sqlEquals(
34
- result,
35
- `\
36
- SELECT "pilot"."favourite colour" AS "favourite_colour"
37
- FROM "pilot"
38
- WHERE "pilot"."id" IS NOT NULL AND "pilot"."id" = ?`,
39
- );
40
- });
41
- },
42
- );
43
-
44
- test(
45
- "/pilot('TextKey')?$select=favourite_colour",
46
- 'GET',
47
- [['Bind', 0]],
48
- (result, sqlEquals) => {
49
- it('should select favourite colour from pilot "TextKey"', () => {
50
- sqlEquals(
51
- result,
52
- `\
53
- SELECT "pilot"."favourite colour" AS "favourite_colour"
54
- FROM "pilot"
55
- WHERE "pilot"."id" IS NOT NULL AND "pilot"."id" = ?`,
56
- );
57
- });
58
- },
59
- );
60
-
61
- test('/pilot?$select=trained__pilot/name', (result, sqlEquals) => {
62
- it('should select name from pilot', () => {
63
- sqlEquals(
64
- result,
65
- `\
66
- SELECT "pilot.trained-pilot"."name"
67
- FROM "pilot"
68
- LEFT JOIN "pilot" AS "pilot.trained-pilot" ON "pilot"."id" = "pilot.trained-pilot"."was trained by-pilot"`,
69
- );
70
- });
71
- });
72
-
73
- test('/pilot?$select=trained__pilot/name,age', (result, sqlEquals) => {
74
- it('should select name, age from pilot', () => {
75
- sqlEquals(
76
- result,
77
- `\
78
- SELECT "pilot.trained-pilot"."name", "pilot"."age"
79
- FROM "pilot"
80
- LEFT JOIN "pilot" AS "pilot.trained-pilot" ON "pilot"."id" = "pilot.trained-pilot"."was trained by-pilot"`,
81
- );
82
- });
83
- });
84
-
85
- test('/pilot?$select=*', (result, sqlEquals) => {
86
- it('should select * from pilot', () => {
87
- sqlEquals(
88
- result,
89
- `\
90
- SELECT ${pilotFieldsStr}
91
- FROM "pilot"`,
92
- );
93
- });
94
- });
95
-
96
- test('/pilot?$select=licence/id', (result, sqlEquals) => {
97
- it('should select licence/id for pilots', () => {
98
- sqlEquals(
99
- result,
100
- `\
101
- SELECT "pilot.licence"."id"
102
- FROM "pilot"
103
- LEFT JOIN "licence" AS "pilot.licence" ON "pilot"."licence" = "pilot.licence"."id"`,
104
- );
105
- });
106
- });
107
-
108
- test('/pilot?$select=can_fly__plane/plane/id', (result, sqlEquals) => {
109
- it('should select can_fly__plane/plane/id for pilots', () => {
110
- sqlEquals(
111
- result,
112
- `\
113
- SELECT "pilot.pilot-can fly-plane.plane"."id"
114
- FROM "pilot"
115
- LEFT JOIN "pilot-can fly-plane" AS "pilot.pilot-can fly-plane" ON "pilot"."id" = "pilot.pilot-can fly-plane"."pilot"
116
- LEFT JOIN "plane" AS "pilot.pilot-can fly-plane.plane" ON "pilot.pilot-can fly-plane"."can fly-plane" = "pilot.pilot-can fly-plane.plane"."id"`,
117
- );
118
- });
119
- });
@@ -1,93 +0,0 @@
1
- import test from './test.js';
2
- import _ from 'lodash';
3
- import { pilotFields } from './fields.js';
4
- const pilotFieldsStr = pilotFields.join(', ');
5
-
6
- const filterIDs = _.range(1, 5000);
7
- const filterBindsInString = _.map(filterIDs, () => '?').join(', ');
8
- const filterBindsOrString = _.map(
9
- filterIDs,
10
- () => '"pilot"."id" IS NOT NULL AND "pilot"."id" = ?',
11
- ).join('\nOR ');
12
- const filterBindsNandString = _.map(
13
- filterIDs,
14
- () => 'NOT("pilot"."id" IS NOT NULL AND "pilot"."id" = ?)',
15
- ).join('\nAND ');
16
-
17
- const filterBinds = filterIDs.map((_n, i) => ['Bind', i] as const);
18
-
19
- let filterString = `id in (${filterIDs.join(', ')})`;
20
- test(
21
- '/pilot?$filter=' + filterString,
22
- 'GET',
23
- filterBinds,
24
- (result, sqlEquals) => {
25
- it('should select from pilot with a long IN clause', () => {
26
- sqlEquals(
27
- result,
28
- `\
29
- SELECT ${pilotFieldsStr}
30
- FROM "pilot"
31
- WHERE "pilot"."id" IN (` +
32
- filterBindsInString +
33
- ')',
34
- );
35
- });
36
- },
37
- );
38
-
39
- filterString = `not(id in (${filterIDs.join(', ')}))`;
40
- test(
41
- '/pilot?$filter=' + filterString,
42
- 'GET',
43
- filterBinds,
44
- (result, sqlEquals) => {
45
- it('should select from pilot with a long NOT IN clause', () => {
46
- sqlEquals(
47
- result,
48
- `\
49
- SELECT ${pilotFieldsStr}
50
- FROM "pilot"
51
- WHERE "pilot"."id" NOT IN (` +
52
- filterBindsInString +
53
- ')',
54
- );
55
- });
56
- },
57
- );
58
-
59
- filterString = filterIDs.map((i) => 'id eq ' + i).join(' or ');
60
- test(
61
- '/pilot?$filter=' + filterString,
62
- 'GET',
63
- filterBinds,
64
- (result, sqlEquals) => {
65
- it('should select from pilot with a long IN clause', () => {
66
- sqlEquals(
67
- result,
68
- `\
69
- SELECT ${pilotFieldsStr}
70
- FROM "pilot"
71
- WHERE (${filterBindsOrString})`,
72
- );
73
- });
74
- },
75
- );
76
-
77
- filterString = filterIDs.map((i) => 'id ne ' + i).join(' and ');
78
- test(
79
- '/pilot?$filter=' + filterString,
80
- 'GET',
81
- filterBinds,
82
- (result, sqlEquals) => {
83
- it('should select from pilot with a long NOT IN clause', () => {
84
- sqlEquals(
85
- result,
86
- `\
87
- SELECT ${pilotFieldsStr}
88
- FROM "pilot"
89
- WHERE ${filterBindsNandString}`,
90
- );
91
- });
92
- },
93
- );
@@ -1,297 +0,0 @@
1
- import fs from 'node:fs';
2
- import ODataParser from '@balena/odata-parser';
3
- import { OData2AbstractSQL } from '@balena/odata-to-abstract-sql';
4
- import $sbvrTypes from '@balena/sbvr-types';
5
- const { default: sbvrTypes } = $sbvrTypes;
6
- // @ts-expect-error @balena/sbvr-parser doesn't have types
7
- import { SBVRParser } from '@balena/sbvr-parser';
8
- // @ts-expect-error @balena/lf-to-abstract-sql doesn't have types
9
- import LF2AbstractSQL from '@balena/lf-to-abstract-sql';
10
-
11
- const sbvrModel = await fs.promises.readFile(
12
- new URL(import.meta.resolve('../model.sbvr')),
13
- 'utf8',
14
- );
15
- const typeVocab = await fs.promises.readFile(
16
- new URL(import.meta.resolve('@balena/sbvr-types/Type.sbvr')),
17
- 'utf8',
18
- );
19
-
20
- import * as AbstractSQLCompiler from '../../out/abstract-sql-compiler.js';
21
-
22
- import { expect } from 'chai';
23
- import _ from 'lodash';
24
-
25
- const generateClientModel = function (input: string) {
26
- const sbvrParser = SBVRParser.createInstance();
27
- sbvrParser.enableReusingMemoizations(sbvrParser._sideEffectingRules);
28
- sbvrParser.AddCustomAttribute('Database ID Field:');
29
- sbvrParser.AddCustomAttribute('Database Table Name:');
30
- sbvrParser.AddBuiltInVocab(typeVocab);
31
-
32
- const LF2AbstractSQLTranslator = LF2AbstractSQL.createTranslator(sbvrTypes);
33
-
34
- const lf = sbvrParser.matchAll(input, 'Process');
35
- const abstractSql = LF2AbstractSQLTranslator(lf, 'Process');
36
- return abstractSql;
37
- };
38
-
39
- export const clientModel = generateClientModel(sbvrModel);
40
- const odata2AbstractSQL = new OData2AbstractSQL(clientModel);
41
-
42
- const bindingsTest = function (
43
- actualBindings: AbstractSQLCompiler.Binding[],
44
- expectedBindings: AbstractSQLCompiler.Binding[] | false = false,
45
- ) {
46
- if (expectedBindings === false) {
47
- it('should not have any bindings', () => {
48
- expect(actualBindings).to.be.empty;
49
- });
50
- } else {
51
- it('should have matching bindings', () => {
52
- expect(actualBindings).to.deep.equal(expectedBindings);
53
- });
54
- }
55
- };
56
-
57
- type SqlEquals = (
58
- actual:
59
- | AbstractSQLCompiler.SqlResult
60
- | AbstractSQLCompiler.SqlResult[]
61
- | string,
62
- expected: string,
63
- ) => void;
64
- const equals: SqlEquals = (actual, expected) => {
65
- if (typeof actual !== 'string') {
66
- if (Array.isArray(actual)) {
67
- throw new Error('Expected a single query, got multiple');
68
- }
69
- actual = actual.query;
70
- }
71
- expect(actual).to.equal(expected);
72
- };
73
- const sqlEquals = {
74
- websql: equals,
75
- mysql: equals,
76
- postgres(actual, expected) {
77
- let num = 1;
78
- while (_.includes(expected, '?')) {
79
- expected = expected.replace('?', '$' + num);
80
- num++;
81
- }
82
- equals(actual, expected);
83
- },
84
- } satisfies Record<string, SqlEquals>;
85
-
86
- type ReadonlyBinding = Readonly<AbstractSQLCompiler.Binding>;
87
- type ExpectedBindings = ReadonlyArray<
88
- ReadonlyBinding | readonly ReadonlyBinding[]
89
- >;
90
-
91
- export type ExpectationSuccessFn = (
92
- result:
93
- | AbstractSQLCompiler.SqlResult
94
- | [AbstractSQLCompiler.SqlResult, AbstractSQLCompiler.SqlResult],
95
- sqlEquals: SqlEquals,
96
- ) => void;
97
- export type ExpectationFailFn = (result: Error) => void;
98
- type ExpectationFn<ExpectFail extends boolean> = ExpectFail extends true
99
- ? ExpectationFailFn
100
- : ExpectationSuccessFn;
101
-
102
- function runExpectation<ExpectFail extends boolean>(
103
- describe: Mocha.SuiteFunction,
104
- engine: keyof typeof sqlEquals,
105
- expectFailure: ExpectFail,
106
- input: string,
107
- method: ODataParser.SupportedMethod,
108
- expectedBindings: ExpectedBindings | false,
109
- body: Record<string, unknown>,
110
- expectation: ExpectationFn<ExpectFail>,
111
- ): void;
112
- function runExpectation<ExpectFail extends boolean>(
113
- describe: Mocha.SuiteFunction,
114
- engine: keyof typeof sqlEquals,
115
- expectFailure: ExpectFail,
116
- input: string,
117
- method: ODataParser.SupportedMethod,
118
- expectedBindings: ExpectedBindings | false,
119
- expectation: ExpectationFn<ExpectFail>,
120
- ): void;
121
- function runExpectation<ExpectFail extends boolean>(
122
- describe: Mocha.SuiteFunction,
123
- engine: keyof typeof sqlEquals,
124
- expectFailure: ExpectFail,
125
- input: string,
126
- method: ODataParser.SupportedMethod,
127
- expectation: ExpectationFn<ExpectFail>,
128
- ): void;
129
- function runExpectation<ExpectFail extends boolean>(
130
- describe: Mocha.SuiteFunction,
131
- engine: keyof typeof sqlEquals,
132
- expectFailure: ExpectFail,
133
- input: string,
134
- expectation: ExpectationFn<ExpectFail>,
135
- ): void;
136
- function runExpectation<ExpectFail extends boolean>(
137
- describe: Mocha.SuiteFunction,
138
- engine: keyof typeof sqlEquals,
139
- expectFailure: ExpectFail,
140
- input: string,
141
- ...args:
142
- | [expectation: ExpectationFn<ExpectFail>]
143
- | [
144
- method: ODataParser.SupportedMethod,
145
- expectation: ExpectationFn<ExpectFail>,
146
- ]
147
- | [
148
- method: ODataParser.SupportedMethod,
149
- expectedBindings: ExpectedBindings | false,
150
- expectation: ExpectationFn<ExpectFail>,
151
- ]
152
- | [
153
- method: ODataParser.SupportedMethod,
154
- expectedBindings: ExpectedBindings | false,
155
- body: Record<string, unknown>,
156
- expectation: ExpectationFn<ExpectFail>,
157
- ]
158
- ): void {
159
- let method: ODataParser.SupportedMethod = 'GET';
160
- let expectedBindings: ExpectedBindings | false = false;
161
- let body: Record<string, unknown> = {};
162
- let expectation: ExpectationFn<ExpectFail>;
163
- switch (args.length) {
164
- case 1:
165
- [expectation] = args;
166
- break;
167
- case 2:
168
- [method, expectation] = args;
169
- break;
170
- case 3:
171
- [method, expectedBindings, expectation] = args;
172
- break;
173
- case 4:
174
- [method, expectedBindings, body, expectation] = args;
175
- break;
176
- }
177
-
178
- describe(
179
- 'Parsing ' + method + ' ' + _.truncate(input, { length: 100 }),
180
- function () {
181
- let result;
182
- try {
183
- const odataAST = ODataParser.parse(input);
184
- const { tree, extraBodyVars } = odata2AbstractSQL.match(
185
- odataAST.tree,
186
- method,
187
- _.keys(body),
188
- 0,
189
- );
190
- _.assign(body, extraBodyVars);
191
- result = AbstractSQLCompiler[engine].compileRule(tree);
192
- } catch (e: any) {
193
- if (!expectFailure) {
194
- throw e;
195
- }
196
- (expectation as ExpectationFailFn)(e);
197
- return;
198
- }
199
- if (Array.isArray(result)) {
200
- for (let i = 0; i < result.length; i++) {
201
- const actualResult = result[i];
202
- if (expectedBindings === false) {
203
- bindingsTest(actualResult.bindings, false);
204
- } else if (expectedBindings[0][0] === 'Bind') {
205
- bindingsTest(
206
- actualResult.bindings,
207
- expectedBindings as AbstractSQLCompiler.Binding[],
208
- );
209
- } else {
210
- bindingsTest(
211
- actualResult.bindings,
212
- expectedBindings[i] as AbstractSQLCompiler.Binding[],
213
- );
214
- }
215
- }
216
- } else {
217
- bindingsTest(
218
- result.bindings,
219
- expectedBindings as AbstractSQLCompiler.Binding[],
220
- );
221
- }
222
- (expectation as ExpectationSuccessFn)(result, sqlEquals[engine]);
223
- },
224
- );
225
- }
226
-
227
- interface BoundRunExpectation<ExpectFail extends boolean> {
228
- (
229
- input: string,
230
- method: ODataParser.SupportedMethod,
231
- expectedBindings: ExpectedBindings | false,
232
- body: Record<string, unknown>,
233
- expectation: ExpectationFn<ExpectFail>,
234
- ): void;
235
- (
236
- input: string,
237
- method: ODataParser.SupportedMethod,
238
- expectedBindings: ExpectedBindings | false,
239
- expectation: ExpectationFn<ExpectFail>,
240
- ): void;
241
- (
242
- input: string,
243
- method: ODataParser.SupportedMethod,
244
- expectation: ExpectationFn<ExpectFail>,
245
- ): void;
246
- (input: string, expectation: ExpectationFn<ExpectFail>): void;
247
- (
248
- input: string,
249
- ...args:
250
- | [expectation: ExpectationFn<ExpectFail>]
251
- | [
252
- method: ODataParser.SupportedMethod,
253
- expectation: ExpectationFn<ExpectFail>,
254
- ]
255
- | [
256
- method: ODataParser.SupportedMethod,
257
- expectedBindings: ExpectedBindings | false,
258
- expectation: ExpectationFn<ExpectFail>,
259
- ]
260
- | [
261
- method: ODataParser.SupportedMethod,
262
- expectedBindings: ExpectedBindings | false,
263
- body: Record<string, unknown>,
264
- expectation: ExpectationFn<ExpectFail>,
265
- ]
266
- ): void;
267
- }
268
-
269
- type MochaBoundRunExpectation = BoundRunExpectation<false> & {
270
- fail: BoundRunExpectation<true>;
271
- skip: BoundRunExpectation<false>;
272
- only: BoundRunExpectation<false>;
273
- };
274
- const bindRunExpectation = function (engine: keyof typeof sqlEquals) {
275
- const bound: MochaBoundRunExpectation = runExpectation.bind(
276
- null,
277
- describe,
278
- engine,
279
- false,
280
- );
281
- bound.fail = runExpectation.bind(null, describe, engine, true);
282
- bound.skip = runExpectation.bind(null, describe.skip, engine, false);
283
- // eslint-disable-next-line no-only-tests/no-only-tests -- this is a false positive
284
- bound.only = runExpectation.bind(null, describe.only, engine, false);
285
- return bound;
286
- };
287
-
288
- const testFn = bindRunExpectation('postgres') as MochaBoundRunExpectation & {
289
- postgres: MochaBoundRunExpectation;
290
- mysql: MochaBoundRunExpectation;
291
- websql: MochaBoundRunExpectation;
292
- };
293
- testFn.postgres = bindRunExpectation('postgres');
294
- testFn.mysql = bindRunExpectation('mysql');
295
- testFn.websql = bindRunExpectation('websql');
296
-
297
- export default testFn;