@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
@@ -25,13 +25,1120 @@
25
25
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
26
 
27
27
  import {RuntimeList, allDatabases} from '../../runtimes';
28
- import {databasesFromEnvironmentOr} from '../../util';
29
- import {noModelSharedTests} from '../shared/nomodel';
28
+ import {databasesFromEnvironmentOr, testIf} from '../../util';
29
+ import '../../util/db-jest-matchers';
30
30
 
31
31
  const runtimes = new RuntimeList(databasesFromEnvironmentOr(allDatabases));
32
32
 
33
- /*
34
- * This test file reuses common tests definitions.
35
- * For actual test development please go to: test/src/databases/shared/nomodel.spec.ts
36
- */
37
- noModelSharedTests(runtimes);
33
+ // No prebuilt shared model, each test is complete. Makes debugging easier.
34
+ function rootDbPath(databaseName: string) {
35
+ return databaseName === 'bigquery' ? 'malloy-data.' : '';
36
+ }
37
+
38
+ // TODO: Figure out how to generalize this.
39
+ function getSplitFunction(db: string) {
40
+ return {
41
+ 'bigquery': (column: string, splitChar: string) =>
42
+ `split(${column}, '${splitChar}')`,
43
+ 'postgres': (column: string, splitChar: string) =>
44
+ `string_to_array(${column}, '${splitChar}')`,
45
+ 'duckdb': (column: string, splitChar: string) =>
46
+ `string_to_array(${column}, '${splitChar}')`,
47
+ 'duckdb_wasm': (column: string, splitChar: string) =>
48
+ `string_to_array(${column}, '${splitChar}')`,
49
+ }[db];
50
+ }
51
+
52
+ afterAll(async () => {
53
+ await runtimes.closeAll();
54
+ });
55
+
56
+ runtimes.runtimeMap.forEach((runtime, databaseName) => {
57
+ // Issue: #151
58
+ it(`unknown dialect - ${databaseName}`, async () => {
59
+ const result = await runtime
60
+ .loadQuery(
61
+ `
62
+ query: q is table('malloytest.aircraft')->{
63
+ where: state != null
64
+ group_by: state
65
+ }
66
+
67
+ source: r is from(->q){
68
+ query: foo is {
69
+ order_by: 1 desc
70
+ group_by: state
71
+ }
72
+ }
73
+
74
+ query: r->foo
75
+ `
76
+ )
77
+ .run();
78
+ // console.log(result.data.toObject());
79
+ expect(result.data.path(0, 'state').value).toBe('WY');
80
+ });
81
+
82
+ // Issue #149
83
+ it(`refine query from query - ${databaseName}`, async () => {
84
+ const result = await runtime
85
+ .loadQuery(
86
+ `
87
+ query: from(
88
+ table('malloytest.state_facts')->{group_by: state; order_by: 1 desc; limit: 1}
89
+ )
90
+ {
91
+ dimension: lower_state is lower(state)
92
+ }
93
+ -> {project: lower_state}
94
+ `
95
+ )
96
+ .run();
97
+ // console.log(result.data.toObject());
98
+ expect(result.data.path(0, 'lower_state').value).toBe('wy');
99
+ });
100
+
101
+ // issue #157
102
+ it(`source- not -found - ${databaseName}`, async () => {
103
+ // console.log(result.data.toObject());
104
+ let error;
105
+ try {
106
+ await runtime
107
+ .loadQuery(
108
+ `
109
+ source: foo is table('malloytest.state_facts'){primary_key: state}
110
+ query: foox->{aggregate: c is count()}
111
+ `
112
+ )
113
+ .run();
114
+ } catch (e) {
115
+ error = e;
116
+ }
117
+ expect(error.toString()).not.toContain('Unknown Dialect');
118
+ });
119
+
120
+ it(`join_many - ${databaseName}`, async () => {
121
+ const result = await runtime
122
+ .loadQuery(
123
+ `
124
+ source: a is table('malloytest.aircraft'){
125
+ measure: avg_year is floor(avg(year_built))
126
+ }
127
+ source: m is table('malloytest.aircraft_models'){
128
+ join_many: a on a.aircraft_model_code=aircraft_model_code
129
+ measure: avg_seats is floor(avg(seats))
130
+ }
131
+ query: m->{aggregate: avg_seats, a.avg_year}
132
+ `
133
+ )
134
+ .run();
135
+ expect(result.data.value[0]['avg_year']).toBe(1969);
136
+ expect(result.data.value[0]['avg_seats']).toBe(7);
137
+ });
138
+
139
+ it(`join_many condition no primary key - ${databaseName}`, async () => {
140
+ const result = await runtime
141
+ .loadQuery(
142
+ `
143
+ source: a is table('malloytest.airports'){}
144
+ source: b is table('malloytest.state_facts') {
145
+ join_many: a on state=a.state
146
+ }
147
+ query: b->{aggregate: c is airport_count.sum()}
148
+ `
149
+ )
150
+ .run();
151
+ expect(result.data.value[0]['c']).toBe(19701);
152
+ });
153
+
154
+ it(`join_many filter multiple values - ${databaseName}`, async () => {
155
+ const result = await runtime
156
+ .loadQuery(
157
+ `
158
+ source: a is table('malloytest.airports'){
159
+ where: state = 'NH' | 'CA'
160
+ }
161
+ source: b is table('malloytest.state_facts') {
162
+ join_many: a on state=a.state
163
+ }
164
+ query: b->{
165
+ aggregate: c is airport_count.sum()
166
+ group_by: a.state
167
+ }
168
+ `
169
+ )
170
+ .run();
171
+ expect(result.data.value[0]['c']).toBe(18605);
172
+ expect(result.data.value[0]['state']).toBeNull();
173
+ expect(result.data.value[1]['c']).toBe(984);
174
+ expect(result.data.value[1]['state']).toBe('CA');
175
+ expect(result.data.value[2]['c']).toBe(112);
176
+ expect(result.data.value[2]['state']).toBe('NH');
177
+ });
178
+
179
+ it(`join_one condition no primary key - ${databaseName}`, async () => {
180
+ const result = await runtime
181
+ .loadQuery(
182
+ `
183
+ source: a is table('malloytest.state_facts'){}
184
+ source: b is table('malloytest.airports') {
185
+ join_one: a on state=a.state
186
+ }
187
+ query: b->{aggregate: c is a.airport_count.sum()}
188
+
189
+ `
190
+ )
191
+ .run();
192
+ expect(result.data.value[0]['c']).toBe(19701);
193
+ });
194
+
195
+ it(`join_one filter multiple values - ${databaseName}`, async () => {
196
+ const result = await runtime
197
+ .loadQuery(
198
+ `
199
+ source: a is table('malloytest.state_facts'){
200
+ where: state = 'TX' | 'LA'
201
+ }
202
+ source: b is table('malloytest.airports') {
203
+ join_one: a on state=a.state
204
+ }
205
+ query: b->{
206
+ aggregate: c is a.airport_count.sum()
207
+ group_by: a.state
208
+ }
209
+ `
210
+ )
211
+ .run();
212
+ // https://github.com/malloydata/malloy/pull/501#discussion_r861022857
213
+ expect(result.data.value).toHaveLength(3);
214
+ expect(result.data.value).toContainEqual({c: 1845, state: 'TX'});
215
+ expect(result.data.value).toContainEqual({c: 500, state: 'LA'});
216
+ expect(result.data.value).toContainEqual({c: 0, state: null});
217
+ });
218
+
219
+ it(`join_many cross from - ${databaseName}`, async () => {
220
+ // a cross join produces a Many to Many result.
221
+ // symmetric aggregate are needed on both sides of the join
222
+ // Check the row count and that sums on each side work properly.
223
+ const result = await runtime
224
+ .loadQuery(
225
+ `
226
+ source: a is table('malloytest.state_facts')
227
+ source: f is a{
228
+ join_cross: a
229
+ }
230
+ query: f->{
231
+ aggregate:
232
+ row_count is count(distinct concat(state,a.state))
233
+ left_count is count()
234
+ right_count is a.count()
235
+ left_sum is airport_count.sum()
236
+ right_sum is a.airport_count.sum()
237
+ }
238
+ `
239
+ )
240
+ .run();
241
+ expect(result.data.value[0]['row_count']).toBe(51 * 51);
242
+ expect(result.data.value[0]['left_sum']).toBe(19701);
243
+ expect(result.data.value[0]['right_sum']).toBe(19701);
244
+ });
245
+
246
+ it(`join_one only - ${databaseName}`, async () => {
247
+ // a cross join produces a Many to Many result.
248
+ // symmetric aggregate are needed on both sides of the join
249
+ // Check the row count and that sums on each side work properly.
250
+ const result = await runtime
251
+ .loadQuery(
252
+ `
253
+ query: q is table('malloytest.state_facts')->{
254
+ aggregate: r is airport_count.sum()
255
+ }
256
+ source: f is table('malloytest.state_facts'){
257
+ join_one: a is from(->q)
258
+ }
259
+ query: f->{
260
+ aggregate:
261
+ row_count is count(distinct concat(state,a.r))
262
+ left_sum is airport_count.sum()
263
+ right_sum is a.r.sum()
264
+ sum_sum is sum(airport_count + a.r)
265
+ }
266
+ `
267
+ )
268
+ .run();
269
+ expect(result.data.value[0]['row_count']).toBe(51);
270
+ expect(result.data.value[0]['left_sum']).toBe(19701);
271
+ expect(result.data.value[0]['right_sum']).toBe(19701);
272
+ expect(result.data.value[0]['sum_sum']).toBe(19701 + 51 * 19701);
273
+ });
274
+
275
+ it(`join_many cross ON - ${databaseName}`, async () => {
276
+ // a cross join produces a Many to Many result.
277
+ // symmetric aggregate are needed on both sides of the join
278
+ // Check the row count and that sums on each side work properly.
279
+ const result = await runtime
280
+ .loadQuery(
281
+ `
282
+ source: a is table('malloytest.state_facts')
283
+ source: f is a{
284
+ join_cross: a on a.state = 'CA' | 'NY'
285
+ }
286
+ query: f->{
287
+ aggregate:
288
+ row_count is count(distinct concat(state,a.state))
289
+ left_sum is airport_count.sum()
290
+ right_sum is a.airport_count.sum()
291
+ }
292
+ `
293
+ )
294
+ .run();
295
+ expect(result.data.value[0]['row_count']).toBe(51 * 2);
296
+ expect(result.data.value[0]['left_sum']).toBe(19701);
297
+ expect(result.data.value[0]['right_sum']).toBe(1560);
298
+ });
299
+
300
+ it(`limit - provided - ${databaseName}`, async () => {
301
+ // a cross join produces a Many to Many result.
302
+ // symmetric aggregate are needed on both sides of the join
303
+ // Check the row count and that sums on each side work properly.
304
+ const result = await runtime
305
+ .loadQuery(
306
+ `
307
+ query: table('malloytest.state_facts') -> {
308
+ group_by: state
309
+ aggregate: c is count()
310
+ limit: 3
311
+ }
312
+ `
313
+ )
314
+ .run();
315
+ expect(result.resultExplore.limit).toBe(3);
316
+ });
317
+
318
+ testIf(runtime.supportsNesting)(
319
+ `number as null- ${databaseName}`,
320
+ async () => {
321
+ // a cross join produces a Many to Many result.
322
+ // symmetric aggregate are needed on both sides of the join
323
+ // Check the row count and that sums on each side work properly.
324
+ const result = await runtime
325
+ .loadQuery(
326
+ `
327
+ source: s is table('malloytest.state_facts') + {
328
+ }
329
+ query: s-> {
330
+ group_by: state
331
+ nest: ugly is {
332
+ group_by: popular_name
333
+ aggregate: foo is NULLIF(sum(airport_count)*0,0)+1
334
+ }
335
+ }
336
+ `
337
+ )
338
+ .run();
339
+ expect(result.data.path(0, 'ugly', 0, 'foo').value).toBe(null);
340
+ }
341
+ );
342
+
343
+ // average should only include non-null values in the denominator
344
+ it(`avg ignore null- ${databaseName}`, async () => {
345
+ const result = await runtime
346
+ .loadQuery(
347
+ `
348
+ sql: one is { select: """
349
+ SELECT 2 as a
350
+ UNION ALL SELECT 4
351
+ UNION ALL SELECT null
352
+ """}
353
+
354
+ query: from_sql(one) -> {
355
+ join_cross: b is from_sql(one)
356
+ aggregate:
357
+ avg_a is a.avg()
358
+ avg_b is b.a.avg()
359
+ }
360
+ `
361
+ )
362
+ .run();
363
+ expect(result.data.value[0]['avg_a']).toBe(3);
364
+ });
365
+
366
+ it(`limit - not provided - ${databaseName}`, async () => {
367
+ // a cross join produces a Many to Many result.
368
+ // symmetric aggregate are needed on both sides of the join
369
+ // Check the row count and that sums on each side work properly.
370
+ const result = await runtime
371
+ .loadQuery(
372
+ `
373
+ query: table('malloytest.state_facts') -> {
374
+ group_by: state
375
+ aggregate: c is count()
376
+ }
377
+ `
378
+ )
379
+ .run();
380
+ expect(result.resultExplore.limit).toBe(undefined);
381
+ });
382
+
383
+ it(`limit pipeline - provided - ${databaseName}`, async () => {
384
+ // a cross join produces a Many to Many result.
385
+ // symmetric aggregate are needed on both sides of the join
386
+ // Check the row count and that sums on each side work properly.
387
+ const result = await runtime
388
+ .loadQuery(
389
+ `
390
+ query: table('malloytest.state_facts') -> {
391
+ project: state
392
+ limit: 10
393
+ }
394
+ -> {
395
+ project: state
396
+ limit: 3
397
+ }
398
+ `
399
+ )
400
+ .run();
401
+ expect(result.resultExplore.limit).toBe(3);
402
+ });
403
+
404
+ it(`ungrouped top level - ${databaseName}`, async () => {
405
+ const result = await runtime
406
+ .loadQuery(
407
+ `
408
+ source: s is table('malloytest.state_facts') + {
409
+ measure: total_births is births.sum()
410
+ measure: births_per_100k is floor(total_births/ all(total_births) * 100000)
411
+ }
412
+
413
+ query:s-> {
414
+ group_by: state
415
+ aggregate: births_per_100k
416
+ }
417
+ `
418
+ )
419
+ .run();
420
+ // console.log(result.sql);
421
+ expect(result.data.path(0, 'births_per_100k').value).toBe(9742);
422
+ });
423
+
424
+ testIf(runtime.supportsNesting)(
425
+ `ungrouped top level with nested - ${databaseName}`,
426
+ async () => {
427
+ const result = await runtime
428
+ .loadQuery(
429
+ `
430
+ source: s is table('malloytest.state_facts') + {
431
+ measure: total_births is births.sum()
432
+ measure: births_per_100k is floor(total_births/ all(total_births) * 100000)
433
+ }
434
+
435
+ query:s-> {
436
+ group_by: state
437
+ aggregate: births_per_100k
438
+ nest: by_name is {
439
+ group_by: popular_name
440
+ aggregate: total_births
441
+ }
442
+ limit: 1000
443
+ }
444
+ `
445
+ )
446
+ .run();
447
+ // console.log(result.sql);
448
+ expect(result.data.path(0, 'births_per_100k').value).toBe(9742);
449
+ }
450
+ );
451
+
452
+ it(`ungrouped - eliminate rows - ${databaseName}`, async () => {
453
+ const result = await runtime
454
+ .loadQuery(
455
+ `
456
+ source: s is table('malloytest.state_facts') + {
457
+ measure: m is all(births.sum())
458
+ where: state='CA' | 'NY'
459
+ }
460
+
461
+ query:s-> {
462
+ group_by: state
463
+ aggregate: m
464
+ }
465
+ `
466
+ )
467
+ .run();
468
+ // console.log(result.sql);
469
+ expect(result.data.toObject().length).toBe(2);
470
+ });
471
+
472
+ testIf(runtime.supportsNesting)(
473
+ `ungrouped nested with no grouping above - ${databaseName}`,
474
+ async () => {
475
+ const result = await runtime
476
+ .loadQuery(
477
+ `
478
+ source: s is table('malloytest.state_facts') + {
479
+ measure: total_births is births.sum()
480
+ measure: births_per_100k is floor(total_births/ all(total_births) * 100000)
481
+ }
482
+
483
+ query: s-> {
484
+ aggregate: total_births
485
+ nest: by_name is {
486
+ group_by: popular_name
487
+ aggregate: births_per_100k
488
+ }
489
+ }
490
+
491
+ `
492
+ )
493
+ .run();
494
+ // console.log(result.sql);
495
+ expect(result.data.path(0, 'by_name', 0, 'births_per_100k').value).toBe(
496
+ 66703
497
+ );
498
+ }
499
+ );
500
+
501
+ testIf(runtime.supportsNesting)(
502
+ `ungrouped - partial grouping - ${databaseName}`,
503
+ async () => {
504
+ const result = await runtime
505
+ .loadQuery(
506
+ `
507
+ source: airports is table('malloytest.airports') {
508
+ measure: c is count()
509
+ }
510
+
511
+
512
+ query: airports -> {
513
+ where: state = 'TX' | 'NY'
514
+ group_by:
515
+ faa_region
516
+ state
517
+ aggregate:
518
+ c
519
+ all_ is all(c)
520
+ airport_count is c {? fac_type = 'AIRPORT'}
521
+ nest: fac_type is {
522
+ group_by: fac_type
523
+ aggregate:
524
+ c
525
+ all_ is all(c)
526
+ all_state_region is exclude(c,fac_type)
527
+ all_of_this_type is exclude(c, state, faa_region)
528
+ all_top is exclude(c, state, faa_region, fac_type)
529
+ }
530
+ }
531
+
532
+ `
533
+ )
534
+ .run();
535
+ // console.log(result.sql);
536
+ expect(result.data.path(0, 'fac_type', 0, 'all_').value).toBe(1845);
537
+ expect(result.data.path(0, 'fac_type', 0, 'all_state_region').value).toBe(
538
+ 1845
539
+ );
540
+ expect(result.data.path(0, 'fac_type', 0, 'all_of_this_type').value).toBe(
541
+ 1782
542
+ );
543
+ expect(result.data.path(0, 'fac_type', 0, 'all_top').value).toBe(2421);
544
+ }
545
+ );
546
+
547
+ testIf(runtime.supportsNesting)(
548
+ `ungrouped - all nested - ${databaseName}`,
549
+ async () => {
550
+ const result = await runtime
551
+ .loadQuery(
552
+ `
553
+ source: airports is table('malloytest.airports') {
554
+ measure: c is count()
555
+ }
556
+
557
+
558
+ query: airports -> {
559
+ where: state = 'TX' | 'NY'
560
+ group_by:
561
+ state
562
+ aggregate:
563
+ c
564
+ all_ is all(c)
565
+ airport_count is c {? fac_type = 'AIRPORT'}
566
+ nest: fac_type is {
567
+ group_by: fac_type, major
568
+ aggregate:
569
+ c
570
+ all_ is all(c)
571
+ all_major is all(c,major)
572
+ }
573
+ }
574
+
575
+
576
+ `
577
+ )
578
+ .run();
579
+ // console.log(result.sql);
580
+ expect(result.data.path(0, 'fac_type', 0, 'all_').value).toBe(1845);
581
+ expect(result.data.path(0, 'fac_type', 0, 'all_major').value).toBe(1819);
582
+ }
583
+ );
584
+
585
+ testIf(runtime.supportsNesting)(
586
+ `ungrouped nested - ${databaseName}`,
587
+ async () => {
588
+ const result = await runtime
589
+ .loadQuery(
590
+ `
591
+ source: s is table('malloytest.state_facts') + {
592
+ measure: total_births is births.sum()
593
+ measure: births_per_100k is floor(total_births/ all(total_births) * 100000)
594
+ }
595
+
596
+ query:s -> {
597
+ group_by: popular_name
598
+ nest: by_state is {
599
+ group_by: state
600
+ aggregate: births_per_100k
601
+ }
602
+ }
603
+
604
+ `
605
+ )
606
+ .run();
607
+ // console.log(result.sql);
608
+ expect(result.data.path(0, 'by_state', 0, 'births_per_100k').value).toBe(
609
+ 36593
610
+ );
611
+ }
612
+ );
613
+
614
+ testIf(runtime.supportsNesting)(
615
+ `ungrouped nested expression - ${databaseName}`,
616
+ async () => {
617
+ const result = await runtime
618
+ .loadQuery(
619
+ `
620
+ source: s is table('malloytest.state_facts') + {
621
+ measure: total_births is births.sum()
622
+ measure: births_per_100k is floor(total_births/ all(total_births) * 100000)
623
+ }
624
+
625
+ query:s -> {
626
+ group_by: upper_name is upper(popular_name)
627
+ nest: by_state is {
628
+ group_by: state
629
+ aggregate: births_per_100k
630
+ }
631
+ }
632
+
633
+ `
634
+ )
635
+ .run();
636
+ // console.log(result.sql);
637
+ expect(result.data.path(0, 'by_state', 0, 'births_per_100k').value).toBe(
638
+ 36593
639
+ );
640
+ }
641
+ );
642
+
643
+ testIf(runtime.supportsNesting)(
644
+ `ungrouped nested group by float - ${databaseName}`,
645
+ async () => {
646
+ const result = await runtime
647
+ .loadQuery(
648
+ `
649
+ source: s is table('malloytest.state_facts') + {
650
+ measure: total_births is births.sum()
651
+ measure: ug is all(total_births)
652
+ }
653
+
654
+ query:s -> {
655
+ group_by: f is floor(airport_count/300.0)
656
+ nest: by_state is {
657
+ group_by: state
658
+ aggregate: ug
659
+ }
660
+ }
661
+
662
+ `
663
+ )
664
+ .run();
665
+ // console.log(result.sql);
666
+ // console.log(JSON.stringify(result.data.toObject(), null, 2));
667
+ expect(result.data.path(0, 'by_state', 0, 'ug').value).toBe(62742230);
668
+ }
669
+ );
670
+
671
+ it(`all with parameters - basic - ${databaseName}`, async () => {
672
+ const result = await runtime
673
+ .loadQuery(
674
+ `
675
+ source: s is table('malloytest.state_facts') + {
676
+ measure: total_births is births.sum()
677
+ }
678
+
679
+ query: s -> {
680
+ group_by: popular_name, state
681
+ aggregate:
682
+ total_births
683
+ all_births is all(total_births)
684
+ all_name is exclude(total_births, state)
685
+ }
686
+
687
+ `
688
+ )
689
+ .run();
690
+ // console.log(result.sql);
691
+ // console.log(JSON.stringify(result.data.toObject(), null, 2));
692
+ expect(result.data.path(0, 'all_births').value).toBe(295727065);
693
+ expect(result.data.path(0, 'all_name').value).toBe(197260594);
694
+ });
695
+
696
+ testIf(runtime.supportsNesting)(
697
+ `all with parameters - nest - ${databaseName}`,
698
+ async () => {
699
+ const result = await runtime
700
+ .loadQuery(
701
+ `
702
+ source: s is table('malloytest.state_facts') + {
703
+ measure: total_births is births.sum()
704
+ dimension: abc is floor(airport_count/300)
705
+ }
706
+
707
+ query: s -> {
708
+ group_by: abc
709
+ aggregate: total_births
710
+ nest: by_stuff is {
711
+ group_by: popular_name, state
712
+ aggregate:
713
+ total_births
714
+ all_births is all(total_births)
715
+ all_name is exclude(total_births, state)
716
+ }
717
+ }
718
+
719
+ `
720
+ )
721
+ .run();
722
+ // console.log(result.sql);
723
+ // console.log(JSON.stringify(result.data.toObject(), null, 2));
724
+ expect(result.data.path(0, 'by_stuff', 0, 'all_births').value).toBe(
725
+ 119809719
726
+ );
727
+ expect(result.data.path(0, 'by_stuff', 0, 'all_name').value).toBe(
728
+ 61091215
729
+ );
730
+ }
731
+ );
732
+
733
+ testIf(runtime.supportsNesting)(
734
+ `single value to udf - ${databaseName}`,
735
+ async () => {
736
+ const result = await runtime
737
+ .loadQuery(
738
+ `
739
+ source: f is table('malloytest.state_facts') {
740
+ query: fun is {
741
+ aggregate: t is count()
742
+ }
743
+ -> {
744
+ project: t1 is t+1
745
+ }
746
+ }
747
+ query: f-> {
748
+ nest: fun
749
+ }
750
+ `
751
+ )
752
+ .run();
753
+ // console.log(result.sql);
754
+ expect(result.data.path(0, 'fun', 0, 't1').value).toBe(52);
755
+ }
756
+ );
757
+
758
+ testIf(runtime.supportsNesting)(
759
+ `Multi value to udf - ${databaseName}`,
760
+ async () => {
761
+ const result = await runtime
762
+ .loadQuery(
763
+ `
764
+ source: f is table('malloytest.state_facts') {
765
+ query: fun is {
766
+ group_by: one is 1
767
+ aggregate: t is count()
768
+ }
769
+ -> {
770
+ project: t1 is t+1
771
+ }
772
+ }
773
+ query: f-> {
774
+ nest: fun
775
+ }
776
+ `
777
+ )
778
+ .run();
779
+ // console.log(result.sql);
780
+ // console.log(result.data.toObject());
781
+ expect(result.data.path(0, 'fun', 0, 't1').value).toBe(52);
782
+ }
783
+ );
784
+
785
+ testIf(runtime.supportsNesting)(
786
+ `Multi value to udf group by - ${databaseName}`,
787
+ async () => {
788
+ const result = await runtime
789
+ .loadQuery(
790
+ `
791
+ source: f is table('malloytest.state_facts') {
792
+ query: fun is {
793
+ group_by: one is 1
794
+ aggregate: t is count()
795
+ }
796
+ -> {
797
+ group_by: t1 is t+1
798
+ }
799
+ }
800
+ query: f-> {
801
+ nest: fun
802
+ }
803
+ `
804
+ )
805
+ .run();
806
+ // console.log(result.sql);
807
+ // console.log(result.data.toObject());
808
+ expect(result.data.path(0, 'fun', 0, 't1').value).toBe(52);
809
+ }
810
+ );
811
+
812
+ const sql1234 = `
813
+ sql: one is {select: """
814
+ SELECT 1 as a, 2 as b
815
+ UNION ALL SELECT 3, 4
816
+ """}`;
817
+
818
+ it(`sql_block - ${databaseName}`, async () => {
819
+ const result = await runtime
820
+ .loadQuery(
821
+ `
822
+ ${sql1234}
823
+ source: eone is from_sql(one) {}
824
+
825
+ query: eone -> { project: a }
826
+ `
827
+ )
828
+ .run();
829
+ expect(result.data.value[0]['a']).toBe(1);
830
+ });
831
+
832
+ it(`sql_block no explore- ${databaseName}`, async () => {
833
+ const result = await runtime
834
+ .loadQuery(
835
+ `
836
+ ${sql1234}
837
+ query: from_sql(one) -> { project: a }
838
+ `
839
+ )
840
+ .run();
841
+ expect(result.data.value[0]['a']).toBe(1);
842
+ });
843
+
844
+ it(`sql_block with turducken- ${databaseName}`, async () => {
845
+ if (databaseName !== 'postgres') {
846
+ const turduckenQuery = `
847
+ sql: state_as_sql is {
848
+ select: """
849
+ SELECT
850
+ ROW_NUMBER() OVER (ORDER BY state_count) as row_number,
851
+ *
852
+ FROM (%{
853
+ table('malloytest.state_facts')
854
+ -> {
855
+ group_by: popular_name
856
+ aggregate: state_count is count()
857
+ }
858
+ }%)
859
+ """
860
+ }
861
+ query: from_sql(state_as_sql) -> {
862
+ project: *; where: popular_name = 'Emma'
863
+ }`;
864
+ const result = await runtime.loadQuery(turduckenQuery).run();
865
+ expect(result.data.value[0]['state_count']).toBe(6);
866
+ }
867
+ });
868
+
869
+ // it(`sql_block version- ${databaseName}`, async () => {
870
+ // const result = await runtime
871
+ // .loadQuery(
872
+ // `
873
+ // sql: one is ||
874
+ // select version() as version
875
+ // ;;
876
+
877
+ // query: from_sql(one) -> { project: version }
878
+ // `
879
+ // )
880
+ // .run();
881
+ // expect(result.data.value[0].version).toBe("something");
882
+ // });
883
+
884
+ // local declarations
885
+ it(`local declarations external query - ${databaseName}`, async () => {
886
+ const result = await runtime
887
+ .loadQuery(
888
+ `
889
+ ${sql1234}
890
+ query: from_sql(one) -> {
891
+ declare: c is a + 1
892
+ project: c
893
+ }
894
+ `
895
+ )
896
+ .run();
897
+ expect(result.data.value[0]['c']).toBe(2);
898
+ });
899
+
900
+ it(`local declarations named query - ${databaseName}`, async () => {
901
+ const result = await runtime
902
+ .loadQuery(
903
+ `
904
+ ${sql1234}
905
+ source: foo is from_sql(one) + {
906
+ query: bar is {
907
+ declare: c is a + 1
908
+ project: c
909
+ }
910
+ }
911
+
912
+ query: foo-> bar
913
+ `
914
+ )
915
+ .run();
916
+ expect(result.data.value[0]['c']).toBe(2);
917
+ });
918
+
919
+ it(`local declarations refined named query - ${databaseName}`, async () => {
920
+ const result = await runtime
921
+ .loadQuery(
922
+ `
923
+ ${sql1234}
924
+ source: foo is from_sql(one) + {
925
+ query: bar is {
926
+ declare: c is a + 1
927
+ project: c
928
+ }
929
+
930
+ query: baz is bar + {
931
+ declare: d is c + 1
932
+ project: d
933
+ }
934
+ }
935
+
936
+ query: foo-> baz
937
+ `
938
+ )
939
+ .run();
940
+ expect(result.data.value[0]['d']).toBe(3);
941
+ });
942
+
943
+ it(`regexp match- ${databaseName}`, async () => {
944
+ const result = await runtime
945
+ .loadQuery(
946
+ `
947
+ sql: one is { select: """
948
+ SELECT 'hello mom' as a, 'cheese tastes good' as b
949
+ UNION ALL SELECT 'lloyd is a bozo', 'michael likes poetry'
950
+ """}
951
+
952
+ query: from_sql(one) -> {
953
+ aggregate: llo is count() {? a ~ r'llo'}
954
+ aggregate: m2 is count() {? a !~ r'bozo'}
955
+ }
956
+ `
957
+ )
958
+ .run();
959
+ expect(result.data.value[0]['llo']).toBe(2);
960
+ expect(result.data.value[0]['m2']).toBe(1);
961
+ });
962
+
963
+ it(`substitution precidence- ${databaseName}`, async () => {
964
+ const result = await runtime
965
+ .loadQuery(
966
+ `
967
+ sql: one is {select: """
968
+ SELECT 5 as a, 2 as b
969
+ UNION ALL SELECT 3, 4
970
+ """}
971
+
972
+ query: from_sql(one) -> {
973
+ declare: c is b + 4
974
+ project: x is a * c
975
+ }
976
+ `
977
+ )
978
+ .run();
979
+ expect(result.data.value[0]['x']).toBe(30);
980
+ });
981
+
982
+ it(`array unnest - ${databaseName}`, async () => {
983
+ const result = await runtime
984
+ .loadQuery(
985
+ `
986
+ sql: atitle is {select:"""
987
+ SELECT
988
+ city,
989
+ ${getSplitFunction(databaseName)!('city', ' ')} as words
990
+ FROM ${rootDbPath(databaseName)}malloytest.aircraft
991
+ """}
992
+
993
+ source: title is from_sql(atitle){}
994
+
995
+ query: title -> {
996
+ where: words.value != null
997
+ group_by: words.value
998
+ aggregate: c is count()
999
+ }
1000
+ `
1001
+ )
1002
+ .run();
1003
+ expect(result.data.value[0]['c']).toBe(145);
1004
+ });
1005
+
1006
+ // make sure we can count the total number of elements when fanning out.
1007
+ it(`array unnest x 2 - ${databaseName}`, async () => {
1008
+ const result = await runtime
1009
+ .loadQuery(
1010
+ `
1011
+ sql: atitle is {select: """
1012
+ SELECT
1013
+ city,
1014
+ ${getSplitFunction(databaseName)!('city', ' ')} as words,
1015
+ ${getSplitFunction(databaseName)!('city', 'A')} as abreak
1016
+ FROM ${rootDbPath(databaseName)}malloytest.aircraft
1017
+ where city IS NOT null
1018
+ """}
1019
+
1020
+ source: title is from_sql(atitle){}
1021
+
1022
+ query: title -> {
1023
+ aggregate:
1024
+ b is count()
1025
+ c is words.count()
1026
+ a is abreak.count()
1027
+ }
1028
+ `
1029
+ )
1030
+ .run();
1031
+ expect(result.data.value[0]['b']).toBe(3552);
1032
+ expect(result.data.value[0]['c']).toBe(4586);
1033
+ expect(result.data.value[0]['a']).toBe(6601);
1034
+ });
1035
+
1036
+ testIf(runtime.supportsNesting)(`nest null - ${databaseName}`, async () => {
1037
+ const result = await runtime
1038
+ .loadQuery(
1039
+ `
1040
+ query: table('malloytest.airports') -> {
1041
+ where: faa_region = null
1042
+ group_by: faa_region
1043
+ aggregate: airport_count is count()
1044
+ nest: by_state is {
1045
+ where: state != null
1046
+ group_by: state
1047
+ aggregate: airport_count is count()
1048
+ }
1049
+ nest: by_state1 is {
1050
+ where: state != null
1051
+ group_by: state
1052
+ aggregate: airport_count is count()
1053
+ limit: 1
1054
+ }
1055
+ }
1056
+ `
1057
+ )
1058
+ .run();
1059
+
1060
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1061
+ const d: any = result.data.toObject();
1062
+ expect(d[0]['by_state']).not.toBe(null);
1063
+ expect(d[0]['by_state1']).not.toBe(null);
1064
+ });
1065
+
1066
+ testIf(runtime.supportsNesting)(
1067
+ `number as null- ${databaseName}`,
1068
+ async () => {
1069
+ const result = await runtime
1070
+ .loadQuery(
1071
+ `
1072
+ source: s is table('malloytest.state_facts') + {
1073
+ }
1074
+ query: s-> {
1075
+ group_by: state
1076
+ nest: ugly is {
1077
+ group_by: popular_name
1078
+ aggregate: foo is NULLIF(sum(airport_count)*0,0)+1
1079
+ }
1080
+ }
1081
+ `
1082
+ )
1083
+ .run();
1084
+ expect(result.data.path(0, 'ugly', 0, 'foo').value).toBe(null);
1085
+ }
1086
+ );
1087
+
1088
+ describe('quoting and strings', () => {
1089
+ const tick = "'";
1090
+ const back = '\\';
1091
+ test('backslash quote', async () => {
1092
+ const result = await runtime
1093
+ .loadQuery(
1094
+ `
1095
+ query: table('malloytest.state_facts') -> {
1096
+ project: tick is '${back}${tick}'
1097
+ }
1098
+ `
1099
+ )
1100
+ .run();
1101
+ expect(result.data.value[0]['tick']).toBe(tick);
1102
+ });
1103
+ test('backslash backslash', async () => {
1104
+ const result = await runtime
1105
+ .loadQuery(
1106
+ `
1107
+ query: table('malloytest.state_facts') -> {
1108
+ project: back is '${back}${back}'
1109
+ }
1110
+ `
1111
+ )
1112
+ .run();
1113
+ expect(result.data.value[0]['back']).toBe(back);
1114
+ });
1115
+
1116
+ testIf(runtime.supportsNesting)('spaces in names', async () => {
1117
+ const result = await runtime
1118
+ .loadQuery(
1119
+ `
1120
+ source: \`space race\` is table('malloytest.state_facts') {
1121
+ join_one: \`j space\` is table('malloytest.state_facts') on \`j space\`.state=state
1122
+ query: \`q u e r y\` is {
1123
+ group_by:
1124
+ \`P O P\` is popular_name
1125
+ \`J P O P\` is \`j space\`.popular_name
1126
+ aggregate: \`c o u n t\` is count()
1127
+ calculate:
1128
+ \`R O W\` is row_number()
1129
+ \`l a g\` is lag(\`P O P\`, 1)
1130
+ nest: \`by state\` is {
1131
+ group_by: \`J S\` is \`j space\`.state
1132
+ aggregate: \`c o u n t\` is count()
1133
+ }
1134
+ }
1135
+ }
1136
+
1137
+ query: \`space race\` -> \`q u e r y\`
1138
+ `
1139
+ )
1140
+ .run();
1141
+ expect(result.data.value[0]['c o u n t']).toBe(24);
1142
+ });
1143
+ });
1144
+ });