@balena/abstract-sql-compiler 10.2.5-build-tests-ts-c00e9270589111b882d4894fc437dd8b0343ecce-1 → 10.2.6-build-ts-tests-3f2373a4482584aa493652784bd2041a8b7b9314-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 +85 -1
- package/CHANGELOG.md +13 -0
- package/package.json +5 -11
- package/test/odata/{expand.js → expand.ts} +122 -60
- package/test/odata/{filterby.js → filterby.ts} +105 -79
- package/test/odata/{resource_parsing.js → resource_parsing.ts} +12 -12
- package/test/odata/{stress.js → stress.ts} +1 -2
- package/test/odata/test.ts +4 -3
- package/test/sbvr/{pilots.js → pilots.ts} +2 -1
- package/test/sbvr/{reference-type.js → reference-type.ts} +5 -4
- package/test/sbvr/{test.js → test.ts} +21 -8
- package/tsconfig.json +1 -2
- package/.eslintrc.js +0 -12
- package/tsconfig.js.json +0 -12
- /package/test/odata/{orderby.js → orderby.ts} +0 -0
- /package/test/odata/{paging.js → paging.ts} +0 -0
- /package/test/odata/{select.js → select.ts} +0 -0
@@ -1,3 +1,87 @@
|
|
1
|
+
- commits:
|
2
|
+
- subject: "Tests: convert test/sbvr/reference-type to typescript"
|
3
|
+
hash: c41377f6f468c2c4006399e19117153837b503e6
|
4
|
+
body: ""
|
5
|
+
footer:
|
6
|
+
Change-type: patch
|
7
|
+
change-type: patch
|
8
|
+
author: Pagan Gazzard
|
9
|
+
nested: []
|
10
|
+
- subject: "Tests: convert test/sbvr/pilots to typescript"
|
11
|
+
hash: a275ef78d116e2768f95c402b1bcbcf79b1e0079
|
12
|
+
body: ""
|
13
|
+
footer:
|
14
|
+
Change-type: patch
|
15
|
+
change-type: patch
|
16
|
+
author: Pagan Gazzard
|
17
|
+
nested: []
|
18
|
+
- subject: "Tests: convert test/sbvr/test to typescript"
|
19
|
+
hash: 18ec8de28eb80b2d1d3ec46cc7550dbbe8b4b9e6
|
20
|
+
body: ""
|
21
|
+
footer:
|
22
|
+
Change-type: patch
|
23
|
+
change-type: patch
|
24
|
+
author: Pagan Gazzard
|
25
|
+
nested: []
|
26
|
+
- subject: "Tests: convert test/odata/expand to typescript"
|
27
|
+
hash: 031750d479e9c67293c489ccd93436d33aa668f9
|
28
|
+
body: ""
|
29
|
+
footer:
|
30
|
+
Change-type: patch
|
31
|
+
change-type: patch
|
32
|
+
author: Pagan Gazzard
|
33
|
+
nested: []
|
34
|
+
- subject: "Tests: convert test/odata/filterby to typescript"
|
35
|
+
hash: 206aaf4363007e81f5d54d4bf957835b184fcf94
|
36
|
+
body: ""
|
37
|
+
footer:
|
38
|
+
Change-type: patch
|
39
|
+
change-type: patch
|
40
|
+
author: Pagan Gazzard
|
41
|
+
nested: []
|
42
|
+
- subject: "Tests: convert test/odata/orderby to typescript"
|
43
|
+
hash: 1bd82f39836a28017436090307fb6d2646396d69
|
44
|
+
body: ""
|
45
|
+
footer:
|
46
|
+
Change-type: patch
|
47
|
+
change-type: patch
|
48
|
+
author: Pagan Gazzard
|
49
|
+
nested: []
|
50
|
+
- subject: "Tests: convert test/odata/paging to typescript"
|
51
|
+
hash: fec1912620feecf5c6ab596680cec2909bfdcb1b
|
52
|
+
body: ""
|
53
|
+
footer:
|
54
|
+
Change-type: patch
|
55
|
+
change-type: patch
|
56
|
+
author: Pagan Gazzard
|
57
|
+
nested: []
|
58
|
+
- subject: "Tests: convert test/odata/resource_parsing to typescript"
|
59
|
+
hash: 601c5256a8ac7acd00ae3f978365eab44782448e
|
60
|
+
body: ""
|
61
|
+
footer:
|
62
|
+
Change-type: patch
|
63
|
+
change-type: patch
|
64
|
+
author: Pagan Gazzard
|
65
|
+
nested: []
|
66
|
+
- subject: "Tests: convert test/odata/select to typescript"
|
67
|
+
hash: 75492ad8a054b7178cb2579c61cfa98a191d49b8
|
68
|
+
body: ""
|
69
|
+
footer:
|
70
|
+
Change-type: patch
|
71
|
+
change-type: patch
|
72
|
+
author: Pagan Gazzard
|
73
|
+
nested: []
|
74
|
+
- subject: "Tests: convert test/odata/stress to typescript"
|
75
|
+
hash: 35caa5820914c0ca082f7784ff4c54c5245cefcc
|
76
|
+
body: ""
|
77
|
+
footer:
|
78
|
+
Change-type: patch
|
79
|
+
change-type: patch
|
80
|
+
author: Pagan Gazzard
|
81
|
+
nested: []
|
82
|
+
version: 10.2.6
|
83
|
+
title: ""
|
84
|
+
date: 2025-04-07T11:05:19.400Z
|
1
85
|
- commits:
|
2
86
|
- subject: "Tests: convert test/odata/test to typescript"
|
3
87
|
hash: c00e9270589111b882d4894fc437dd8b0343ecce
|
@@ -9,7 +93,7 @@
|
|
9
93
|
nested: []
|
10
94
|
version: 10.2.5
|
11
95
|
title: ""
|
12
|
-
date: 2025-04-06T22:
|
96
|
+
date: 2025-04-06T22:40:57.152Z
|
13
97
|
- commits:
|
14
98
|
- subject: Update dev dependencies
|
15
99
|
hash: 703263fa73aff2253d1a931a5946a027d20c9ff6
|
package/CHANGELOG.md
CHANGED
@@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file
|
|
4
4
|
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
|
5
5
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
6
6
|
|
7
|
+
## 10.2.6 - 2025-04-07
|
8
|
+
|
9
|
+
* Tests: convert test/sbvr/reference-type to typescript [Pagan Gazzard]
|
10
|
+
* Tests: convert test/sbvr/pilots to typescript [Pagan Gazzard]
|
11
|
+
* Tests: convert test/sbvr/test to typescript [Pagan Gazzard]
|
12
|
+
* Tests: convert test/odata/expand to typescript [Pagan Gazzard]
|
13
|
+
* Tests: convert test/odata/filterby to typescript [Pagan Gazzard]
|
14
|
+
* Tests: convert test/odata/orderby to typescript [Pagan Gazzard]
|
15
|
+
* Tests: convert test/odata/paging to typescript [Pagan Gazzard]
|
16
|
+
* Tests: convert test/odata/resource_parsing to typescript [Pagan Gazzard]
|
17
|
+
* Tests: convert test/odata/select to typescript [Pagan Gazzard]
|
18
|
+
* Tests: convert test/odata/stress to typescript [Pagan Gazzard]
|
19
|
+
|
7
20
|
## 10.2.5 - 2025-04-06
|
8
21
|
|
9
22
|
* Tests: convert test/odata/test to typescript [Pagan Gazzard]
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@balena/abstract-sql-compiler",
|
3
|
-
"version": "10.2.
|
3
|
+
"version": "10.2.6-build-ts-tests-3f2373a4482584aa493652784bd2041a8b7b9314-1",
|
4
4
|
"description": "A translator for abstract sql into sql.",
|
5
5
|
"type": "commonjs",
|
6
6
|
"main": "out/AbstractSQLCompiler.js",
|
@@ -11,8 +11,8 @@
|
|
11
11
|
"test": "mocha",
|
12
12
|
"posttest": "npm run lint",
|
13
13
|
"prepare": "node -e \"try { (await import('husky')).default() } catch (e) { if (e.code !== 'ERR_MODULE_NOT_FOUND') throw e }\" --input-type module && npm run build",
|
14
|
-
"lint-fix": "balena-lint --fix
|
15
|
-
"lint": "balena-lint
|
14
|
+
"lint-fix": "balena-lint --fix src/ test/",
|
15
|
+
"lint": "balena-lint src/ test/ && tsc --noEmit"
|
16
16
|
},
|
17
17
|
"repository": "https://github.com/balena-io-modules/abstract-sql-compiler.git",
|
18
18
|
"author": "",
|
@@ -42,9 +42,6 @@
|
|
42
42
|
"typescript": "^5.8.2"
|
43
43
|
},
|
44
44
|
"lint-staged": {
|
45
|
-
"*.js": [
|
46
|
-
"balena-lint --fix"
|
47
|
-
],
|
48
45
|
"*.ts": [
|
49
46
|
"balena-lint --fix"
|
50
47
|
]
|
@@ -54,16 +51,13 @@
|
|
54
51
|
"recursive": true,
|
55
52
|
"require": "ts-node/register/transpile-only",
|
56
53
|
"bail": true,
|
57
|
-
"_":
|
58
|
-
"test/**/*.ts",
|
59
|
-
"test/**/*.js"
|
60
|
-
]
|
54
|
+
"_": "test/**/*.ts"
|
61
55
|
},
|
62
56
|
"engines": {
|
63
57
|
"node": ">=20.14.0",
|
64
58
|
"npm": ">=10.7.0"
|
65
59
|
},
|
66
60
|
"versionist": {
|
67
|
-
"publishedAt": "2025-04-
|
61
|
+
"publishedAt": "2025-04-07T11:05:19.874Z"
|
68
62
|
}
|
69
63
|
}
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import type { ExpectationFailFn, ExpectationSuccessFn } from './test';
|
1
2
|
import test from './test';
|
2
3
|
import {
|
3
4
|
pilotFields,
|
@@ -8,8 +9,15 @@ import {
|
|
8
9
|
} from './fields';
|
9
10
|
import _ from 'lodash';
|
10
11
|
|
11
|
-
|
12
|
-
|
12
|
+
type TestFn = (
|
13
|
+
aggFunc: (field: string) => string,
|
14
|
+
fields?: string,
|
15
|
+
) => ExpectationSuccessFn;
|
16
|
+
|
17
|
+
const postgresAgg = (field: string) =>
|
18
|
+
'COALESCE(JSON_AGG(' + field + "), '[]')";
|
19
|
+
const mysqlAgg = (field: string) =>
|
20
|
+
"'[' || group_concat(" + field + ", ',') || ']'";
|
13
21
|
const websqlAgg = mysqlAgg;
|
14
22
|
|
15
23
|
(function () {
|
@@ -17,7 +25,7 @@ const websqlAgg = mysqlAgg;
|
|
17
25
|
pilotFields,
|
18
26
|
(field) => field === '"pilot"."licence"',
|
19
27
|
).join(', ');
|
20
|
-
const testFunc = (aggFunc, fields) => (result, sqlEquals) => {
|
28
|
+
const testFunc: TestFn = (aggFunc, fields) => (result, sqlEquals) => {
|
21
29
|
it('should select from pilot.*, aggregated licence', () => {
|
22
30
|
sqlEquals?.(
|
23
31
|
result,
|
@@ -38,10 +46,28 @@ FROM "pilot"`,
|
|
38
46
|
const urlCount = '/pilot?$expand=licence/$count';
|
39
47
|
test.postgres(url, testFunc(postgresAgg, aliasLicenceFields.join(', ')));
|
40
48
|
test.postgres(urlCount, testFunc(postgresAgg, 'COUNT(*) AS "$count"'));
|
41
|
-
test.mysql.fail(
|
42
|
-
|
43
|
-
|
44
|
-
|
49
|
+
test.mysql.fail(
|
50
|
+
url,
|
51
|
+
testFunc(
|
52
|
+
mysqlAgg,
|
53
|
+
aliasLicenceFields.join(', '),
|
54
|
+
) as any as ExpectationFailFn,
|
55
|
+
);
|
56
|
+
test.mysql.fail(
|
57
|
+
urlCount,
|
58
|
+
testFunc(mysqlAgg, 'COUNT(*) AS "$count"') as any as ExpectationFailFn,
|
59
|
+
);
|
60
|
+
test.websql.fail(
|
61
|
+
url,
|
62
|
+
testFunc(
|
63
|
+
websqlAgg,
|
64
|
+
aliasLicenceFields.join(', '),
|
65
|
+
) as any as ExpectationFailFn,
|
66
|
+
);
|
67
|
+
test.websql.fail(
|
68
|
+
urlCount,
|
69
|
+
testFunc(websqlAgg, 'COUNT(*) AS "$count"') as any as ExpectationFailFn,
|
70
|
+
);
|
45
71
|
})();
|
46
72
|
|
47
73
|
(function () {
|
@@ -49,7 +75,7 @@ FROM "pilot"`,
|
|
49
75
|
aliasPilotCanFlyPlaneFields,
|
50
76
|
(field) => field === '"pilot.pilot-can fly-plane"."can fly-plane"',
|
51
77
|
).join(', ');
|
52
|
-
const testFunc = (aggFunc) => (result, sqlEquals) => {
|
78
|
+
const testFunc: TestFn = (aggFunc) => (result, sqlEquals) => {
|
53
79
|
it('should select from pilot.*, aggregated(pilot-can fly-plane, aggregated plane)', () => {
|
54
80
|
sqlEquals?.(
|
55
81
|
result,
|
@@ -79,8 +105,8 @@ FROM "pilot"`,
|
|
79
105
|
'/pilot?$expand=can_fly__plane($expand=plane)',
|
80
106
|
]) {
|
81
107
|
test.postgres(url, testFunc(postgresAgg));
|
82
|
-
test.mysql.fail(url, testFunc(mysqlAgg));
|
83
|
-
test.websql.fail(url, testFunc(websqlAgg));
|
108
|
+
test.mysql.fail(url, testFunc(mysqlAgg) as any as ExpectationFailFn);
|
109
|
+
test.websql.fail(url, testFunc(websqlAgg) as any as ExpectationFailFn);
|
84
110
|
}
|
85
111
|
})();
|
86
112
|
|
@@ -93,7 +119,7 @@ FROM "pilot"`,
|
|
93
119
|
pilotFields,
|
94
120
|
(field) => field === '"pilot"."licence"',
|
95
121
|
).join(', ');
|
96
|
-
const testFunc = (aggFunc) => (result, sqlEquals) => {
|
122
|
+
const testFunc: TestFn = (aggFunc) => (result, sqlEquals) => {
|
97
123
|
it('should select from pilot.*, aggregated(pilot-can fly-plane, aggregated plane), aggregated licence', () => {
|
98
124
|
sqlEquals?.(
|
99
125
|
result,
|
@@ -130,13 +156,13 @@ FROM "pilot"`,
|
|
130
156
|
'/pilot?$expand=can_fly__plane($expand=plane),licence',
|
131
157
|
]) {
|
132
158
|
test.postgres(url, testFunc(postgresAgg));
|
133
|
-
test.mysql.fail(url, testFunc(mysqlAgg));
|
134
|
-
test.websql.fail(url, testFunc(websqlAgg));
|
159
|
+
test.mysql.fail(url, testFunc(mysqlAgg) as any as ExpectationFailFn);
|
160
|
+
test.websql.fail(url, testFunc(websqlAgg) as any as ExpectationFailFn);
|
135
161
|
}
|
136
162
|
})();
|
137
163
|
|
138
164
|
(function () {
|
139
|
-
const testFunc = (aggFunc) => (result, sqlEquals) => {
|
165
|
+
const testFunc: TestFn = (aggFunc) => (result, sqlEquals) => {
|
140
166
|
it('should select from pilot.*, aggregated(pilot-can fly-plane, aggregated plane), aggregated licence', () => {
|
141
167
|
sqlEquals?.(
|
142
168
|
result,
|
@@ -155,8 +181,8 @@ FROM "pilot"`,
|
|
155
181
|
};
|
156
182
|
const url = '/pilot?$select=licence&$expand=licence';
|
157
183
|
test.postgres(url, testFunc(postgresAgg));
|
158
|
-
test.mysql.fail(url, testFunc(mysqlAgg));
|
159
|
-
test.websql.fail(url, testFunc(websqlAgg));
|
184
|
+
test.mysql.fail(url, testFunc(mysqlAgg) as any as ExpectationFailFn);
|
185
|
+
test.websql.fail(url, testFunc(websqlAgg) as any as ExpectationFailFn);
|
160
186
|
})();
|
161
187
|
|
162
188
|
(function () {
|
@@ -164,7 +190,7 @@ FROM "pilot"`,
|
|
164
190
|
aliasPilotCanFlyPlaneFields,
|
165
191
|
(field) => field === '"pilot.pilot-can fly-plane"."can fly-plane"',
|
166
192
|
).join(', ');
|
167
|
-
const testFunc = (aggFunc) => (result, sqlEquals) => {
|
193
|
+
const testFunc: TestFn = (aggFunc) => (result, sqlEquals) => {
|
168
194
|
it('should select from pilot.*, aggregated(pilot-can fly-plane, aggregated plane)', () => {
|
169
195
|
sqlEquals?.(
|
170
196
|
result,
|
@@ -194,8 +220,8 @@ FROM "pilot"`,
|
|
194
220
|
'/pilot?$select=id&$expand=can_fly__plane($expand=plane)',
|
195
221
|
]) {
|
196
222
|
test.postgres(url, testFunc(postgresAgg));
|
197
|
-
test.mysql.fail(url, testFunc(mysqlAgg));
|
198
|
-
test.websql.fail(url, testFunc(websqlAgg));
|
223
|
+
test.mysql.fail(url, testFunc(mysqlAgg) as any as ExpectationFailFn);
|
224
|
+
test.websql.fail(url, testFunc(websqlAgg) as any as ExpectationFailFn);
|
199
225
|
}
|
200
226
|
})();
|
201
227
|
|
@@ -204,7 +230,7 @@ FROM "pilot"`,
|
|
204
230
|
aliasPilotCanFlyPlaneFields,
|
205
231
|
(field) => field === '"pilot.pilot-can fly-plane"."can fly-plane"',
|
206
232
|
).join(', ');
|
207
|
-
const testFunc = (aggFunc) => (result, sqlEquals) => {
|
233
|
+
const testFunc: TestFn = (aggFunc) => (result, sqlEquals) => {
|
208
234
|
it('should select from pilot.*, aggregated(pilot-can fly-plane, aggregated plane), aggregated licence', () => {
|
209
235
|
sqlEquals?.(
|
210
236
|
result,
|
@@ -241,13 +267,13 @@ FROM "pilot"`,
|
|
241
267
|
'/pilot?$select=id,licence&$expand=can_fly__plane($expand=plane),licence',
|
242
268
|
]) {
|
243
269
|
test.postgres(url, testFunc(postgresAgg));
|
244
|
-
test.mysql.fail(url, testFunc(mysqlAgg));
|
245
|
-
test.websql.fail(url, testFunc(websqlAgg));
|
270
|
+
test.mysql.fail(url, testFunc(mysqlAgg) as any as ExpectationFailFn);
|
271
|
+
test.websql.fail(url, testFunc(websqlAgg) as any as ExpectationFailFn);
|
246
272
|
}
|
247
273
|
})();
|
248
274
|
|
249
275
|
(function () {
|
250
|
-
const testFunc = (aggFunc) => (result, sqlEquals) => {
|
276
|
+
const testFunc: TestFn = (aggFunc) => (result, sqlEquals) => {
|
251
277
|
it('should select from pilot.*, aggregated(pilot-can fly-plane, aggregated plane)', () => {
|
252
278
|
sqlEquals?.(
|
253
279
|
result,
|
@@ -266,8 +292,8 @@ FROM "pilot"`,
|
|
266
292
|
};
|
267
293
|
const url = '/pilot?$expand=can_fly__plane($select=id)';
|
268
294
|
test.postgres(url, testFunc(postgresAgg));
|
269
|
-
test.mysql.fail(url, testFunc(mysqlAgg));
|
270
|
-
test.websql.fail(url, testFunc(websqlAgg));
|
295
|
+
test.mysql.fail(url, testFunc(mysqlAgg) as any as ExpectationFailFn);
|
296
|
+
test.websql.fail(url, testFunc(websqlAgg) as any as ExpectationFailFn);
|
271
297
|
})();
|
272
298
|
|
273
299
|
(function () {
|
@@ -275,7 +301,7 @@ FROM "pilot"`,
|
|
275
301
|
pilotFields,
|
276
302
|
(field) => field === '"pilot"."licence"',
|
277
303
|
).join(', ');
|
278
|
-
const testFunc = (aggFunc, fields) => (result, sqlEquals) => {
|
304
|
+
const testFunc: TestFn = (aggFunc, fields) => (result, sqlEquals) => {
|
279
305
|
it('should select from pilot.*, aggregated licence', () => {
|
280
306
|
sqlEquals?.(
|
281
307
|
result,
|
@@ -311,25 +337,31 @@ FROM "pilot"`,
|
|
311
337
|
url,
|
312
338
|
'GET',
|
313
339
|
[['Bind', 0]],
|
314
|
-
testFunc(
|
340
|
+
testFunc(
|
341
|
+
mysqlAgg,
|
342
|
+
aliasLicenceFields.join(', '),
|
343
|
+
) as any as ExpectationFailFn,
|
315
344
|
);
|
316
345
|
test.mysql.fail(
|
317
346
|
urlCount,
|
318
347
|
'GET',
|
319
348
|
[['Bind', 0]],
|
320
|
-
testFunc(mysqlAgg, 'COUNT(*) AS "$count"'),
|
349
|
+
testFunc(mysqlAgg, 'COUNT(*) AS "$count"') as any as ExpectationFailFn,
|
321
350
|
);
|
322
351
|
test.websql.fail(
|
323
352
|
url,
|
324
353
|
'GET',
|
325
354
|
[['Bind', 0]],
|
326
|
-
testFunc(
|
355
|
+
testFunc(
|
356
|
+
websqlAgg,
|
357
|
+
aliasLicenceFields.join(', '),
|
358
|
+
) as any as ExpectationFailFn,
|
327
359
|
);
|
328
360
|
test.websql.fail(
|
329
361
|
urlCount,
|
330
362
|
'GET',
|
331
363
|
[['Bind', 0]],
|
332
|
-
testFunc(websqlAgg, 'COUNT(*) AS "$count'),
|
364
|
+
testFunc(websqlAgg, 'COUNT(*) AS "$count') as any as ExpectationFailFn,
|
333
365
|
);
|
334
366
|
})();
|
335
367
|
|
@@ -338,7 +370,7 @@ FROM "pilot"`,
|
|
338
370
|
pilotFields,
|
339
371
|
(field) => field === '"pilot"."licence"',
|
340
372
|
).join(', ');
|
341
|
-
const testFunc = (aggFunc) => (result, sqlEquals) => {
|
373
|
+
const testFunc: TestFn = (aggFunc) => (result, sqlEquals) => {
|
342
374
|
it('should select from pilot.*, aggregated licence', () => {
|
343
375
|
sqlEquals?.(
|
344
376
|
result,
|
@@ -359,8 +391,18 @@ FROM "pilot"`,
|
|
359
391
|
};
|
360
392
|
const url = '/pilot?$expand=licence($filter=is_of__pilot/id eq 1)';
|
361
393
|
test.postgres(url, 'GET', [['Bind', 0]], testFunc(postgresAgg));
|
362
|
-
test.mysql.fail(
|
363
|
-
|
394
|
+
test.mysql.fail(
|
395
|
+
url,
|
396
|
+
'GET',
|
397
|
+
[['Bind', 0]],
|
398
|
+
testFunc(mysqlAgg) as any as ExpectationFailFn,
|
399
|
+
);
|
400
|
+
test.websql.fail(
|
401
|
+
url,
|
402
|
+
'GET',
|
403
|
+
[['Bind', 0]],
|
404
|
+
testFunc(websqlAgg) as any as ExpectationFailFn,
|
405
|
+
);
|
364
406
|
})();
|
365
407
|
|
366
408
|
(function () {
|
@@ -368,7 +410,7 @@ FROM "pilot"`,
|
|
368
410
|
pilotFields,
|
369
411
|
(field) => field === '"pilot"."licence"',
|
370
412
|
).join(', ');
|
371
|
-
const testFunc = (aggFunc) => (result, sqlEquals) => {
|
413
|
+
const testFunc: TestFn = (aggFunc) => (result, sqlEquals) => {
|
372
414
|
it('should select from pilot.*, aggregated licence', () => {
|
373
415
|
sqlEquals?.(
|
374
416
|
result,
|
@@ -388,8 +430,8 @@ FROM "pilot"`,
|
|
388
430
|
};
|
389
431
|
const url = '/pilot?$expand=licence($orderby=id)';
|
390
432
|
test.postgres(url, testFunc(postgresAgg));
|
391
|
-
test.mysql.fail(url, testFunc(mysqlAgg));
|
392
|
-
test.websql.fail(url, testFunc(websqlAgg));
|
433
|
+
test.mysql.fail(url, testFunc(mysqlAgg) as any as ExpectationFailFn);
|
434
|
+
test.websql.fail(url, testFunc(websqlAgg) as any as ExpectationFailFn);
|
393
435
|
})();
|
394
436
|
|
395
437
|
(function () {
|
@@ -397,7 +439,7 @@ FROM "pilot"`,
|
|
397
439
|
pilotFields,
|
398
440
|
(field) => field === '"pilot"."licence"',
|
399
441
|
).join(', ');
|
400
|
-
const testFunc = (aggFunc) => (result, sqlEquals) => {
|
442
|
+
const testFunc: TestFn = (aggFunc) => (result, sqlEquals) => {
|
401
443
|
it('should select from pilot.*, aggregated count(*) licence and ignore orderby', () => {
|
402
444
|
sqlEquals?.(
|
403
445
|
result,
|
@@ -416,8 +458,8 @@ FROM "pilot"`,
|
|
416
458
|
};
|
417
459
|
const urlCount = '/pilot?$expand=licence/$count($orderby=id)';
|
418
460
|
test.postgres(urlCount, testFunc(postgresAgg));
|
419
|
-
test.mysql.fail(urlCount, testFunc(mysqlAgg));
|
420
|
-
test.websql.fail(urlCount, testFunc(websqlAgg));
|
461
|
+
test.mysql.fail(urlCount, testFunc(mysqlAgg) as any as ExpectationFailFn);
|
462
|
+
test.websql.fail(urlCount, testFunc(websqlAgg) as any as ExpectationFailFn);
|
421
463
|
})();
|
422
464
|
|
423
465
|
(function () {
|
@@ -425,7 +467,7 @@ FROM "pilot"`,
|
|
425
467
|
pilotFields,
|
426
468
|
(field) => field === '"pilot"."licence"',
|
427
469
|
).join(', ');
|
428
|
-
const testFunc = (aggFunc) => (result, sqlEquals) => {
|
470
|
+
const testFunc: TestFn = (aggFunc) => (result, sqlEquals) => {
|
429
471
|
it('should select from pilot.*, aggregated licence', () => {
|
430
472
|
sqlEquals?.(
|
431
473
|
result,
|
@@ -445,8 +487,18 @@ FROM "pilot"`,
|
|
445
487
|
};
|
446
488
|
const url = '/pilot?$expand=licence($top=10)';
|
447
489
|
test.postgres(url, 'GET', [['Bind', 0]], testFunc(postgresAgg));
|
448
|
-
test.mysql.fail(
|
449
|
-
|
490
|
+
test.mysql.fail(
|
491
|
+
url,
|
492
|
+
'GET',
|
493
|
+
[['Bind', 0]],
|
494
|
+
testFunc(mysqlAgg) as any as ExpectationFailFn,
|
495
|
+
);
|
496
|
+
test.websql.fail(
|
497
|
+
url,
|
498
|
+
'GET',
|
499
|
+
[['Bind', 0]],
|
500
|
+
testFunc(websqlAgg) as any as ExpectationFailFn,
|
501
|
+
);
|
450
502
|
})();
|
451
503
|
|
452
504
|
(function () {
|
@@ -454,7 +506,7 @@ FROM "pilot"`,
|
|
454
506
|
pilotFields,
|
455
507
|
(field) => field === '"pilot"."licence"',
|
456
508
|
).join(', ');
|
457
|
-
const testFunc = (aggFunc) => (result, sqlEquals) => {
|
509
|
+
const testFunc: TestFn = (aggFunc) => (result, sqlEquals) => {
|
458
510
|
it('should select from pilot.*, aggregated count(*) licence and ignore top', () => {
|
459
511
|
sqlEquals?.(
|
460
512
|
result,
|
@@ -473,8 +525,8 @@ FROM "pilot"`,
|
|
473
525
|
};
|
474
526
|
const urlCount = '/pilot?$expand=licence/$count($top=10)';
|
475
527
|
test.postgres(urlCount, testFunc(postgresAgg));
|
476
|
-
test.mysql.fail(urlCount, testFunc(mysqlAgg));
|
477
|
-
test.websql.fail(urlCount, testFunc(websqlAgg));
|
528
|
+
test.mysql.fail(urlCount, testFunc(mysqlAgg) as any as ExpectationFailFn);
|
529
|
+
test.websql.fail(urlCount, testFunc(websqlAgg) as any as ExpectationFailFn);
|
478
530
|
})();
|
479
531
|
|
480
532
|
(function () {
|
@@ -482,7 +534,7 @@ FROM "pilot"`,
|
|
482
534
|
pilotFields,
|
483
535
|
(field) => field === '"pilot"."licence"',
|
484
536
|
).join(', ');
|
485
|
-
const testFunc = (aggFunc) => (result, sqlEquals) => {
|
537
|
+
const testFunc: TestFn = (aggFunc) => (result, sqlEquals) => {
|
486
538
|
it('should select from pilot.*, aggregated licence', () => {
|
487
539
|
sqlEquals?.(
|
488
540
|
result,
|
@@ -502,8 +554,18 @@ FROM "pilot"`,
|
|
502
554
|
};
|
503
555
|
const url = '/pilot?$expand=licence($skip=10)';
|
504
556
|
test.postgres(url, 'GET', [['Bind', 0]], testFunc(postgresAgg));
|
505
|
-
test.mysql.fail(
|
506
|
-
|
557
|
+
test.mysql.fail(
|
558
|
+
url,
|
559
|
+
'GET',
|
560
|
+
[['Bind', 0]],
|
561
|
+
testFunc(mysqlAgg) as any as ExpectationFailFn,
|
562
|
+
);
|
563
|
+
test.websql.fail(
|
564
|
+
url,
|
565
|
+
'GET',
|
566
|
+
[['Bind', 0]],
|
567
|
+
testFunc(websqlAgg) as any as ExpectationFailFn,
|
568
|
+
);
|
507
569
|
})();
|
508
570
|
|
509
571
|
(function () {
|
@@ -511,7 +573,7 @@ FROM "pilot"`,
|
|
511
573
|
pilotFields,
|
512
574
|
(field) => field === '"pilot"."licence"',
|
513
575
|
).join(', ');
|
514
|
-
const testFunc = (aggFunc) => (result, sqlEquals) => {
|
576
|
+
const testFunc: TestFn = (aggFunc) => (result, sqlEquals) => {
|
515
577
|
it('should select from pilot.*, aggregated count(*) licence and ignore skip', () => {
|
516
578
|
sqlEquals?.(
|
517
579
|
result,
|
@@ -530,12 +592,12 @@ FROM "pilot"`,
|
|
530
592
|
};
|
531
593
|
const urlCount = '/pilot?$expand=licence/$count($skip=10)';
|
532
594
|
test.postgres(urlCount, testFunc(postgresAgg));
|
533
|
-
test.mysql.fail(urlCount, testFunc(mysqlAgg));
|
534
|
-
test.websql.fail(urlCount, testFunc(websqlAgg));
|
595
|
+
test.mysql.fail(urlCount, testFunc(mysqlAgg) as any as ExpectationFailFn);
|
596
|
+
test.websql.fail(urlCount, testFunc(websqlAgg) as any as ExpectationFailFn);
|
535
597
|
})();
|
536
598
|
|
537
599
|
(function () {
|
538
|
-
const testFunc = (aggFunc) => (result, sqlEquals) => {
|
600
|
+
const testFunc: TestFn = (aggFunc) => (result, sqlEquals) => {
|
539
601
|
it('should select from pilot.*, aggregated(pilot-can fly-plane, aggregated plane)', () => {
|
540
602
|
sqlEquals?.(
|
541
603
|
result,
|
@@ -554,12 +616,12 @@ FROM "pilot"`,
|
|
554
616
|
};
|
555
617
|
const url = '/pilot?$expand=can_fly__plane($select=plane)';
|
556
618
|
test.postgres(url, testFunc(postgresAgg));
|
557
|
-
test.mysql.fail(url, testFunc(mysqlAgg));
|
558
|
-
test.websql.fail(url, testFunc(websqlAgg));
|
619
|
+
test.mysql.fail(url, testFunc(mysqlAgg) as any as ExpectationFailFn);
|
620
|
+
test.websql.fail(url, testFunc(websqlAgg) as any as ExpectationFailFn);
|
559
621
|
})();
|
560
622
|
|
561
623
|
(function () {
|
562
|
-
const testFunc = (aggFunc) => (result, sqlEquals) => {
|
624
|
+
const testFunc: TestFn = (aggFunc) => (result, sqlEquals) => {
|
563
625
|
it('should select from pilot.*, aggregated count(*) pilot-can fly-plane and ignore select', () => {
|
564
626
|
sqlEquals?.(
|
565
627
|
result,
|
@@ -578,8 +640,8 @@ FROM "pilot"`,
|
|
578
640
|
};
|
579
641
|
const urlCount = '/pilot?$expand=can_fly__plane/$count($select=plane)';
|
580
642
|
test.postgres(urlCount, testFunc(postgresAgg));
|
581
|
-
test.mysql.fail(urlCount, testFunc(mysqlAgg));
|
582
|
-
test.websql.fail(urlCount, testFunc(websqlAgg));
|
643
|
+
test.mysql.fail(urlCount, testFunc(mysqlAgg) as any as ExpectationFailFn);
|
644
|
+
test.websql.fail(urlCount, testFunc(websqlAgg) as any as ExpectationFailFn);
|
583
645
|
})();
|
584
646
|
|
585
647
|
(function () {
|
@@ -588,7 +650,7 @@ FROM "pilot"`,
|
|
588
650
|
pilotFields,
|
589
651
|
(field) => field === '"pilot"."trained-pilot"',
|
590
652
|
).join(', ');
|
591
|
-
const testFunc = (aggFunc) => (result, sqlEquals) => {
|
653
|
+
const testFunc: TestFn = (aggFunc) => (result, sqlEquals) => {
|
592
654
|
it('should select from pilot.*, aggregated pilot', () => {
|
593
655
|
sqlEquals?.(
|
594
656
|
result,
|
@@ -607,6 +669,6 @@ FROM "pilot"`,
|
|
607
669
|
};
|
608
670
|
const url = '/pilot?$expand=trained__pilot';
|
609
671
|
test.postgres(url, testFunc(postgresAgg));
|
610
|
-
test.mysql.fail(url, testFunc(mysqlAgg));
|
611
|
-
test.websql.fail(url, testFunc(websqlAgg));
|
672
|
+
test.mysql.fail(url, testFunc(mysqlAgg) as any as ExpectationFailFn);
|
673
|
+
test.websql.fail(url, testFunc(websqlAgg) as any as ExpectationFailFn);
|
612
674
|
})();
|
@@ -4,29 +4,46 @@
|
|
4
4
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
5
5
|
*/
|
6
6
|
import { expect } from 'chai';
|
7
|
+
import type { ExpectationSuccessFn } from './test';
|
7
8
|
import test, { clientModel } from './test';
|
8
9
|
import _ from 'lodash';
|
9
10
|
import { odataNameToSqlName } from '@balena/odata-to-abstract-sql';
|
10
11
|
import { pilotFields, teamFields, aliasPilotCanFlyPlaneFields } from './fields';
|
12
|
+
import type {
|
13
|
+
Binding,
|
14
|
+
DurationNode,
|
15
|
+
SqlResult,
|
16
|
+
} from '../../src/AbstractSQLCompiler';
|
11
17
|
|
12
18
|
const pilotFieldsStr = pilotFields.join(', ');
|
13
19
|
const aliasPilotCanFlyPlaneFieldsStr = aliasPilotCanFlyPlaneFields.join(', ');
|
14
20
|
const teamFieldsStr = teamFields.join(', ');
|
15
21
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
22
|
+
type ParsedOperand = {
|
23
|
+
odata: string | number | boolean;
|
24
|
+
bindings: Binding[];
|
25
|
+
sql: string;
|
26
|
+
};
|
27
|
+
type Operand =
|
28
|
+
| string
|
29
|
+
| number
|
30
|
+
| boolean
|
31
|
+
| Date
|
32
|
+
| DurationNode[1]
|
33
|
+
| ParsedOperand;
|
34
|
+
|
35
|
+
let parseOperandFactory = function (defaultResource = 'pilot') {
|
20
36
|
let bindNo = 0;
|
21
|
-
const operandToOData = function (operand) {
|
22
|
-
if (operand.odata != null) {
|
23
|
-
return operand.odata;
|
24
|
-
}
|
25
|
-
if (_.isDate(operand)) {
|
26
|
-
return "datetime'" + encodeURIComponent(operand.toISOString()) + "'";
|
27
|
-
}
|
37
|
+
const operandToOData = function (operand: Operand) {
|
28
38
|
if (operand != null && typeof operand === 'object') {
|
29
|
-
|
39
|
+
if ('odata' in operand) {
|
40
|
+
return operand.odata;
|
41
|
+
}
|
42
|
+
if (_.isDate(operand)) {
|
43
|
+
return "datetime'" + encodeURIComponent(operand.toISOString()) + "'";
|
44
|
+
}
|
45
|
+
|
46
|
+
const duration: Array<string | number> = [];
|
30
47
|
let t = false;
|
31
48
|
if (operand.negative) {
|
32
49
|
duration.push('-');
|
@@ -61,8 +78,8 @@ let parseOperandFactory = function (defaultResource) {
|
|
61
78
|
return operand;
|
62
79
|
};
|
63
80
|
|
64
|
-
const operandToBindings = function (operand) {
|
65
|
-
if (operand
|
81
|
+
const operandToBindings = function (operand: Operand): Binding[] {
|
82
|
+
if (typeof operand === 'object' && 'bindings' in operand) {
|
66
83
|
return operand.bindings;
|
67
84
|
}
|
68
85
|
if (
|
@@ -76,11 +93,11 @@ let parseOperandFactory = function (defaultResource) {
|
|
76
93
|
return [];
|
77
94
|
};
|
78
95
|
|
79
|
-
const operandToSQL = function (
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
if (operand
|
96
|
+
const operandToSQL = function (
|
97
|
+
operand: Operand,
|
98
|
+
resource = defaultResource,
|
99
|
+
): string {
|
100
|
+
if (typeof operand === 'object' && 'sql' in operand) {
|
84
101
|
return operand.sql;
|
85
102
|
}
|
86
103
|
if (
|
@@ -134,17 +151,17 @@ let parseOperandFactory = function (defaultResource) {
|
|
134
151
|
throw new Error('Unknown operand type: ' + operand);
|
135
152
|
};
|
136
153
|
|
137
|
-
return (operand) => ({
|
154
|
+
return (operand: Operand): ParsedOperand => ({
|
138
155
|
sql: operandToSQL(operand),
|
139
156
|
bindings: operandToBindings(operand),
|
140
157
|
odata: operandToOData(operand),
|
141
158
|
});
|
142
159
|
};
|
143
160
|
|
144
|
-
let parseOperand = null;
|
161
|
+
let parseOperand: ReturnType<typeof parseOperandFactory> | null = null;
|
145
162
|
const run = (function () {
|
146
163
|
let running = false;
|
147
|
-
return function (fn) {
|
164
|
+
return function (fn: () => void) {
|
148
165
|
if (!running) {
|
149
166
|
running = true;
|
150
167
|
parseOperand = parseOperandFactory();
|
@@ -178,10 +195,10 @@ const methodMaps = {
|
|
178
195
|
TOLOWER: 'LOWER',
|
179
196
|
};
|
180
197
|
|
181
|
-
const createExpression = function (lhs, op, rhs) {
|
198
|
+
const createExpression = function (lhs: Operand, op?: Operand, rhs?: Operand) {
|
182
199
|
let sql;
|
183
200
|
if (lhs === 'not') {
|
184
|
-
op = parseOperand(op);
|
201
|
+
op = parseOperand!(op!);
|
185
202
|
return {
|
186
203
|
odata: 'not(' + op.odata + ')',
|
187
204
|
sql: 'NOT (\n\t' + op.sql + '\n)',
|
@@ -189,17 +206,17 @@ const createExpression = function (lhs, op, rhs) {
|
|
189
206
|
};
|
190
207
|
}
|
191
208
|
if (rhs == null) {
|
192
|
-
lhs = parseOperand(lhs);
|
209
|
+
lhs = parseOperand!(lhs);
|
193
210
|
return {
|
194
211
|
odata: '(' + lhs.odata + ')',
|
195
212
|
sql: lhs.sql,
|
196
213
|
bindings: lhs.bindings,
|
197
214
|
};
|
198
215
|
}
|
199
|
-
lhs = parseOperand(lhs);
|
200
|
-
rhs = parseOperand(rhs);
|
216
|
+
lhs = parseOperand!(lhs);
|
217
|
+
rhs = parseOperand!(rhs);
|
201
218
|
const bindings = lhs.bindings.concat(rhs.bindings);
|
202
|
-
if (
|
219
|
+
if (op === 'eq' || op === 'ne') {
|
203
220
|
if ([lhs.sql, rhs.sql].includes('NULL')) {
|
204
221
|
const nullCheck = op === 'eq' ? ' IS NULL' : ' IS NOT NULL';
|
205
222
|
if (lhs.sql === 'NULL') {
|
@@ -232,10 +249,10 @@ const createExpression = function (lhs, op, rhs) {
|
|
232
249
|
}
|
233
250
|
}
|
234
251
|
} else {
|
235
|
-
sql = `${lhs.sql}${sqlOps[op]} ${rhs.sql}`;
|
252
|
+
sql = `${lhs.sql}${sqlOps[op as keyof typeof sqlOps]} ${rhs.sql}`;
|
236
253
|
}
|
237
254
|
|
238
|
-
if (sqlOpBrackets[op]) {
|
255
|
+
if (sqlOpBrackets[op as keyof typeof sqlOpBrackets]) {
|
239
256
|
sql = '(' + sql + ')';
|
240
257
|
}
|
241
258
|
return {
|
@@ -244,43 +261,44 @@ const createExpression = function (lhs, op, rhs) {
|
|
244
261
|
bindings,
|
245
262
|
};
|
246
263
|
};
|
247
|
-
const createMethodCall = function (method, ...args) {
|
248
|
-
|
249
|
-
const odata =
|
264
|
+
const createMethodCall = function (method: string, ...args: Operand[]) {
|
265
|
+
const parsedArgs = args.map((arg) => parseOperand!(arg));
|
266
|
+
const odata =
|
267
|
+
method + '(' + parsedArgs.map((arg) => arg.odata).join(',') + ')';
|
250
268
|
method = method.toUpperCase();
|
251
269
|
switch (method) {
|
252
270
|
case 'CONTAINS':
|
253
271
|
case 'SUBSTRINGOF':
|
254
272
|
if (method === 'SUBSTRINGOF') {
|
255
|
-
|
273
|
+
parsedArgs.reverse();
|
256
274
|
}
|
257
275
|
return {
|
258
|
-
sql: `${
|
259
|
-
bindings: [...
|
276
|
+
sql: `${parsedArgs[0].sql} LIKE ('%' || REPLACE(REPLACE(REPLACE(${parsedArgs[1].sql}, '\\', '\\\\'), '_', '\\_'), '%', '\\%') || '%')`,
|
277
|
+
bindings: [...parsedArgs[0].bindings, ...parsedArgs[1].bindings],
|
260
278
|
odata,
|
261
279
|
};
|
262
280
|
case 'STARTSWITH':
|
263
281
|
return {
|
264
|
-
sql: `STARTS_WITH(${
|
265
|
-
bindings: [...
|
282
|
+
sql: `STARTS_WITH(${parsedArgs[0].sql}, ${parsedArgs[1].sql})`,
|
283
|
+
bindings: [...parsedArgs[0].bindings, ...parsedArgs[1].bindings],
|
266
284
|
odata,
|
267
285
|
};
|
268
286
|
case 'ENDSWITH':
|
269
287
|
return {
|
270
|
-
sql: `${
|
271
|
-
bindings: [...
|
288
|
+
sql: `${parsedArgs[0].sql} LIKE ('%' || REPLACE(REPLACE(REPLACE(${parsedArgs[1].sql}, '\\', '\\\\'), '_', '\\_'), '%', '\\%'))`,
|
289
|
+
bindings: [...parsedArgs[0].bindings, ...parsedArgs[1].bindings],
|
272
290
|
odata,
|
273
291
|
};
|
274
292
|
case 'CONCAT':
|
275
293
|
return {
|
276
|
-
sql: '(' +
|
277
|
-
bindings: _.flatten(
|
294
|
+
sql: '(' + parsedArgs.map((arg) => arg.sql).join(' || ') + ')',
|
295
|
+
bindings: _.flatten(parsedArgs.map((arg) => arg.bindings)),
|
278
296
|
odata,
|
279
297
|
};
|
280
298
|
case 'INDEXOF':
|
281
299
|
return {
|
282
|
-
sql: 'STRPOS(' +
|
283
|
-
bindings: _.flatten(
|
300
|
+
sql: 'STRPOS(' + parsedArgs.map((arg) => arg.sql).join(', ') + ') - 1',
|
301
|
+
bindings: _.flatten(parsedArgs.map((arg) => arg.bindings)),
|
284
302
|
odata,
|
285
303
|
};
|
286
304
|
case 'NOW':
|
@@ -295,60 +313,66 @@ const createMethodCall = function (method, ...args) {
|
|
295
313
|
case 'HOUR':
|
296
314
|
case 'MINUTE':
|
297
315
|
return {
|
298
|
-
sql: `EXTRACT('${method}' FROM DATE_TRUNC('milliseconds', ${
|
299
|
-
bindings:
|
316
|
+
sql: `EXTRACT('${method}' FROM DATE_TRUNC('milliseconds', ${parsedArgs[0].sql}))`,
|
317
|
+
bindings: parsedArgs[0].bindings,
|
300
318
|
odata,
|
301
319
|
};
|
302
320
|
case 'SECOND':
|
303
321
|
return {
|
304
|
-
sql: `FLOOR(EXTRACT('${method}' FROM DATE_TRUNC('milliseconds', ${
|
305
|
-
bindings:
|
322
|
+
sql: `FLOOR(EXTRACT('${method}' FROM DATE_TRUNC('milliseconds', ${parsedArgs[0].sql})))`,
|
323
|
+
bindings: parsedArgs[0].bindings,
|
306
324
|
odata,
|
307
325
|
};
|
308
326
|
case 'FRACTIONALSECONDS':
|
309
327
|
return {
|
310
|
-
sql: `EXTRACT('SECOND' FROM DATE_TRUNC('milliseconds', ${
|
311
|
-
bindings:
|
328
|
+
sql: `EXTRACT('SECOND' FROM DATE_TRUNC('milliseconds', ${parsedArgs[0].sql})) - FLOOR(EXTRACT('SECOND' FROM DATE_TRUNC('milliseconds', ${parsedArgs[0].sql})))`,
|
329
|
+
bindings: parsedArgs[0].bindings,
|
312
330
|
odata,
|
313
331
|
};
|
314
332
|
case 'TIME':
|
315
333
|
return {
|
316
|
-
sql: `CAST(DATE_TRUNC('milliseconds', ${
|
317
|
-
bindings:
|
334
|
+
sql: `CAST(DATE_TRUNC('milliseconds', ${parsedArgs[0].sql}) AS ${method})`,
|
335
|
+
bindings: parsedArgs[0].bindings,
|
318
336
|
odata,
|
319
337
|
};
|
320
338
|
case 'TOTALSECONDS':
|
321
339
|
return {
|
322
|
-
sql: `EXTRACT(EPOCH FROM ${
|
323
|
-
bindings:
|
340
|
+
sql: `EXTRACT(EPOCH FROM ${parsedArgs[0].sql})`,
|
341
|
+
bindings: parsedArgs[0].bindings,
|
324
342
|
odata,
|
325
343
|
};
|
326
344
|
case 'DATE':
|
327
345
|
return {
|
328
|
-
sql: `DATE(DATE_TRUNC('milliseconds', ${
|
329
|
-
bindings:
|
346
|
+
sql: `DATE(DATE_TRUNC('milliseconds', ${parsedArgs[0].sql}))`,
|
347
|
+
bindings: parsedArgs[0].bindings,
|
330
348
|
odata,
|
331
349
|
};
|
332
350
|
default: {
|
333
351
|
if (Object.prototype.hasOwnProperty.call(methodMaps, method)) {
|
334
|
-
method = methodMaps[method];
|
352
|
+
method = methodMaps[method as keyof typeof methodMaps];
|
335
353
|
}
|
336
354
|
switch (method) {
|
337
355
|
case 'SUBSTRING':
|
338
|
-
|
356
|
+
parsedArgs[1].sql += ' + 1';
|
339
357
|
break;
|
340
358
|
}
|
341
|
-
const sql =
|
359
|
+
const sql =
|
360
|
+
method + '(' + parsedArgs.map((arg) => arg.sql).join(', ') + ')';
|
342
361
|
return {
|
343
362
|
sql,
|
344
|
-
bindings: _.flatten(
|
363
|
+
bindings: _.flatten(parsedArgs.map((arg) => arg.bindings)),
|
345
364
|
odata,
|
346
365
|
};
|
347
366
|
}
|
348
367
|
}
|
349
368
|
};
|
350
369
|
|
351
|
-
const operandTest = (
|
370
|
+
const operandTest = (
|
371
|
+
lhs: Operand,
|
372
|
+
op?: Operand,
|
373
|
+
rhs?: Operand,
|
374
|
+
override?: Partial<ParsedOperand>,
|
375
|
+
) => {
|
352
376
|
run(function () {
|
353
377
|
let from;
|
354
378
|
let { odata, sql, bindings } = createExpression(lhs, op, rhs);
|
@@ -392,7 +416,7 @@ WHERE ${sql}`,
|
|
392
416
|
});
|
393
417
|
};
|
394
418
|
|
395
|
-
const methodTest = (...args) => {
|
419
|
+
const methodTest = (...args: [method: string, ...Operand[]]) => {
|
396
420
|
run(function () {
|
397
421
|
const { odata, sql, bindings } = createMethodCall(...args);
|
398
422
|
test(`/pilot?$filter=${odata}`, 'GET', bindings, (result, sqlEquals) => {
|
@@ -566,7 +590,7 @@ WHERE ${sql}`,
|
|
566
590
|
});
|
567
591
|
|
568
592
|
run(function () {
|
569
|
-
const { odata: keyOdata, bindings: keyBindings } = parseOperand(1);
|
593
|
+
const { odata: keyOdata, bindings: keyBindings } = parseOperand!(1);
|
570
594
|
const { odata, bindings } = createExpression('can_fly__plane/id', 'eq', 10);
|
571
595
|
test(
|
572
596
|
'/pilot(' + keyOdata + ')/can_fly__plane?$filter=' + odata,
|
@@ -600,8 +624,8 @@ run(function () {
|
|
600
624
|
10,
|
601
625
|
);
|
602
626
|
const name = 'Peter';
|
603
|
-
const bodyBindings = [['Bind', ['pilot', 'name']], ...bindings];
|
604
|
-
const insertTest = (result, sqlEquals) => {
|
627
|
+
const bodyBindings = [['Bind', ['pilot', 'name']], ...bindings] as const;
|
628
|
+
const insertTest: ExpectationSuccessFn = (result, sqlEquals) => {
|
605
629
|
sqlEquals(
|
606
630
|
result,
|
607
631
|
`\
|
@@ -685,11 +709,11 @@ ${updateWhere}`,
|
|
685
709
|
expect(result).to.be.an('array');
|
686
710
|
});
|
687
711
|
it('that inserts', () => {
|
688
|
-
insertTest(result[0], sqlEquals);
|
712
|
+
insertTest((result as SqlResult[])[0], sqlEquals);
|
689
713
|
});
|
690
714
|
it('and updates', () => {
|
691
715
|
sqlEquals(
|
692
|
-
result[1]
|
716
|
+
(result as SqlResult[])[1],
|
693
717
|
`\
|
694
718
|
UPDATE "pilot"
|
695
719
|
SET "created at" = DEFAULT,
|
@@ -736,11 +760,10 @@ run(function () {
|
|
736
760
|
sql,
|
737
761
|
bindings: exprBindings,
|
738
762
|
} = createExpression('name', 'eq', `'${name}'`);
|
739
|
-
const bindings = [['Bind', ['pilot', 'name']], ...exprBindings];
|
740
763
|
test(
|
741
764
|
`/pilot?$filter=${odata}`,
|
742
765
|
'POST',
|
743
|
-
|
766
|
+
[['Bind', ['pilot', 'name']], ...exprBindings],
|
744
767
|
{ name },
|
745
768
|
(result, sqlEquals) => {
|
746
769
|
it(`should insert into pilot where '${odata}'`, () => {
|
@@ -767,20 +790,24 @@ WHERE EXISTS (
|
|
767
790
|
|
768
791
|
run(function () {
|
769
792
|
const name = 'Peter';
|
770
|
-
const { odata: keyOdata, bindings: keyBindings } = parseOperand(1);
|
793
|
+
const { odata: keyOdata, bindings: keyBindings } = parseOperand!(1);
|
771
794
|
const {
|
772
795
|
odata,
|
773
796
|
sql,
|
774
797
|
bindings: exprBindings,
|
775
798
|
} = createExpression('name', 'eq', `'${name}'`);
|
776
|
-
const bodyBindings = [['Bind', ['pilot', 'name']]];
|
799
|
+
const bodyBindings = [['Bind', ['pilot', 'name']]] as const;
|
777
800
|
const insertBindings = [
|
778
801
|
['Bind', ['pilot', 'id']],
|
779
802
|
...bodyBindings,
|
780
803
|
...exprBindings,
|
781
804
|
...keyBindings,
|
782
|
-
];
|
783
|
-
const updateBindings = [
|
805
|
+
] as const;
|
806
|
+
const updateBindings = [
|
807
|
+
...bodyBindings,
|
808
|
+
...keyBindings,
|
809
|
+
...exprBindings,
|
810
|
+
] as const;
|
784
811
|
test(
|
785
812
|
'/pilot(' + keyOdata + ')?$filter=' + odata,
|
786
813
|
'PATCH',
|
@@ -816,7 +843,7 @@ AND "pilot"."id" IN ((
|
|
816
843
|
});
|
817
844
|
it('that inserts', () => {
|
818
845
|
sqlEquals(
|
819
|
-
result[0]
|
846
|
+
(result as SqlResult[])[0],
|
820
847
|
`\
|
821
848
|
INSERT INTO "pilot" ("id", "name")
|
822
849
|
SELECT "$insert"."id", "$insert"."name"
|
@@ -835,7 +862,7 @@ WHERE EXISTS (
|
|
835
862
|
});
|
836
863
|
it('and updates', () => {
|
837
864
|
sqlEquals(
|
838
|
-
result[1]
|
865
|
+
(result as SqlResult[])[1],
|
839
866
|
`\
|
840
867
|
UPDATE "pilot"
|
841
868
|
SET "created at" = DEFAULT,
|
@@ -864,7 +891,7 @@ AND "pilot"."id" IN ((
|
|
864
891
|
});
|
865
892
|
|
866
893
|
run(function () {
|
867
|
-
const { odata: keyOdata, bindings: keyBindings } = parseOperand(1);
|
894
|
+
const { odata: keyOdata, bindings: keyBindings } = parseOperand!(1);
|
868
895
|
const { odata, bindings, sql } = createExpression(
|
869
896
|
createExpression(1, 'eq', 1),
|
870
897
|
'or',
|
@@ -1442,14 +1469,13 @@ WHERE CURRENT_TIMESTAMP - DATE_TRUNC('milliseconds', "pilot"."created at") < INT
|
|
1442
1469
|
|
1443
1470
|
run(function () {
|
1444
1471
|
const odata = 'now() add now()';
|
1445
|
-
test.fail(`/pilot?$filter=${odata}`, 'GET', [], (
|
1472
|
+
test.fail(`/pilot?$filter=${odata}`, 'GET', [], (err) => {
|
1446
1473
|
it(
|
1447
1474
|
'should fail to add current_timestamp to current_timestamp where "' +
|
1448
1475
|
odata +
|
1449
1476
|
'"',
|
1450
1477
|
() => {
|
1451
|
-
expect(
|
1452
|
-
expect(sqlEquals).to.be.undefined;
|
1478
|
+
expect(err).to.be.instanceOf(Error);
|
1453
1479
|
},
|
1454
1480
|
);
|
1455
1481
|
});
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { expect } from 'chai';
|
2
|
+
import type { ExpectationSuccessFn } from './test';
|
2
3
|
import test from './test';
|
3
4
|
import * as ODataParser from '@balena/odata-parser';
|
4
5
|
import {
|
@@ -9,6 +10,7 @@ import {
|
|
9
10
|
aliasPilotLicenceFields,
|
10
11
|
aliasLicenceFields,
|
11
12
|
} from './fields';
|
13
|
+
import type { SqlResult } from '../../src/AbstractSQLRules2SQL';
|
12
14
|
const aliasPilotFields = aliasFields(
|
13
15
|
'plane.pilot-can fly-plane.pilot',
|
14
16
|
pilotFields,
|
@@ -151,7 +153,7 @@ test(
|
|
151
153
|
(result, sqlEquals) => {
|
152
154
|
it('should insert/update the pilot with id 1', () => {
|
153
155
|
sqlEquals(
|
154
|
-
result[0]
|
156
|
+
(result as SqlResult[])[0],
|
155
157
|
`\
|
156
158
|
INSERT INTO "pilot" ("id")
|
157
159
|
SELECT "$insert"."id"
|
@@ -167,7 +169,7 @@ WHERE EXISTS (
|
|
167
169
|
)`,
|
168
170
|
);
|
169
171
|
sqlEquals(
|
170
|
-
result[1]
|
172
|
+
(result as SqlResult[])[1],
|
171
173
|
`\
|
172
174
|
UPDATE "pilot"
|
173
175
|
SET "created at" = DEFAULT,
|
@@ -214,12 +216,11 @@ INSERT INTO "pilot" DEFAULT VALUES`,
|
|
214
216
|
});
|
215
217
|
|
216
218
|
(function () {
|
217
|
-
|
218
|
-
const bindings = /** @type {const} */ ([
|
219
|
+
const bindings = [
|
219
220
|
['Bind', ['pilot', 'is_experienced']],
|
220
221
|
['Bind', 0],
|
221
|
-
]
|
222
|
-
const testFunc = (result, sqlEquals) => {
|
222
|
+
] as const;
|
223
|
+
const testFunc: ExpectationSuccessFn = (result, sqlEquals) => {
|
223
224
|
it('should update the pilot with id 1', () => {
|
224
225
|
sqlEquals(
|
225
226
|
result,
|
@@ -266,7 +267,7 @@ test(
|
|
266
267
|
(result, sqlEquals) => {
|
267
268
|
it('should insert/update the pilot-can fly-plane with id 1', () => {
|
268
269
|
sqlEquals(
|
269
|
-
result[0]
|
270
|
+
(result as SqlResult[])[0],
|
270
271
|
`\
|
271
272
|
INSERT INTO "pilot-can fly-plane" ("id")
|
272
273
|
SELECT "$insert"."id"
|
@@ -282,7 +283,7 @@ WHERE EXISTS (
|
|
282
283
|
)`,
|
283
284
|
);
|
284
285
|
sqlEquals(
|
285
|
-
result[1]
|
286
|
+
(result as SqlResult[])[1],
|
286
287
|
`\
|
287
288
|
UPDATE "pilot-can fly-plane"
|
288
289
|
SET "created at" = DEFAULT,
|
@@ -325,12 +326,11 @@ INSERT INTO "pilot-can fly-plane" DEFAULT VALUES`,
|
|
325
326
|
});
|
326
327
|
|
327
328
|
(function () {
|
328
|
-
|
329
|
-
const bindings = /** @type {const} */ ([
|
329
|
+
const bindings = [
|
330
330
|
['Bind', ['pilot-can fly-plane', 'pilot']],
|
331
331
|
['Bind', 0],
|
332
|
-
]
|
333
|
-
const testFunc = (result, sqlEquals) => {
|
332
|
+
] as const;
|
333
|
+
const testFunc: ExpectationSuccessFn = (result, sqlEquals) => {
|
334
334
|
it('should update the pilot with id 1', () => {
|
335
335
|
sqlEquals(
|
336
336
|
result,
|
@@ -14,8 +14,7 @@ const filterBindsNandString = _.map(
|
|
14
14
|
() => 'NOT(("pilot"."id") IS NOT NULL AND ("pilot"."id") = (?))',
|
15
15
|
).join('\nAND ');
|
16
16
|
|
17
|
-
|
18
|
-
const filterBinds = filterIDs.map((_n, i) => /** @type {const} */ (['Bind', i]));
|
17
|
+
const filterBinds = filterIDs.map((_n, i) => ['Bind', i] as const);
|
19
18
|
|
20
19
|
let filterString = `id in (${filterIDs.join(', ')})`;
|
21
20
|
test(
|
package/test/odata/test.ts
CHANGED
@@ -79,17 +79,18 @@ const sqlEquals = {
|
|
79
79
|
},
|
80
80
|
} satisfies Record<string, SqlEquals>;
|
81
81
|
|
82
|
+
type ReadonlyBinding = Readonly<AbstractSQLCompiler.Binding>;
|
82
83
|
type ExpectedBindings = ReadonlyArray<
|
83
|
-
|
84
|
+
ReadonlyBinding | readonly ReadonlyBinding[]
|
84
85
|
>;
|
85
86
|
|
86
|
-
type ExpectationSuccessFn = (
|
87
|
+
export type ExpectationSuccessFn = (
|
87
88
|
result:
|
88
89
|
| AbstractSQLCompiler.SqlResult
|
89
90
|
| [AbstractSQLCompiler.SqlResult, AbstractSQLCompiler.SqlResult],
|
90
91
|
sqlEquals: SqlEquals,
|
91
92
|
) => void;
|
92
|
-
type ExpectationFailFn = (result: Error) => void;
|
93
|
+
export type ExpectationFailFn = (result: Error) => void;
|
93
94
|
type ExpectationFn<ExpectFail extends boolean> = ExpectFail extends true
|
94
95
|
? ExpectationFailFn
|
95
96
|
: ExpectationSuccessFn;
|
@@ -1,11 +1,12 @@
|
|
1
1
|
import * as fs from 'node:fs';
|
2
2
|
const typeVocab = fs.readFileSync(
|
3
3
|
require.resolve('@balena/sbvr-types/Type.sbvr'),
|
4
|
+
'utf8',
|
4
5
|
);
|
5
6
|
import { getTestHelpers } from './test';
|
6
7
|
const test = getTestHelpers(typeVocab);
|
7
8
|
|
8
|
-
const modifiedAtTrigger = (tableName) => `\
|
9
|
+
const modifiedAtTrigger = (tableName: string) => `\
|
9
10
|
DO
|
10
11
|
$$
|
11
12
|
BEGIN
|
@@ -3,9 +3,10 @@ import { getTestHelpers } from './test';
|
|
3
3
|
|
4
4
|
const typeVocab = fs.readFileSync(
|
5
5
|
require.resolve('@balena/sbvr-types/Type.sbvr'),
|
6
|
+
'utf8',
|
6
7
|
);
|
7
8
|
|
8
|
-
const modifiedAtTrigger = (tableName) => `\
|
9
|
+
const modifiedAtTrigger = (tableName: string) => `\
|
9
10
|
DO
|
10
11
|
$$
|
11
12
|
BEGIN
|
@@ -24,7 +25,7 @@ END;
|
|
24
25
|
$$`;
|
25
26
|
|
26
27
|
describe('reference type', function () {
|
27
|
-
let test
|
28
|
+
let test: ReturnType<typeof getTestHelpers>;
|
28
29
|
beforeEach(() => {
|
29
30
|
test = getTestHelpers(typeVocab);
|
30
31
|
});
|
@@ -37,7 +38,7 @@ Term: term
|
|
37
38
|
Term: term history
|
38
39
|
Fact Type: term history references term
|
39
40
|
Necessity: each term history references exactly one term
|
40
|
-
Reference Type: informative
|
41
|
+
Reference Type: informative
|
41
42
|
`,
|
42
43
|
[
|
43
44
|
`\
|
@@ -81,7 +82,7 @@ CREATE TABLE IF NOT EXISTS "term history" (
|
|
81
82
|
Term: term
|
82
83
|
Term: term history
|
83
84
|
Fact Type: term history references term
|
84
|
-
Reference Type: informative
|
85
|
+
Reference Type: informative
|
85
86
|
Necessity: each term history references exactly one term
|
86
87
|
`,
|
87
88
|
[
|
@@ -4,10 +4,7 @@ import sbvrTypes from '@balena/sbvr-types';
|
|
4
4
|
import { expect } from 'chai';
|
5
5
|
import * as AbstractSQLCompiler from '../..';
|
6
6
|
|
7
|
-
export function getTestHelpers(builtInVocab) {
|
8
|
-
if (builtInVocab == null) {
|
9
|
-
builtInVocab = false;
|
10
|
-
}
|
7
|
+
export function getTestHelpers(builtInVocab: string | boolean = false) {
|
11
8
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
12
9
|
const SBVRParser = require('@balena/sbvr-parser').SBVRParser.createInstance();
|
13
10
|
SBVRParser.enableReusingMemoizations(SBVRParser._sideEffectingRules);
|
@@ -22,7 +19,11 @@ export function getTestHelpers(builtInVocab) {
|
|
22
19
|
|
23
20
|
let seSoFar = '';
|
24
21
|
|
25
|
-
const runExpectation = (
|
22
|
+
const runExpectation = (
|
23
|
+
it: Mocha.TestFunction,
|
24
|
+
input: string,
|
25
|
+
expectation: (result: AbstractSQLCompiler.SqlModel | Error) => void,
|
26
|
+
) => {
|
26
27
|
it(input, function () {
|
27
28
|
let result;
|
28
29
|
try {
|
@@ -30,7 +31,7 @@ export function getTestHelpers(builtInVocab) {
|
|
30
31
|
const lf = SBVRParser.matchAll(seSoFar + input, 'Process');
|
31
32
|
const schema = LF2AbstractSQLTranslator(lf, 'Process');
|
32
33
|
result = AbstractSQLCompiler.postgres.compileSchema(schema);
|
33
|
-
} catch (e) {
|
34
|
+
} catch (e: any) {
|
34
35
|
expectation(e);
|
35
36
|
return;
|
36
37
|
}
|
@@ -38,7 +39,13 @@ export function getTestHelpers(builtInVocab) {
|
|
38
39
|
});
|
39
40
|
};
|
40
41
|
|
41
|
-
const runSchema = (
|
42
|
+
const runSchema = (
|
43
|
+
it: Mocha.TestFunction,
|
44
|
+
input: string,
|
45
|
+
expectation:
|
46
|
+
| ((result: AbstractSQLCompiler.SqlModel | Error) => void)
|
47
|
+
| string[],
|
48
|
+
) => {
|
42
49
|
runExpectation(it, input, function (result) {
|
43
50
|
seSoFar += input + '\n';
|
44
51
|
if (_.isFunction(expectation)) {
|
@@ -57,7 +64,13 @@ export function getTestHelpers(builtInVocab) {
|
|
57
64
|
});
|
58
65
|
};
|
59
66
|
|
60
|
-
const runRule = (
|
67
|
+
const runRule = (
|
68
|
+
it: Mocha.TestFunction,
|
69
|
+
input: string,
|
70
|
+
expectation:
|
71
|
+
| ((result: AbstractSQLCompiler.SqlModel | Error) => void)
|
72
|
+
| string,
|
73
|
+
) => {
|
61
74
|
runExpectation(it, 'Rule: ' + input, function (result) {
|
62
75
|
if (_.isFunction(expectation)) {
|
63
76
|
expectation(result);
|
package/tsconfig.json
CHANGED
package/.eslintrc.js
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
module.exports = {
|
2
|
-
extends: ['./node_modules/@balena/lint/config/.eslintrc.js'],
|
3
|
-
parserOptions: {
|
4
|
-
project: 'tsconfig.js.json',
|
5
|
-
sourceType: 'module',
|
6
|
-
},
|
7
|
-
env: {
|
8
|
-
// TODO: Drop this once we convert all .js tests to .ts
|
9
|
-
mocha: true,
|
10
|
-
},
|
11
|
-
root: true,
|
12
|
-
};
|
package/tsconfig.js.json
DELETED
File without changes
|
File without changes
|
File without changes
|