@balena/odata-to-abstract-sql 8.0.2 → 9.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/test/model.sbvr DELETED
@@ -1,79 +0,0 @@
1
- Term: name
2
- Concept Type: Short Text (Type)
3
-
4
- Term: age
5
- Concept Type: Integer (Type)
6
-
7
- Term: favourite colour
8
- Concept Type: Color (Type)
9
-
10
- Term: hire date
11
- Concept Type: Date Time (Type)
12
-
13
- Term: identification type
14
- Concept Type: Short Text (Type)
15
-
16
- Term: identification number
17
- Concept Type: Short Text (Type)
18
-
19
- Term: licence
20
-
21
- Fact type: licence has name
22
- Necessity: each licence has exactly one name
23
-
24
- Term: team
25
- Database ID Field: favourite colour
26
- Fact type: team has favourite colour
27
- Necessity: each team has exactly one favourite colour
28
-
29
- Term: plane
30
- Synonym: aircraft
31
-
32
- Fact type: plane has name
33
- Necessity: each plane has exactly one name
34
-
35
- Term: person
36
-
37
- Term: pilot
38
- Concept Type: person
39
-
40
- Fact type: pilot is experienced
41
-
42
- Fact type: pilot has name
43
- Necessity: each pilot has exactly one name
44
-
45
- Fact type: pilot has age
46
- Necessity: each pilot has exactly one age
47
-
48
- Fact type: pilot has favourite colour
49
- Necessity: each pilot has exactly one favourite colour
50
-
51
- Fact type: pilot can fly plane
52
- Synonymous Form: plane can be flown by pilot
53
-
54
- Fact type: pilot is on team
55
- Synonymous Form: team includes pilot
56
- Necessity: each pilot is on exactly one team
57
-
58
- Fact type: pilot has licence
59
- Necessity: each pilot has exactly one licence
60
-
61
- Fact type: pilot has hire date
62
- Necessity: each pilot has exactly one hire date
63
-
64
- Fact type: pilot has identification type
65
- Term Form: identification method
66
- Database Table Name: identification method
67
-
68
- Fact type: identification method has identification number
69
- Necessity: each identification method has exactly one identification number.
70
-
71
- Fact type: pilot1 was trained by pilot2
72
- Synonymous Form: pilot2 trained pilot1
73
- Necessity: each pilot was trained by exactly one pilot
74
-
75
- Term: copilot
76
- Concept Type: pilot
77
-
78
- Fact Type: copilot assists pilot
79
- Necessity: each copilot assists at most one pilot
package/test/orderby.ts DELETED
@@ -1,544 +0,0 @@
1
- import { expect } from 'chai';
2
- import {
3
- operandToAbstractSQLFactory,
4
- pilotFields,
5
- teamFields,
6
- } from './chai-sql';
7
- import test, { itExpectsError } from './test';
8
-
9
- const operandToAbstractSQL = operandToAbstractSQLFactory();
10
-
11
- test('/pilot?$orderby=name', (result) => {
12
- it('should order by name desc', () => {
13
- expect(result)
14
- .to.be.a.query.that.selects(pilotFields)
15
- .from('pilot')
16
- .orderby(['DESC', operandToAbstractSQL('name')]);
17
- });
18
- });
19
-
20
- test('/pilot?$orderby=name,age', (result) => {
21
- it('should order by name desc, age desc', () => {
22
- expect(result)
23
- .to.be.a.query.that.selects(pilotFields)
24
- .from('pilot')
25
- .orderby(
26
- ['DESC', operandToAbstractSQL('name')],
27
- ['DESC', operandToAbstractSQL('age')],
28
- );
29
- });
30
- });
31
-
32
- test('/pilot?$orderby=name desc', (result) => {
33
- it('should order by name desc', () => {
34
- expect(result)
35
- .to.be.a.query.that.selects(pilotFields)
36
- .from('pilot')
37
- .orderby(['DESC', operandToAbstractSQL('name')]);
38
- });
39
- });
40
-
41
- test('/pilot?$orderby=name asc', (result) => {
42
- it('should order by name asc', () => {
43
- expect(result)
44
- .to.be.a.query.that.selects(pilotFields)
45
- .from('pilot')
46
- .orderby(['ASC', operandToAbstractSQL('name')]);
47
- });
48
- });
49
-
50
- test('/pilot?$orderby=p/name asc', (result) => {
51
- // TODO: This should fail
52
- it('should order by name asc using a non-existing alias', () => {
53
- expect(result)
54
- .to.be.a.query.that.selects(pilotFields)
55
- .from('pilot')
56
- .orderby(['ASC', operandToAbstractSQL('name')]);
57
- });
58
- });
59
-
60
- test('/pilot?$orderby=name asc,age desc', (result) => {
61
- it('should order by name asc, age desc', () => {
62
- expect(result)
63
- .to.be.a.query.that.selects(pilotFields)
64
- .from('pilot')
65
- .orderby(
66
- ['ASC', operandToAbstractSQL('name')],
67
- ['DESC', operandToAbstractSQL('age')],
68
- );
69
- });
70
- });
71
-
72
- test('/pilot?$orderby=licence/id asc', (result) => {
73
- it('should order by licence/id asc', () => {
74
- expect(result)
75
- .to.be.a.query.that.selects(pilotFields)
76
- .from('pilot')
77
- .leftJoin([
78
- ['licence', 'pilot.licence'],
79
- [
80
- 'Equals',
81
- ['ReferencedField', 'pilot', 'licence'],
82
- ['ReferencedField', 'pilot.licence', 'id'],
83
- ],
84
- ])
85
- .where()
86
- .orderby(['ASC', operandToAbstractSQL('licence/id')]);
87
- });
88
- });
89
-
90
- test('/pilot?$orderby=licence/name asc,licence/id desc', (result) => {
91
- it('should order by licence/name asc, licence/id desc w/o JOINing the licence twice', () => {
92
- expect(result)
93
- .to.be.a.query.that.selects(pilotFields)
94
- .from('pilot')
95
- .leftJoin([
96
- ['licence', 'pilot.licence'],
97
- [
98
- 'Equals',
99
- ['ReferencedField', 'pilot', 'licence'],
100
- ['ReferencedField', 'pilot.licence', 'id'],
101
- ],
102
- ])
103
- .where()
104
- .orderby(
105
- ['ASC', operandToAbstractSQL('licence/name')],
106
- ['DESC', operandToAbstractSQL('licence/id')],
107
- );
108
- });
109
- });
110
-
111
- test('/pilot?$orderby=can_fly__plane/plane/id asc', (result) => {
112
- it('should order by can_fly__plane/plane/id asc', () => {
113
- expect(result)
114
- .to.be.a.query.that.selects(pilotFields)
115
- .from('pilot')
116
- .leftJoin(
117
- [
118
- ['pilot-can fly-plane', 'pilot.pilot-can fly-plane'],
119
- [
120
- 'Equals',
121
- ['ReferencedField', 'pilot', 'id'],
122
- ['ReferencedField', 'pilot.pilot-can fly-plane', 'pilot'],
123
- ],
124
- ],
125
- [
126
- ['plane', 'pilot.pilot-can fly-plane.plane'],
127
- [
128
- 'Equals',
129
- ['ReferencedField', 'pilot.pilot-can fly-plane', 'can fly-plane'],
130
- ['ReferencedField', 'pilot.pilot-can fly-plane.plane', 'id'],
131
- ],
132
- ],
133
- )
134
- .orderby(['ASC', operandToAbstractSQL('can_fly__plane/plane/id')]);
135
- });
136
- });
137
-
138
- test('/pilot?$orderby=can_fly__plane/plane/name desc,can_fly__plane/plane/id asc', (result) => {
139
- it('should order by can_fly__plane/plane/name desc, can_fly__plane/plane/id asc w/o JOINing the resources twice', () => {
140
- expect(result)
141
- .to.be.a.query.that.selects(pilotFields)
142
- .from('pilot')
143
- .leftJoin(
144
- [
145
- ['pilot-can fly-plane', 'pilot.pilot-can fly-plane'],
146
- [
147
- 'Equals',
148
- ['ReferencedField', 'pilot', 'id'],
149
- ['ReferencedField', 'pilot.pilot-can fly-plane', 'pilot'],
150
- ],
151
- ],
152
- [
153
- ['plane', 'pilot.pilot-can fly-plane.plane'],
154
- [
155
- 'Equals',
156
- ['ReferencedField', 'pilot.pilot-can fly-plane', 'can fly-plane'],
157
- ['ReferencedField', 'pilot.pilot-can fly-plane.plane', 'id'],
158
- ],
159
- ],
160
- )
161
- .where()
162
- .orderby(
163
- ['DESC', operandToAbstractSQL('can_fly__plane/plane/name')],
164
- ['ASC', operandToAbstractSQL('can_fly__plane/plane/id')],
165
- );
166
- });
167
- });
168
-
169
- test.skip('/pilot?$orderby=favourite_colour/red', () => {
170
- it("should order by how red the pilot's favourite colour is");
171
- });
172
-
173
- test('/pilot?$orderby=trained__pilot/$count asc', (result) => {
174
- it('should order pilots by how many other pilots they have trained', () => {
175
- expect(result)
176
- .to.be.a.query.that.selects(pilotFields)
177
- .from('pilot')
178
- .orderby([
179
- 'ASC',
180
- [
181
- 'SelectQuery',
182
- ['Select', [['Count', '*']]],
183
- ['From', ['Alias', ['Table', 'pilot'], 'pilot.trained-pilot']],
184
- [
185
- 'Where',
186
- [
187
- 'Equals',
188
- ['ReferencedField', 'pilot', 'id'],
189
- [
190
- 'ReferencedField',
191
- 'pilot.trained-pilot',
192
- 'was trained by-pilot',
193
- ],
194
- ],
195
- ],
196
- ],
197
- ]);
198
- });
199
- });
200
-
201
- test('/pilot?$orderby=trained__pilot/$count($filter=is_experienced eq true) asc', (result) => {
202
- it('should order pilots by how many other pilots that they have trained are now experienced', () => {
203
- expect(result)
204
- .to.be.a.query.that.selects(pilotFields)
205
- .from('pilot')
206
- .orderby([
207
- 'ASC',
208
- [
209
- 'SelectQuery',
210
- ['Select', [['Count', '*']]],
211
- ['From', ['Alias', ['Table', 'pilot'], 'pilot.trained-pilot']],
212
- [
213
- 'Where',
214
- [
215
- 'And',
216
- [
217
- 'Equals',
218
- ['ReferencedField', 'pilot', 'id'],
219
- [
220
- 'ReferencedField',
221
- 'pilot.trained-pilot',
222
- 'was trained by-pilot',
223
- ],
224
- ],
225
- [
226
- 'IsNotDistinctFrom',
227
- ['ReferencedField', 'pilot.trained-pilot', 'is experienced'],
228
- ['Bind', 0],
229
- ],
230
- ],
231
- ],
232
- ],
233
- ]);
234
- });
235
- });
236
-
237
- test('/team?$orderby=includes__pilot/$count desc', (result) => {
238
- it('should order teams by the number of pilots', () => {
239
- expect(result)
240
- .to.be.a.query.that.selects(teamFields)
241
- .from('team')
242
- .orderby([
243
- 'DESC',
244
- [
245
- 'SelectQuery',
246
- ['Select', [['Count', '*']]],
247
- ['From', ['Alias', ['Table', 'pilot'], 'team.includes-pilot']],
248
- [
249
- 'Where',
250
- [
251
- 'Equals',
252
- [
253
- 'ReferencedField',
254
- 'team',
255
- // That's b/c it's the team's `Database ID Field`
256
- 'favourite colour',
257
- ],
258
- ['ReferencedField', 'team.includes-pilot', 'is on-team'],
259
- ],
260
- ],
261
- ],
262
- ]);
263
- });
264
- });
265
-
266
- test('/team?$orderby=includes__pilot/$count($filter=is_experienced eq true) desc', (result) => {
267
- it('should order teams by the number of pilots that are experienced', () => {
268
- expect(result)
269
- .to.be.a.query.that.selects(teamFields)
270
- .from('team')
271
- .orderby([
272
- 'DESC',
273
- [
274
- 'SelectQuery',
275
- ['Select', [['Count', '*']]],
276
- ['From', ['Alias', ['Table', 'pilot'], 'team.includes-pilot']],
277
- [
278
- 'Where',
279
- [
280
- 'And',
281
- [
282
- 'Equals',
283
- [
284
- 'ReferencedField',
285
- 'team',
286
- // That's b/c it's the team's `Database ID Field`
287
- 'favourite colour',
288
- ],
289
- ['ReferencedField', 'team.includes-pilot', 'is on-team'],
290
- ],
291
- [
292
- 'IsNotDistinctFrom',
293
- ['ReferencedField', 'team.includes-pilot', 'is experienced'],
294
- ['Bind', 0],
295
- ],
296
- ],
297
- ],
298
- ],
299
- ]);
300
- });
301
- });
302
-
303
- test('/pilot?$select=name,licence/name&$orderby=name asc,licence/name desc', function (result) {
304
- it('should select from pilot.name, licence.name, ordered by the pilot name asc and licence name desc w/o JOINing the licence twice', () => {
305
- expect(result)
306
- .to.be.a.query.that.selects([
307
- operandToAbstractSQL('name'),
308
- operandToAbstractSQL('licence/name'),
309
- ])
310
- .from('pilot')
311
- .leftJoin([
312
- ['licence', 'pilot.licence'],
313
- [
314
- 'Equals',
315
- ['ReferencedField', 'pilot', 'licence'],
316
- ['ReferencedField', 'pilot.licence', 'id'],
317
- ],
318
- ])
319
- .where()
320
- .orderby(
321
- ['ASC', operandToAbstractSQL('name')],
322
- ['DESC', operandToAbstractSQL('licence/name')],
323
- );
324
- });
325
- });
326
-
327
- test(`/pilot?$orderby=identification_method(1)/identification_number desc`, (result) => {
328
- it('should fail to order pilots by their passport number when using a primitive key', () => {
329
- expect(result)
330
- .to.be.instanceOf(SyntaxError)
331
- .and.to.have.property(
332
- 'message',
333
- 'Using a key bind after a navigation expression is not supported.',
334
- );
335
- });
336
- });
337
-
338
- test(`/pilot?$orderby=identification_method(pilot=1)/identification_number desc`, (result) => {
339
- it('should fail to order by an associated resource when providing the navigated FK of the associated resource as the only part of the alternate key', () => {
340
- expect(result)
341
- .to.be.instanceOf(SyntaxError)
342
- .and.to.have.property(
343
- 'message',
344
- 'Specified already navigated field as part of key: pilot',
345
- );
346
- });
347
- });
348
-
349
- test(`/pilot?$orderby=identification_method(pilot=1,identification_type='passport')/identification_number desc`, (result) => {
350
- it('should fail to order by an associated resource when providing the navigated FK of the associated resource as part of the alternate key', () => {
351
- expect(result)
352
- .to.be.instanceOf(SyntaxError)
353
- .and.to.have.property(
354
- 'message',
355
- 'Specified already navigated field as part of key: pilot',
356
- );
357
- });
358
- });
359
-
360
- test(`/pilot?$orderby=identification_method(identification_type='passport') desc`, (result) => {
361
- it('should fail to order by an associated resource when not defining the associated resource field', () => {
362
- expect(result)
363
- .to.be.instanceOf(SyntaxError)
364
- .and.to.have.property(
365
- 'message',
366
- 'Attempted to directly fetch a virtual field: "identification_method"',
367
- );
368
- });
369
- });
370
-
371
- test(`/pilot?$orderby=identification_method(not_a_field='12345')/identification_number desc`, (result) => {
372
- it('should fail to order pilots when the field provided as an alternate key does not exist', () => {
373
- expect(result)
374
- .to.be.instanceOf(SyntaxError)
375
- .and.to.have.property(
376
- 'message',
377
- 'Specified non-existent field for path key',
378
- );
379
- });
380
- });
381
-
382
- test(`/pilot?$orderby=identification_method(identification_number='12345')/identification_number desc`, (result) => {
383
- it('should fail to order pilots when the field provided as an alternate key does not complete a natural key when combined with the navigation field', () => {
384
- expect(result)
385
- .to.be.instanceOf(SyntaxError)
386
- .and.to.have.property(
387
- 'message',
388
- 'Specified fields for path key that are not directly unique',
389
- );
390
- });
391
- });
392
-
393
- test(`/pilot?$orderby=identification_method(identification_type='passport',identification_number='12345')/identification_number desc`, (result) => {
394
- it('should fail to order pilots when the field provided as an alternate key does not complete a natural key when combined with the navigation field', () => {
395
- expect(result)
396
- .to.be.instanceOf(SyntaxError)
397
- .and.to.have.property(
398
- 'message',
399
- 'Specified fields for path key that are not directly unique',
400
- );
401
- });
402
- });
403
-
404
- test(`/pilot?$orderby=identification_method(identification_type='passport')/identification_number desc`, (result) => {
405
- it('should order pilots by their passport number when using part of the alternate key and infering the rest from the navigation', () => {
406
- expect(result)
407
- .to.be.a.query.that.selects(pilotFields)
408
- .from('pilot')
409
- .leftJoin([
410
- ['identification method', 'pilot.identification method'],
411
- [
412
- 'And',
413
- [
414
- 'Equals',
415
- ['ReferencedField', 'pilot', 'id'],
416
- ['ReferencedField', 'pilot.identification method', 'pilot'],
417
- ],
418
- [
419
- 'IsNotDistinctFrom',
420
- [
421
- 'ReferencedField',
422
- 'pilot.identification method',
423
- 'identification type',
424
- ],
425
- ['Bind', 0],
426
- ],
427
- ],
428
- ])
429
- .orderby([
430
- 'DESC',
431
- [
432
- 'ReferencedField',
433
- 'pilot.identification method',
434
- 'identification number',
435
- ],
436
- ]);
437
- });
438
- });
439
-
440
- test(`/pilot?$orderby=identification_method(identification_type='passport')/identification_number desc,identification_method(identification_type='id card')/identification_number desc`, (result) => {
441
- it('should order pilots by their passport number & then their ID when using part of the alternate key and infering the rest from the navigation', () => {
442
- expect(result)
443
- .to.be.instanceOf(Error)
444
- .and.to.have.property(
445
- 'message',
446
- `Adding JOINs on the same resource with different ON clauses is not supported. Found pilot.identification method`,
447
- );
448
- });
449
- });
450
-
451
- test(`/pilot?$orderby=identification_method(identification_type='passport')/identification_number desc,identification_method(identification_type='passport')/created_at desc`, (result) => {
452
- // TODO: This atm doens't work b/c the two JOINs are generated with differnet Bind numbers
453
- itExpectsError(
454
- `should order pilots by their passport's creation date and then by its number`,
455
- () => {
456
- expect(result)
457
- .to.be.a.query.that.selects(pilotFields)
458
- .from('pilot')
459
- .leftJoin([
460
- ['identification method', 'pilot.identification method'],
461
- [
462
- 'And',
463
- [
464
- 'Equals',
465
- ['ReferencedField', 'pilot', 'id'],
466
- ['ReferencedField', 'pilot.identification method', 'pilot'],
467
- ],
468
- [
469
- 'IsNotDistinctFrom',
470
- [
471
- 'ReferencedField',
472
- 'pilot.identification method',
473
- 'identification type',
474
- ],
475
- ['Bind', 0],
476
- ],
477
- ],
478
- ])
479
- .orderby(
480
- [
481
- 'DESC',
482
- [
483
- 'ReferencedField',
484
- 'pilot.identification method',
485
- 'identification number',
486
- ],
487
- ],
488
- [
489
- 'DESC',
490
- ['ReferencedField', 'pilot.identification method', 'created at'],
491
- ],
492
- );
493
- },
494
- 'expected SyntaxError: Adding JOINs on the same res… to be an instance of Array',
495
- );
496
- });
497
-
498
- test(`/pilot?$select=name,identification_method(identification_type='passport')/identification_number&$orderby=identification_method(identification_type='passport')/created_at desc`, (result) => {
499
- // TODO: This atm doens't work b/c the two JOINs are generated with differnet Bind numbers
500
- itExpectsError(
501
- `should order pilots by their passport's creation date and select their passport number`,
502
- () => {
503
- expect(result)
504
- .to.be.a.query.that.selects([
505
- operandToAbstractSQL('name'),
506
- [
507
- 'Alias',
508
- [
509
- 'ReferencedField',
510
- 'pilot.identification method',
511
- 'identification number',
512
- ],
513
- 'identification_number',
514
- ],
515
- ])
516
- .from('pilot')
517
- .leftJoin([
518
- ['identification method', 'pilot.identification method'],
519
- [
520
- 'And',
521
- [
522
- 'Equals',
523
- ['ReferencedField', 'pilot', 'id'],
524
- ['ReferencedField', 'pilot.identification method', 'pilot'],
525
- ],
526
- [
527
- 'IsNotDistinctFrom',
528
- [
529
- 'ReferencedField',
530
- 'pilot.identification method',
531
- 'identification type',
532
- ],
533
- ['Bind', 0],
534
- ],
535
- ],
536
- ])
537
- .orderby([
538
- 'DESC',
539
- ['ReferencedField', 'pilot.identification method', 'created at'],
540
- ]);
541
- },
542
- 'expected SyntaxError: Adding JOINs on the same res… to be an instance of Array',
543
- );
544
- });
package/test/paging.ts DELETED
@@ -1,75 +0,0 @@
1
- import { expect } from 'chai';
2
- import { pilotFields } from './chai-sql';
3
- import test from './test';
4
-
5
- test('/pilot?$top=5', (result) => {
6
- it('should select from pilot limited by 5', () => {
7
- expect(result)
8
- .to.be.a.query.that.selects(pilotFields)
9
- .from('pilot')
10
- .limit(['Bind', 0]);
11
- });
12
- });
13
-
14
- test('/pilot?$skip=100', (result) => {
15
- it('should select from pilot offset by 100', () => {
16
- expect(result)
17
- .to.be.a.query.that.selects(pilotFields)
18
- .from('pilot')
19
- .offset(['Bind', 0]);
20
- });
21
- });
22
-
23
- test('/pilot?$top=5&$skip=100', (result) => {
24
- it('should select from pilot limited by 5 and offset by 100', () => {
25
- expect(result)
26
- .to.be.a.query.that.selects(pilotFields)
27
- .from('pilot')
28
- .limit(['Bind', 0])
29
- .offset(['Bind', 1]);
30
- });
31
- });
32
-
33
- const name = 'Peter';
34
- test('/pilot?$top=5&$skip=100', 'PATCH', { name }, (result) => {
35
- it('should update pilot limited by 5 and offset by 100', () => {
36
- expect(result)
37
- .to.be.a.query.that.updates.fields('name')
38
- .values(['Bind', ['pilot', 'name']])
39
- .from('pilot')
40
- .where([
41
- 'In',
42
- ['ReferencedField', 'pilot', 'id'],
43
- [
44
- 'SelectQuery',
45
- [
46
- 'Select',
47
- [['Alias', ['ReferencedField', 'pilot', 'id'], '$modifyid']],
48
- ],
49
- ['From', ['Table', 'pilot']],
50
- ['Limit', ['Bind', 0]],
51
- ['Offset', ['Bind', 1]],
52
- ],
53
- ]);
54
- });
55
- });
56
- test('/pilot?$top=5&$skip=100', 'DELETE', (result) => {
57
- it('should delete from pilot limited by 5 and offset by 100', () => {
58
- expect(result)
59
- .to.be.a.query.that.deletes.from('pilot')
60
- .where([
61
- 'In',
62
- ['ReferencedField', 'pilot', 'id'],
63
- [
64
- 'SelectQuery',
65
- [
66
- 'Select',
67
- [['Alias', ['ReferencedField', 'pilot', 'id'], '$modifyid']],
68
- ],
69
- ['From', ['Table', 'pilot']],
70
- ['Limit', ['Bind', 0]],
71
- ['Offset', ['Bind', 1]],
72
- ],
73
- ]);
74
- });
75
- });