@malloydata/malloy-tests 0.0.68 → 0.0.69-dev230809221417

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 (79) hide show
  1. package/dist/databases/all/db_index.spec.d.ts +1 -1
  2. package/dist/databases/all/db_index.spec.js +116 -6
  3. package/dist/databases/all/db_index.spec.js.map +1 -1
  4. package/dist/databases/all/expr.spec.js +542 -6
  5. package/dist/databases/all/expr.spec.js.map +1 -1
  6. package/dist/databases/all/functions.spec.d.ts +1 -1
  7. package/dist/databases/all/functions.spec.js +745 -6
  8. package/dist/databases/all/functions.spec.js.map +1 -1
  9. package/dist/databases/all/join.spec.d.ts +1 -1
  10. package/dist/databases/all/join.spec.js +272 -6
  11. package/dist/databases/all/join.spec.js.map +1 -1
  12. package/dist/databases/all/nomodel.spec.d.ts +1 -1
  13. package/dist/databases/all/nomodel.spec.js +919 -6
  14. package/dist/databases/all/nomodel.spec.js.map +1 -1
  15. package/dist/databases/all/orderby.spec.d.ts +1 -1
  16. package/dist/databases/all/orderby.spec.js +187 -6
  17. package/dist/databases/all/orderby.spec.js.map +1 -1
  18. package/dist/databases/all/problems.spec.d.ts +1 -1
  19. package/dist/databases/all/problems.spec.js +76 -6
  20. package/dist/databases/all/problems.spec.js.map +1 -1
  21. package/dist/databases/all/sql_expressions.spec.d.ts +1 -1
  22. package/dist/databases/all/sql_expressions.spec.js +58 -6
  23. package/dist/databases/all/sql_expressions.spec.js.map +1 -1
  24. package/dist/databases/all/time.spec.d.ts +1 -1
  25. package/dist/databases/all/time.spec.js +609 -5
  26. package/dist/databases/all/time.spec.js.map +1 -1
  27. package/dist/databases/shared/test_list.js +1 -20
  28. package/dist/databases/shared/test_list.js.map +1 -1
  29. package/dist/index.d.ts +0 -8
  30. package/dist/index.js +1 -17
  31. package/dist/index.js.map +1 -1
  32. package/package.json +6 -6
  33. package/src/databases/all/db_index.spec.ts +137 -6
  34. package/src/databases/all/expr.spec.ts +661 -7
  35. package/src/databases/all/functions.spec.ts +1092 -6
  36. package/src/databases/all/join.spec.ts +309 -6
  37. package/src/databases/all/nomodel.spec.ts +1114 -7
  38. package/src/databases/all/orderby.spec.ts +229 -6
  39. package/src/databases/all/problems.spec.ts +82 -6
  40. package/src/databases/all/sql_expressions.spec.ts +65 -6
  41. package/src/databases/all/time.spec.ts +734 -5
  42. package/src/databases/shared/test_list.ts +1 -20
  43. package/src/index.ts +0 -9
  44. package/dist/databases/shared/db_index.d.ts +0 -3
  45. package/dist/databases/shared/db_index.js +0 -123
  46. package/dist/databases/shared/db_index.js.map +0 -1
  47. package/dist/databases/shared/expr.d.ts +0 -3
  48. package/dist/databases/shared/expr.js +0 -551
  49. package/dist/databases/shared/expr.js.map +0 -1
  50. package/dist/databases/shared/functions.d.ts +0 -3
  51. package/dist/databases/shared/functions.js +0 -754
  52. package/dist/databases/shared/functions.js.map +0 -1
  53. package/dist/databases/shared/join.d.ts +0 -3
  54. package/dist/databases/shared/join.js +0 -302
  55. package/dist/databases/shared/join.js.map +0 -1
  56. package/dist/databases/shared/nomodel.d.ts +0 -3
  57. package/dist/databases/shared/nomodel.js +0 -950
  58. package/dist/databases/shared/nomodel.js.map +0 -1
  59. package/dist/databases/shared/orderby.d.ts +0 -3
  60. package/dist/databases/shared/orderby.js +0 -217
  61. package/dist/databases/shared/orderby.js.map +0 -1
  62. package/dist/databases/shared/problems.d.ts +0 -3
  63. package/dist/databases/shared/problems.js +0 -106
  64. package/dist/databases/shared/problems.js.map +0 -1
  65. package/dist/databases/shared/sql_expressions.d.ts +0 -3
  66. package/dist/databases/shared/sql_expressions.js +0 -88
  67. package/dist/databases/shared/sql_expressions.js.map +0 -1
  68. package/dist/databases/shared/time.d.ts +0 -3
  69. package/dist/databases/shared/time.js +0 -640
  70. package/dist/databases/shared/time.js.map +0 -1
  71. package/src/databases/shared/db_index.ts +0 -167
  72. package/src/databases/shared/expr.ts +0 -695
  73. package/src/databases/shared/functions.ts +0 -1126
  74. package/src/databases/shared/join.ts +0 -340
  75. package/src/databases/shared/nomodel.ts +0 -1150
  76. package/src/databases/shared/orderby.ts +0 -260
  77. package/src/databases/shared/problems.ts +0 -113
  78. package/src/databases/shared/sql_expressions.ts +0 -96
  79. package/src/databases/shared/time.ts +0 -786
@@ -1,695 +0,0 @@
1
- /* eslint-disable no-console */
2
- /*
3
- * Copyright 2023 Google LLC
4
- *
5
- * Permission is hereby granted, free of charge, to any person obtaining
6
- * a copy of this software and associated documentation files
7
- * (the "Software"), to deal in the Software without restriction,
8
- * including without limitation the rights to use, copy, modify, merge,
9
- * publish, distribute, sublicense, and/or sell copies of the Software,
10
- * and to permit persons to whom the Software is furnished to do so,
11
- * subject to the following conditions:
12
- *
13
- * The above copyright notice and this permission notice shall be
14
- * included in all copies or substantial portions of the Software.
15
- *
16
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
- */
24
- import {RuntimeList} from '../../runtimes';
25
- import '../../util/db-jest-matchers';
26
- import {mkSqlEqWith, testIf} from '../../util';
27
-
28
- const expressionModelText = `
29
- source: aircraft_models is table('malloytest.aircraft_models') extend {
30
- primary_key: aircraft_model_code
31
- measure:
32
- airport_count is count(*),
33
- aircraft_model_count is count(),
34
- total_seats is sum(seats),
35
- boeing_seats is sum(seats) {? manufacturer ? 'BOEING'},
36
- percent_boeing is boeing_seats / total_seats * 100,
37
- percent_boeing_floor is floor(boeing_seats / total_seats * 100),
38
- dimension: seats_bucketed is floor(seats/20)*20.0
39
- }
40
-
41
- source: aircraft is table('malloytest.aircraft') extend {
42
- primary_key: tail_num
43
- join_one: aircraft_models with aircraft_model_code
44
- measure: aircraft_count is count(*)
45
- query: by_manufacturer is {
46
- top: 5
47
- group_by: aircraft_models.manufacturer
48
- aggregate: aircraft_count
49
- }
50
- }
51
- `;
52
-
53
- export const exprSharedTests = (
54
- runtimes: RuntimeList,
55
- _splitFunction?: (column: string, splitChar: string) => string
56
- ) => {
57
- describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
58
- const expressionModel = runtime.loadModel(expressionModelText);
59
- // basic calculations for sum, filtered sum, without a join.
60
- it('basic calculations', async () => {
61
- const result = await expressionModel
62
- .loadQuery(
63
- `
64
- query: aircraft_models->{
65
- aggregate:
66
- total_seats,
67
- total_seats2 is sum(seats),
68
- boeing_seats,
69
- boeing_seats2 is sum(seats) {? manufacturer ? 'BOEING'},
70
- boeing_seats3 is total_seats {? manufacturer ? 'BOEING'},
71
- percent_boeing,
72
- percent_boeing2 is boeing_seats / total_seats * 100,
73
- -- percent_boeing_floor,
74
- -- percent_boeing_floor2 is FLOOR(boeing_seats / total_seats * 100)
75
- }
76
- `
77
- )
78
- .run();
79
- expect(result.data.path(0, 'total_seats').value).toBe(452415);
80
- expect(result.data.path(0, 'total_seats2').value).toBe(452415);
81
- expect(result.data.path(0, 'boeing_seats').value).toBe(252771);
82
- expect(result.data.path(0, 'boeing_seats2').value).toBe(252771);
83
- expect(result.data.path(0, 'boeing_seats3').value).toBe(252771);
84
- expect(
85
- Math.floor(result.data.path(0, 'percent_boeing').number.value)
86
- ).toBe(55);
87
- expect(
88
- Math.floor(result.data.path(0, 'percent_boeing2').number.value)
89
- ).toBe(55);
90
- // expect(result.data.path(0, "percent_boeing_floor").value).toBe(55);
91
- // expect(result.data.path(0, "percent_boeing_floor2").value).toBe(55);
92
- });
93
-
94
- // Floor is broken (doesn't compile because the expression returned isn't an aggregate.)
95
- it('Floor() -or any function bustage with aggregates', async () => {
96
- const result = await expressionModel
97
- .loadQuery(
98
- `
99
- query: aircraft_models->{
100
- aggregate:
101
- percent_boeing_floor
102
- percent_boeing_floor2 is FLOOR(boeing_seats / total_seats * 100)
103
- }
104
- `
105
- )
106
- .run();
107
- expect(result.data.path(0, 'percent_boeing_floor').value).toBe(55);
108
- expect(result.data.path(0, 'percent_boeing_floor2').value).toBe(55);
109
- });
110
-
111
- // Model based version of sums.
112
- it('model: expression fixups.', async () => {
113
- const result = await expressionModel
114
- .loadQuery(
115
- `
116
- query: aircraft->{
117
- aggregate:
118
- aircraft_models.total_seats
119
- aircraft_models.boeing_seats
120
- }
121
- `
122
- )
123
- .run();
124
- expect(result.data.path(0, 'total_seats').value).toBe(18294);
125
- expect(result.data.path(0, 'boeing_seats').value).toBe(6244);
126
- });
127
-
128
- // turtle expressions
129
- it('model: turtle', async () => {
130
- const result = await expressionModel
131
- .loadQuery(
132
- `
133
- query: aircraft->by_manufacturer
134
- `
135
- )
136
- .run();
137
- expect(result.data.path(0, 'manufacturer').value).toBe('CESSNA');
138
- });
139
-
140
- // filtered turtle expressions
141
- testIf(runtime.supportsNesting)('model: filtered turtle', async () => {
142
- const result = await expressionModel
143
- .loadQuery(
144
- `
145
- query: aircraft->{
146
- nest: b is by_manufacturer{? aircraft_models.manufacturer ?~'B%'}
147
- }
148
- `
149
- )
150
- .run();
151
- expect(result.data.path(0, 'b', 0, 'manufacturer').value).toBe('BEECH');
152
- });
153
-
154
- // having.
155
- it('model: simple having', async () => {
156
- const result = await expressionModel
157
- .loadQuery(
158
- `
159
- query: aircraft->{
160
- having: aircraft_count >90
161
- group_by: state
162
- aggregate: aircraft_count
163
- order_by: 2
164
- }
165
- `
166
- )
167
- .run();
168
- expect(result.data.path(0, 'aircraft_count').value).toBe(91);
169
- });
170
-
171
- testIf(runtime.supportsNesting)('model: turtle having2', async () => {
172
- const result = await expressionModel
173
- .loadQuery(
174
- `
175
- -- hacking a null test for now
176
- query: aircraft->{
177
- top: 10
178
- order_by: 1
179
- where: region != NULL
180
- group_by: region
181
- nest: by_state is {
182
- top: 10
183
- order_by: 1 desc
184
- having: aircraft_count > 50
185
- group_by: state
186
- aggregate: aircraft_count
187
- }
188
- }
189
- `
190
- )
191
- .run();
192
- expect(result.data.path(0, 'by_state', 0, 'state').value).toBe('VA');
193
- });
194
-
195
- testIf(runtime.supportsNesting)(
196
- 'model: turtle having on main',
197
- async () => {
198
- const result = await expressionModel
199
- .loadQuery(
200
- `
201
- query: aircraft->{
202
- order_by: 2 asc
203
- having: aircraft_count ? >500
204
- group_by: region
205
- aggregate: aircraft_count
206
- nest: by_state is {
207
- order_by: 2 asc
208
- having: aircraft_count >45
209
- group_by: state
210
- aggregate: aircraft_count
211
- nest: by_city is {
212
- order_by: 2 asc
213
- having: aircraft_count ? >5
214
- group_by: city
215
- aggregate: aircraft_count
216
- }
217
- }
218
- }
219
- `
220
- )
221
- .run();
222
- expect(
223
- result.data.path(0, 'by_state', 0, 'by_city', 0, 'city').value
224
- ).toBe('ALBUQUERQUE');
225
- }
226
- );
227
-
228
- // bigquery doesn't like to partition by floats,
229
- testIf(runtime.supportsNesting)(
230
- 'model: having float group by partition',
231
- async () => {
232
- await expect(runtime).queryMatches(
233
- `${expressionModelText}
234
- query: aircraft_models->{
235
- order_by: 1
236
- where: seats_bucketed > 0
237
- having: aircraft_model_count > 400
238
- group_by: seats_bucketed
239
- aggregate: aircraft_model_count
240
- nest: foo is {
241
- group_by: engines
242
- aggregate: aircraft_model_count
243
- }
244
- }`,
245
- {aircraft_model_count: 448}
246
- );
247
- }
248
- );
249
-
250
- it('model: aggregate functions distinct min max', async () => {
251
- const result = await expressionModel
252
- .loadQuery(
253
- `
254
- query: aircraft_models->{
255
- aggregate:
256
- distinct_seats is count(distinct seats),
257
- boeing_distinct_seats is count(distinct seats) {?manufacturer ? 'BOEING'},
258
- min_seats is min(seats),
259
- cessna_min_seats is min(seats) {? manufacturer ? 'CESSNA'},
260
- max_seats is max(seats),
261
- cessna_max_seats is max(seats) {? manufacturer ? 'CESSNA'},
262
- min_code is min(aircraft_model_code),
263
- boeing_min_model is min(model) {? manufacturer ? 'BOEING'},
264
- max_model is max(model),
265
- boeing_max_model is max(model) {? manufacturer ? 'BOEING'},
266
- }
267
- `
268
- )
269
- .run();
270
- expect(result.data.path(0, 'distinct_seats').value).toBe(187);
271
- expect(result.data.path(0, 'boeing_distinct_seats').value).toBe(85);
272
- expect(result.data.path(0, 'min_seats').value).toBe(0);
273
- expect(result.data.path(0, 'cessna_min_seats').value).toBe(1);
274
- expect(result.data.path(0, 'max_seats').value).toBe(660);
275
- expect(result.data.path(0, 'min_code').value).toBe('0030109');
276
- expect(result.data.path(0, 'cessna_max_seats').value).toBe(14);
277
- expect(result.data.path(0, 'boeing_min_model').value).toBe('100');
278
- expect(result.data.path(0, 'max_model').value).toBe('ZWEIFEL PA18');
279
- expect(result.data.path(0, 'boeing_max_model').value).toBe('YL-15');
280
- });
281
-
282
- (databaseName !== 'bigquery' ? it.skip : it)(
283
- 'model: dates named',
284
- async () => {
285
- const result = await expressionModel
286
- .loadQuery(
287
- `
288
- query: table('malloytest.alltypes')->{
289
- group_by:
290
- t_date,
291
- t_date_month is t_date.month,
292
- t_date_year is t_date.year,
293
- t_timestamp,
294
- t_timestamp_date is t_timestamp.day,
295
- t_timestamp_hour is t_timestamp.hour,
296
- t_timestamp_minute is t_timestamp.minute,
297
- t_timestamp_second is t_timestamp.second,
298
- t_timestamp_month is t_timestamp.month,
299
- t_timestamp_year is t_timestamp.year,
300
- }
301
-
302
- `
303
- )
304
- .run();
305
- expect(result.data.path(0, 't_date').value).toEqual(
306
- new Date('2020-03-02')
307
- );
308
- expect(result.data.path(0, 't_date_month').value).toEqual(
309
- new Date('2020-03-01')
310
- );
311
- expect(result.data.path(0, 't_date_year').value).toEqual(
312
- new Date('2020-01-01')
313
- );
314
- expect(result.data.path(0, 't_timestamp').value).toEqual(
315
- new Date('2020-03-02T12:35:56.000Z')
316
- );
317
- expect(result.data.path(0, 't_timestamp_second').value).toEqual(
318
- new Date('2020-03-02T12:35:56.000Z')
319
- );
320
- expect(result.data.path(0, 't_timestamp_minute').value).toEqual(
321
- new Date('2020-03-02T12:35:00.000Z')
322
- );
323
- expect(result.data.path(0, 't_timestamp_hour').value).toEqual(
324
- new Date('2020-03-02T12:00:00.000Z')
325
- );
326
- expect(result.data.path(0, 't_timestamp_date').value).toEqual(
327
- new Date('2020-03-02')
328
- );
329
- expect(result.data.path(0, 't_timestamp_month').value).toEqual(
330
- new Date('2020-03-01')
331
- );
332
- expect(result.data.path(0, 't_timestamp_year').value).toEqual(
333
- new Date('2020-01-01')
334
- );
335
- }
336
- );
337
-
338
- it.skip('defines in model', async () => {
339
- // const result1 = await model.makeQuery(`
340
- // define a is ('malloytest.alltypes');
341
- // explore a | reduce x is count(*)
342
- // `);
343
- // const result = await model.makeQuery(`
344
- // define a is ('malloytest.alltypes');
345
- // explore a | reduce x is count(*)
346
- // `);
347
- });
348
-
349
- it('named query metadata undefined', async () => {
350
- const result = await expressionModel
351
- .loadQuery(
352
- `
353
- query: aircraft->{
354
- aggregate: aircraft_count is count()
355
- }
356
- `
357
- )
358
- .run();
359
- // TODO The result explore should really be unnamed. This test currently
360
- // inspects inner information because we have no way to have unnamed
361
- // explores today.
362
- // expect(result.getResultExplore().name).toBe(undefined);
363
- expect(result._queryResult.queryName).toBe(undefined);
364
- });
365
-
366
- it('named query metadata named', async () => {
367
- const result = await expressionModel
368
- .loadQuery(
369
- `
370
- query: aircraft->by_manufacturer
371
- `
372
- )
373
- .run();
374
- expect(result.resultExplore.name).toBe('by_manufacturer');
375
- });
376
-
377
- it('named query metadata named head of pipeline', async () => {
378
- const result = await expressionModel
379
- .loadQuery(
380
- `
381
- query: aircraft->by_manufacturer->{ aggregate: c is count()}
382
- `
383
- )
384
- .run();
385
- // TODO Same as above -- this test should check the explore name
386
- // expect(result.getResultExplore().name).toBe(undefined);
387
- expect(result._queryResult.queryName).toBe(undefined);
388
- });
389
-
390
- it('filtered explores basic', async () => {
391
- const result = await expressionModel
392
- .loadQuery(
393
- `
394
- source: b is aircraft{ where: aircraft_models.manufacturer ? ~'B%' }
395
-
396
- query: b->{aggregate: m_count is count(distinct aircraft_models.manufacturer) }
397
- `
398
- )
399
- .run();
400
- expect(result.data.path(0, 'm_count').value).toBe(63);
401
- });
402
-
403
- testIf(runtime.supportsNesting)(
404
- 'query with aliasname used twice',
405
- async () => {
406
- const result = await expressionModel
407
- .loadQuery(
408
- `
409
- query: aircraft->{
410
- group_by: first is substr(city,1,1)
411
- aggregate: aircraft_count is count()
412
- nest: aircraft is {
413
- group_by: first_two is substr(city,1,2)
414
- aggregate: aircraft_count is count()
415
- nest: aircraft is {
416
- group_by: first_three is substr(city,1,3)
417
- aggregate: aircraft_count is count()
418
- }
419
- }
420
- } -> {
421
- project:
422
- aircraft.aircraft.first_three
423
- aircraft_count
424
- order_by: 2 desc, 1
425
- }
426
- `
427
- )
428
- .run();
429
- expect(result.data.path(0, 'first_three').value).toBe('SAB');
430
- }
431
- );
432
-
433
- it.skip('join foreign_key reverse', async () => {
434
- const result = await expressionModel
435
- .loadQuery(
436
- `
437
- source: a is table('malloytest.aircraft') {
438
- primary_key: tail_num
439
- measure: aircraft_count is count()
440
- }
441
- query: table('malloytest.aircraft_models') {
442
- primary_key: aircraft_model_code
443
- join_many: a on a.aircraft_model_code
444
-
445
- some_measures is {
446
- aggregate: am_count is count()
447
- aggregate: a.aircraft_count
448
- }
449
- } -> some_measure
450
- `
451
- )
452
- .run();
453
- expect(result.data.path(0, 'first_three').value).toBe('SAN');
454
- });
455
-
456
- it('joined filtered explores', async () => {
457
- const result = await expressionModel
458
- .loadQuery(
459
- `
460
- source: a_models is table('malloytest.aircraft_models'){
461
- where: manufacturer ? ~'B%'
462
- primary_key: aircraft_model_code
463
- measure:model_count is count()
464
- }
465
-
466
- source: aircraft2 is table('malloytest.aircraft'){
467
- join_one: model is a_models with aircraft_model_code
468
- measure: aircraft_count is count()
469
- }
470
-
471
- query: aircraft2->{
472
- aggregate:
473
- model.model_count
474
- aircraft_count
475
- }
476
- `
477
- )
478
- .run();
479
- expect(result.data.path(0, 'model_count').value).toBe(244);
480
- expect(result.data.path(0, 'aircraft_count').value).toBe(3599);
481
- });
482
-
483
- it('joined filtered explores with dependancies', async () => {
484
- const result = await expressionModel
485
- .loadQuery(
486
- `
487
- source: bo_models is
488
- from(
489
- table('malloytest.aircraft_models') {? manufacturer ? ~ 'BO%' }
490
- -> { project: aircraft_model_code, manufacturer, seats }
491
- ) {
492
- primary_key: aircraft_model_code
493
- measure: bo_count is count()
494
- }
495
-
496
- source: b_models is
497
- from(
498
- table('malloytest.aircraft_models') {? manufacturer ? ~ 'B%' }
499
- -> { project: aircraft_model_code, manufacturer, seats }
500
- ) {
501
- where: bo_models.seats > 200
502
- primary_key: aircraft_model_code
503
- measure: b_count is count()
504
- join_one: bo_models with aircraft_model_code
505
- }
506
-
507
- source: models is table('malloytest.aircraft_models') {
508
- join_one: b_models with aircraft_model_code
509
- measure: model_count is count()
510
- }
511
-
512
- query: models -> {
513
- aggregate: model_count
514
- aggregate: b_models.b_count
515
- -- aggregate: b_models.bo_models.bo_count
516
- }
517
- `
518
- )
519
- .run();
520
- expect(result.data.path(0, 'model_count').value).toBe(60461);
521
- expect(result.data.path(0, 'b_count').value).toBe(355);
522
- });
523
-
524
- it('group by explore - simple group by', async () => {
525
- const result = await expressionModel
526
- .loadQuery(
527
- `
528
- query: aircraft->{
529
- group_by: aircraft_models
530
- aggregate: aircraft_count
531
- }
532
- `
533
- )
534
- .run();
535
- expect(result.data.path(0, 'aircraft_count').value).toBe(58);
536
- expect(result.data.path(0, 'aircraft_models_id').value).toBe('7102802');
537
- });
538
-
539
- it('group by explore - pipeline', async () => {
540
- const result = await expressionModel
541
- .loadQuery(
542
- `
543
- query: aircraft->{
544
- group_by: aircraft_models
545
- aggregate: aircraft_count
546
- } -> {
547
- group_by: aircraft_models.manufacturer
548
- aggregate: aircraft_count is aircraft_count.sum()
549
- }
550
- `
551
- )
552
- .run();
553
- expect(result.data.path(0, 'aircraft_count').value).toBe(1048);
554
- expect(result.data.path(0, 'manufacturer').value).toBe('CESSNA');
555
- });
556
-
557
- it('group by explore - pipeline 2 levels', async () => {
558
- const result = await expressionModel
559
- .loadQuery(
560
- `
561
- source: f is table('malloytest.flights'){
562
- join_one: a is table('malloytest.aircraft') {
563
- join_one: state_facts is table('malloytest.state_facts'){primary_key: state} with state
564
- } on tail_num = a.tail_num
565
- }
566
-
567
- query: f-> {
568
- group_by: a.state_facts
569
- aggregate: flight_count is count()
570
- } -> {
571
- group_by: state_facts.popular_name
572
- aggregate: flight_count is flight_count.sum()
573
- }
574
- `
575
- )
576
- .run();
577
- // console.log(result.data.toObject());
578
- expect(result.data.path(0, 'flight_count').value).toBe(199726);
579
- expect(result.data.path(0, 'popular_name').value).toBe('Isabella');
580
- });
581
- });
582
-
583
- describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
584
- const sqlEq = mkSqlEqWith(runtime, {
585
- malloy: `+ {
586
- dimension: friName is 'friday'
587
- dimension: friDay is 5
588
- dimension: satName is 'saturday'
589
- dimension: satDay is 6
590
- }`,
591
- });
592
-
593
- describe.skip('alternations with not-eq', () => {
594
- /*
595
- Here's the desired truth table ...
596
-
597
- x x != y | z
598
- ====== ============
599
- y false
600
- z false
601
- ^[yz] true
602
- */
603
- test('x not-eq y or z : x eq y', async () => {
604
- const result = await sqlEq('6 != (6|7)', false);
605
- expect(result).isSqlEq();
606
- });
607
- test('x not-eq y or z : x eq z', async () => {
608
- const result = await sqlEq('7 != (6|7)', false);
609
- expect(result).isSqlEq();
610
- });
611
- test('x not-eq y or z : else', async () => {
612
- const result = await sqlEq('5 != (6|7)', true);
613
- expect(result).isSqlEq();
614
- });
615
- /*
616
- Writing this the old way, should have the same truth table ...
617
- x != y & != z
618
- */
619
- test('x not-eq y and not-eq z : x eq y', async () => {
620
- const result = await sqlEq('6 != (6 & !=7)', false);
621
- expect(result).isSqlEq();
622
- });
623
- test('x not-eq y and not-eq z : x eq z', async () => {
624
- const result = await sqlEq('7 != (6 & != 7)', false);
625
- expect(result).isSqlEq();
626
- });
627
- test('x not-eq y and not-eq z : else', async () => {
628
- const result = await sqlEq('5 != (6 & !=7)', true);
629
- expect(result).isSqlEq();
630
- });
631
- });
632
-
633
- describe('string literal quoting', () => {
634
- const dq = '"';
635
- const tick = "'";
636
- const back = '\\';
637
- test('quote single character', async () => {
638
- expect(await sqlEq(`'${back}x'`, 'x')).isSqlEq();
639
- });
640
- test('quote single quote', async () => {
641
- expect(await sqlEq(`'${back}${tick}'`, tick)).isSqlEq();
642
- });
643
- test('quote double quote', async () => {
644
- await expect(runtime).queryMatches(
645
- `sql: x is {connection:"${databaseName}" select:"""SELECT 1 as x"""}
646
- query: from_sql(x) -> {
647
- project: double_quote is "${back}${dq}"
648
- }
649
- `,
650
- {double_quote: '"'}
651
- );
652
- });
653
- test('quote backslash', async () => {
654
- expect(await sqlEq(`'${back}${back}'`, back)).isSqlEq();
655
- });
656
- });
657
-
658
- test('nullish ?? operator', async () => {
659
- await expect(runtime).queryMatches(
660
- `sql: nullTest is { connection: "${databaseName}" select: """
661
- SELECT '' as null_value, '' as string_value
662
- UNION ALL SELECT null, 'correct'
663
- """ }
664
- query: from_sql(nullTest) -> {
665
- where: null_value = null
666
- project:
667
- found_null is null_value ?? 'correct',
668
- else_pass is string_value ?? 'incorrect'
669
- literal_null is null ?? 'correct'
670
- }`,
671
- {found_null: 'correct', else_pass: 'correct', literal_null: 'correct'}
672
- );
673
- });
674
-
675
- test('dimension expressions expanded with parens properly', async () => {
676
- await expect(runtime).queryMatches(
677
- `
678
- sql: tbl is { connection: "${databaseName}" select: """SELECT 1 as n"""}
679
- query: from_sql(tbl) + {
680
- dimension: fot is (false) or (true)
681
- } -> {
682
- project:
683
- no_paren is false and fot
684
- paren is false and (fot)
685
- }
686
- `,
687
- {paren: false, no_paren: false}
688
- );
689
- });
690
- });
691
-
692
- afterAll(async () => {
693
- await runtimes.closeAll();
694
- });
695
- };