@malloydata/malloy-tests 0.0.95-dev231019211822 → 0.0.95

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 (84) hide show
  1. package/README.md +213 -1
  2. package/dist/api.spec.d.ts +1 -1
  3. package/dist/api.spec.js +6 -13
  4. package/dist/api.spec.js.map +1 -1
  5. package/dist/databases/all/db_index.spec.js +21 -41
  6. package/dist/databases/all/db_index.spec.js.map +1 -1
  7. package/dist/databases/all/expr.spec.js +262 -339
  8. package/dist/databases/all/expr.spec.js.map +1 -1
  9. package/dist/databases/all/functions.spec.js +37 -35
  10. package/dist/databases/all/functions.spec.js.map +1 -1
  11. package/dist/databases/all/join.spec.js +125 -169
  12. package/dist/databases/all/join.spec.js.map +1 -1
  13. package/dist/databases/all/nomodel.spec.js +335 -594
  14. package/dist/databases/all/nomodel.spec.js.map +1 -1
  15. package/dist/databases/all/orderby.spec.js +82 -128
  16. package/dist/databases/all/orderby.spec.js.map +1 -1
  17. package/dist/databases/all/sql_expressions.spec.js +27 -43
  18. package/dist/databases/all/sql_expressions.spec.js.map +1 -1
  19. package/dist/databases/all/time.spec.js +63 -103
  20. package/dist/databases/all/time.spec.js.map +1 -1
  21. package/dist/databases/bigquery/double_truncation.spec.js +1 -1
  22. package/dist/databases/bigquery/handexpr.spec.js +12 -12
  23. package/dist/databases/bigquery/injestion_time_partitioning.spec.js +22 -22
  24. package/dist/databases/bigquery/joined_filters.spec.js +3 -3
  25. package/dist/databases/bigquery/json.spec.d.ts +1 -1
  26. package/dist/databases/bigquery/json.spec.js +25 -45
  27. package/dist/databases/bigquery/json.spec.js.map +1 -1
  28. package/dist/databases/bigquery/malloy_query.spec.d.ts +1 -1
  29. package/dist/databases/bigquery/malloy_query.spec.js +47 -48
  30. package/dist/databases/bigquery/malloy_query.spec.js.map +1 -1
  31. package/dist/databases/bigquery/time.spec.js +9 -13
  32. package/dist/databases/bigquery/time.spec.js.map +1 -1
  33. package/dist/databases/bigquery/wildcard_table_names.spec.js +19 -19
  34. package/dist/databases/bigquery-duckdb/nested_source_table.spec.js +53 -87
  35. package/dist/databases/bigquery-duckdb/nested_source_table.spec.js.map +1 -1
  36. package/dist/databases/bigquery-postgres/multi_connection.spec.js +5 -20
  37. package/dist/databases/bigquery-postgres/multi_connection.spec.js.map +1 -1
  38. package/dist/databases/bigquery-postgres/streaming.spec.js +6 -6
  39. package/dist/databases/bigquery-postgres/streaming.spec.js.map +1 -1
  40. package/dist/databases/duckdb/duckdb.spec.js +24 -33
  41. package/dist/databases/duckdb/duckdb.spec.js.map +1 -1
  42. package/dist/databases/postgres/postgres.spec.js +46 -67
  43. package/dist/databases/postgres/postgres.spec.js.map +1 -1
  44. package/dist/jestMatcher.spec.d.ts +1 -0
  45. package/dist/jestMatcher.spec.js +81 -0
  46. package/dist/jestMatcher.spec.js.map +1 -0
  47. package/dist/render/render.spec.js +10 -12
  48. package/dist/render/render.spec.js.map +1 -1
  49. package/dist/tags.spec.js +22 -2
  50. package/dist/tags.spec.js.map +1 -1
  51. package/dist/util/db-jest-matchers.d.ts +17 -6
  52. package/dist/util/db-jest-matchers.js +81 -20
  53. package/dist/util/db-jest-matchers.js.map +1 -1
  54. package/dist/util/index.d.ts +1 -2
  55. package/dist/util/index.js +11 -13
  56. package/dist/util/index.js.map +1 -1
  57. package/package.json +6 -6
  58. package/src/api.spec.ts +7 -16
  59. package/src/databases/all/db_index.spec.ts +22 -48
  60. package/src/databases/all/expr.spec.ts +273 -431
  61. package/src/databases/all/functions.spec.ts +37 -35
  62. package/src/databases/all/join.spec.ts +130 -196
  63. package/src/databases/all/nomodel.spec.ts +333 -689
  64. package/src/databases/all/orderby.spec.ts +87 -161
  65. package/src/databases/all/sql_expressions.spec.ts +29 -49
  66. package/src/databases/all/time.spec.ts +73 -130
  67. package/src/databases/bigquery/double_truncation.spec.ts +1 -1
  68. package/src/databases/bigquery/handexpr.spec.ts +12 -12
  69. package/src/databases/bigquery/injestion_time_partitioning.spec.ts +22 -22
  70. package/src/databases/bigquery/joined_filters.spec.ts +3 -3
  71. package/src/databases/bigquery/json.spec.ts +25 -49
  72. package/src/databases/bigquery/malloy_query.spec.ts +47 -54
  73. package/src/databases/bigquery/time.spec.ts +13 -17
  74. package/src/databases/bigquery/wildcard_table_names.spec.ts +19 -19
  75. package/src/databases/bigquery-duckdb/nested_source_table.spec.ts +56 -98
  76. package/src/databases/bigquery-postgres/multi_connection.spec.ts +5 -23
  77. package/src/databases/bigquery-postgres/streaming.spec.ts +12 -6
  78. package/src/databases/duckdb/duckdb.spec.ts +31 -43
  79. package/src/databases/postgres/postgres.spec.ts +54 -84
  80. package/src/jestMatcher.spec.ts +88 -0
  81. package/src/render/render.spec.ts +10 -12
  82. package/src/tags.spec.ts +22 -2
  83. package/src/util/db-jest-matchers.ts +106 -32
  84. package/src/util/index.ts +16 -14
@@ -28,150 +28,116 @@ import {databasesFromEnvironmentOr, mkSqlEqWith, testIf} from '../../util';
28
28
 
29
29
  const runtimes = new RuntimeList(databasesFromEnvironmentOr(allDatabases));
30
30
 
31
- const expressionModelText = `
32
- source: aircraft_models is table('malloytest.aircraft_models') extend {
31
+ function modelText(databaseName: string): string {
32
+ return `
33
+ source: aircraft_models is ${databaseName}.table('malloytest.aircraft_models') extend {
33
34
  primary_key: aircraft_model_code
34
35
  measure:
35
36
  aircraft_model_count is count(),
36
37
  total_seats is sum(seats),
37
- boeing_seats is sum(seats) {? manufacturer ? 'BOEING'},
38
+ boeing_seats is sum(seats) { where: manufacturer ? 'BOEING'},
38
39
  percent_boeing is boeing_seats / total_seats * 100,
39
40
  percent_boeing_floor is floor(boeing_seats / total_seats * 100),
40
41
  dimension: seats_bucketed is floor(seats/20)*20.0
41
42
  }
42
43
 
43
- source: aircraft is table('malloytest.aircraft') extend {
44
+ source: aircraft is ${databaseName}.table('malloytest.aircraft') extend {
44
45
  primary_key: tail_num
45
46
  join_one: aircraft_models with aircraft_model_code
46
47
  measure: aircraft_count is count()
47
- query: by_manufacturer is {
48
+ view: by_manufacturer is {
48
49
  top: 5
49
50
  group_by: aircraft_models.manufacturer
50
51
  aggregate: aircraft_count
51
52
  }
52
53
  }
53
54
  `;
55
+ }
54
56
 
55
57
  describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
56
- const expressionModel = runtime.loadModel(expressionModelText);
58
+ const expressionModel = runtime.loadModel(modelText(databaseName));
57
59
  // basic calculations for sum, filtered sum, without a join.
58
60
  it('basic calculations', async () => {
59
- const result = await expressionModel
60
- .loadQuery(
61
- `
62
- query: aircraft_models->{
63
- aggregate:
64
- total_seats,
65
- total_seats2 is sum(seats),
66
- boeing_seats,
67
- boeing_seats2 is sum(seats) {? manufacturer ? 'BOEING'},
68
- boeing_seats3 is total_seats {? manufacturer ? 'BOEING'},
69
- percent_boeing,
70
- percent_boeing2 is boeing_seats / total_seats * 100,
71
- -- percent_boeing_floor,
72
- -- percent_boeing_floor2 is FLOOR(boeing_seats / total_seats * 100)
73
- }
74
- `
75
- )
76
- .run();
77
- expect(result.data.path(0, 'total_seats').value).toBe(452415);
78
- expect(result.data.path(0, 'total_seats2').value).toBe(452415);
79
- expect(result.data.path(0, 'boeing_seats').value).toBe(252771);
80
- expect(result.data.path(0, 'boeing_seats2').value).toBe(252771);
81
- expect(result.data.path(0, 'boeing_seats3').value).toBe(252771);
82
- expect(Math.floor(result.data.path(0, 'percent_boeing').number.value)).toBe(
83
- 55
84
- );
85
- expect(
86
- Math.floor(result.data.path(0, 'percent_boeing2').number.value)
87
- ).toBe(55);
88
- // expect(result.data.path(0, "percent_boeing_floor").value).toBe(55);
89
- // expect(result.data.path(0, "percent_boeing_floor2").value).toBe(55);
61
+ await expect(`
62
+ run: aircraft_models->{
63
+ aggregate:
64
+ total_seats,
65
+ total_seats2 is sum(seats),
66
+ boeing_seats,
67
+ boeing_seats2 is sum(seats) { where: manufacturer ? 'BOEING'},
68
+ boeing_seats3 is total_seats { where: manufacturer ? 'BOEING'},
69
+ percent_boeing_floor,
70
+ }
71
+ `).malloyResultMatches(expressionModel, {
72
+ total_seats: 452415,
73
+ total_seats2: 452415,
74
+ boeing_seats: 252771,
75
+ boeing_seats2: 252771,
76
+ boeing_seats3: 252771,
77
+ percent_boeing_floor: 55,
78
+ });
90
79
  });
91
80
 
92
- // Floor is broken (doesn't compile because the expression returned isn't an aggregate.)
81
+ // Floor was broken (wouldn't compile because the expression returned isn't an aggregate.)
93
82
  it('Floor() -or any function bustage with aggregates', async () => {
94
- const result = await expressionModel
95
- .loadQuery(
96
- `
97
- query: aircraft_models->{
98
- aggregate:
99
- percent_boeing_floor
100
- percent_boeing_floor2 is FLOOR(boeing_seats / total_seats * 100)
101
- }
102
- `
103
- )
104
- .run();
105
- expect(result.data.path(0, 'percent_boeing_floor').value).toBe(55);
106
- expect(result.data.path(0, 'percent_boeing_floor2').value).toBe(55);
83
+ await expect(`
84
+ run: aircraft_models->{
85
+ aggregate:
86
+ percent_boeing_floor
87
+ percent_boeing_floor2 is floor(boeing_seats / total_seats * 100)
88
+ }
89
+ `).malloyResultMatches(expressionModel, {
90
+ percent_boeing_floor: 55,
91
+ percent_boeing_floor2: 55,
92
+ });
107
93
  });
108
94
 
109
95
  // Model based version of sums.
110
96
  it('model: expression fixups.', async () => {
111
- const result = await expressionModel
112
- .loadQuery(
113
- `
114
- query: aircraft->{
115
- aggregate:
116
- aircraft_models.total_seats
117
- aircraft_models.boeing_seats
118
- }
119
- `
120
- )
121
- .run();
122
- expect(result.data.path(0, 'total_seats').value).toBe(18294);
123
- expect(result.data.path(0, 'boeing_seats').value).toBe(6244);
97
+ await expect(`
98
+ run: aircraft->{
99
+ aggregate:
100
+ aircraft_models.total_seats
101
+ aircraft_models.boeing_seats
102
+ }
103
+ `).malloyResultMatches(expressionModel, {
104
+ total_seats: 18294,
105
+ boeing_seats: 6244,
106
+ });
124
107
  });
125
108
 
126
109
  // turtle expressions
127
110
  it('model: turtle', async () => {
128
- const result = await expressionModel
129
- .loadQuery(
130
- `
131
- query: aircraft->by_manufacturer
132
- `
133
- )
134
- .run();
135
- expect(result.data.path(0, 'manufacturer').value).toBe('CESSNA');
111
+ await expect('run: aircraft->by_manufacturer').malloyResultMatches(
112
+ expressionModel,
113
+ {manufacturer: 'CESSNA'}
114
+ );
136
115
  });
137
116
 
138
117
  // filtered turtle expressions
139
118
  testIf(runtime.supportsNesting)('model: filtered turtle', async () => {
140
- const result = await expressionModel
141
- .loadQuery(
142
- `
143
- query: aircraft->{
144
- nest: b is by_manufacturer{? aircraft_models.manufacturer ?~'B%'}
145
- }
146
- `
147
- )
148
- .run();
149
- expect(result.data.path(0, 'b', 0, 'manufacturer').value).toBe('BEECH');
119
+ await expect(`
120
+ run: aircraft->{
121
+ nest: b is by_manufacturer refine { where: aircraft_models.manufacturer ?~'B%'}
122
+ }
123
+ `).malloyResultMatches(expressionModel, {'b.manufacturer': 'BEECH'});
150
124
  });
151
125
 
152
126
  // having.
153
127
  it('model: simple having', async () => {
154
- const result = await expressionModel
155
- .loadQuery(
156
- `
157
- query: aircraft->{
158
- having: aircraft_count >90
159
- group_by: state
160
- aggregate: aircraft_count
161
- order_by: 2
162
- }
163
- `
164
- )
165
- .run();
166
- expect(result.data.path(0, 'aircraft_count').value).toBe(91);
128
+ await expect(`
129
+ run: aircraft->{
130
+ having: aircraft_count >90
131
+ group_by: state
132
+ aggregate: aircraft_count
133
+ order_by: 2
134
+ }
135
+ `).malloyResultMatches(expressionModel, {aircraft_count: 91});
167
136
  });
168
137
 
169
- testIf(runtime.supportsNesting)('model: turtle having2', async () => {
170
- const result = await expressionModel
171
- .loadQuery(
172
- `
173
- -- hacking a null test for now
174
- query: aircraft->{
138
+ testIf(runtime.supportsNesting)('model: having in a nest', async () => {
139
+ await expect(`
140
+ run: aircraft->{
175
141
  top: 10
176
142
  order_by: 1
177
143
  where: region != NULL
@@ -184,17 +150,12 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
184
150
  aggregate: aircraft_count
185
151
  }
186
152
  }
187
- `
188
- )
189
- .run();
190
- expect(result.data.path(0, 'by_state', 0, 'state').value).toBe('VA');
153
+ `).malloyResultMatches(expressionModel, {'by_state.state': 'VA'});
191
154
  });
192
155
 
193
156
  testIf(runtime.supportsNesting)('model: turtle having on main', async () => {
194
- const result = await expressionModel
195
- .loadQuery(
196
- `
197
- query: aircraft->{
157
+ await expect(`
158
+ run: aircraft->{
198
159
  order_by: 2 asc
199
160
  having: aircraft_count ? >500
200
161
  group_by: region
@@ -212,129 +173,94 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
212
173
  }
213
174
  }
214
175
  }
215
- `
216
- )
217
- .run();
218
- expect(result.data.path(0, 'by_state', 0, 'by_city', 0, 'city').value).toBe(
219
- 'ALBUQUERQUE'
220
- );
176
+ `).malloyResultMatches(expressionModel, {
177
+ 'by_state.by_city.city': 'ALBUQUERQUE',
178
+ });
221
179
  });
222
180
 
223
181
  // bigquery doesn't like to partition by floats,
224
182
  testIf(runtime.supportsNesting)(
225
183
  'model: having float group by partition',
226
184
  async () => {
227
- await expect(runtime).queryMatches(
228
- `${expressionModelText}
229
- query: aircraft_models->{
230
- order_by: 1
231
- where: seats_bucketed > 0
232
- having: aircraft_model_count > 400
233
- group_by: seats_bucketed
234
- aggregate: aircraft_model_count
235
- nest: foo is {
236
- group_by: engines
185
+ await expect(`${modelText(databaseName)}
186
+ run: aircraft_models->{
187
+ order_by: 1
188
+ where: seats_bucketed > 0
189
+ having: aircraft_model_count > 400
190
+ group_by: seats_bucketed
237
191
  aggregate: aircraft_model_count
238
- }
239
- }`,
240
- {aircraft_model_count: 448}
241
- );
192
+ nest: foo is {
193
+ group_by: engines
194
+ aggregate: aircraft_model_count
195
+ }
196
+ }`).malloyResultMatches(runtime, {aircraft_model_count: 448});
242
197
  }
243
198
  );
244
199
 
245
200
  it('model: aggregate functions distinct min max', async () => {
246
- const result = await expressionModel
247
- .loadQuery(
248
- `
249
- query: aircraft_models->{
250
- aggregate:
251
- distinct_seats is count(seats),
252
- boeing_distinct_seats is count(seats) {?manufacturer ? 'BOEING'},
253
- min_seats is min(seats),
254
- cessna_min_seats is min(seats) {? manufacturer ? 'CESSNA'},
255
- max_seats is max(seats),
256
- cessna_max_seats is max(seats) {? manufacturer ? 'CESSNA'},
257
- min_code is min(aircraft_model_code),
258
- boeing_min_model is min(model) {? manufacturer ? 'BOEING'},
259
- max_model is max(model),
260
- boeing_max_model is max(model) {? manufacturer ? 'BOEING'},
261
- }
262
- `
263
- )
264
- .run();
265
- expect(result.data.path(0, 'distinct_seats').value).toBe(187);
266
- expect(result.data.path(0, 'boeing_distinct_seats').value).toBe(85);
267
- expect(result.data.path(0, 'min_seats').value).toBe(0);
268
- expect(result.data.path(0, 'cessna_min_seats').value).toBe(1);
269
- expect(result.data.path(0, 'max_seats').value).toBe(660);
270
- expect(result.data.path(0, 'min_code').value).toBe('0030109');
271
- expect(result.data.path(0, 'cessna_max_seats').value).toBe(14);
272
- expect(result.data.path(0, 'boeing_min_model').value).toBe('100');
273
- expect(result.data.path(0, 'max_model').value).toBe('ZWEIFEL PA18');
274
- expect(result.data.path(0, 'boeing_max_model').value).toBe('YL-15');
201
+ await expect(`
202
+ run: aircraft_models->{
203
+ aggregate:
204
+ distinct_seats is count(seats),
205
+ boeing_distinct_seats is count(seats) { where:manufacturer ? 'BOEING'},
206
+ min_seats is min(seats),
207
+ cessna_min_seats is min(seats) { where: manufacturer ? 'CESSNA'},
208
+ max_seats is max(seats),
209
+ cessna_max_seats is max(seats) { where: manufacturer ? 'CESSNA'},
210
+ min_code is min(aircraft_model_code),
211
+ boeing_min_model is min(model) { where: manufacturer ? 'BOEING'},
212
+ max_model is max(model),
213
+ boeing_max_model is max(model) { where: manufacturer ? 'BOEING'},
214
+ }
215
+ `).malloyResultMatches(expressionModel, {
216
+ distinct_seats: 187,
217
+ boeing_distinct_seats: 85,
218
+ min_seats: 0,
219
+ cessna_min_seats: 1,
220
+ max_seats: 660,
221
+ min_code: '0030109',
222
+ cessna_max_seats: 14,
223
+ boeing_min_model: '100',
224
+ max_model: 'ZWEIFEL PA18',
225
+ boeing_max_model: 'YL-15',
226
+ });
275
227
  });
276
228
 
277
- (databaseName !== 'bigquery' ? it.skip : it)(
278
- 'model: dates named',
279
- async () => {
280
- const result = await expressionModel
281
- .loadQuery(
282
- `
283
- query: table('malloytest.alltypes')->{
284
- group_by:
285
- t_date,
286
- t_date_month is t_date.month,
287
- t_date_year is t_date.year,
288
- t_timestamp,
289
- t_timestamp_date is t_timestamp.day,
290
- t_timestamp_hour is t_timestamp.hour,
291
- t_timestamp_minute is t_timestamp.minute,
292
- t_timestamp_second is t_timestamp.second,
293
- t_timestamp_month is t_timestamp.month,
294
- t_timestamp_year is t_timestamp.year,
295
- }
296
-
297
- `
298
- )
299
- .run();
300
- expect(result.data.path(0, 't_date').value).toEqual(
301
- new Date('2020-03-02')
302
- );
303
- expect(result.data.path(0, 't_date_month').value).toEqual(
304
- new Date('2020-03-01')
305
- );
306
- expect(result.data.path(0, 't_date_year').value).toEqual(
307
- new Date('2020-01-01')
308
- );
309
- expect(result.data.path(0, 't_timestamp').value).toEqual(
310
- new Date('2020-03-02T12:35:56.000Z')
311
- );
312
- expect(result.data.path(0, 't_timestamp_second').value).toEqual(
313
- new Date('2020-03-02T12:35:56.000Z')
314
- );
315
- expect(result.data.path(0, 't_timestamp_minute').value).toEqual(
316
- new Date('2020-03-02T12:35:00.000Z')
317
- );
318
- expect(result.data.path(0, 't_timestamp_hour').value).toEqual(
319
- new Date('2020-03-02T12:00:00.000Z')
320
- );
321
- expect(result.data.path(0, 't_timestamp_date').value).toEqual(
322
- new Date('2020-03-02')
323
- );
324
- expect(result.data.path(0, 't_timestamp_month').value).toEqual(
325
- new Date('2020-03-01')
326
- );
327
- expect(result.data.path(0, 't_timestamp_year').value).toEqual(
328
- new Date('2020-01-01')
329
- );
330
- }
331
- );
229
+ // TODO not sure why this test needs to be skipped on postgres, feels like an oversight
230
+ testIf(databaseName !== 'postgres')('model: dates named', async () => {
231
+ await expect(`
232
+ run: ${databaseName}.table('malloytest.alltypes')->{
233
+ group_by:
234
+ t_date,
235
+ t_date_month is t_date.month,
236
+ t_date_year is t_date.year,
237
+ t_timestamp,
238
+ t_timestamp_date is t_timestamp.day,
239
+ t_timestamp_hour is t_timestamp.hour,
240
+ t_timestamp_minute is t_timestamp.minute,
241
+ t_timestamp_second is t_timestamp.second,
242
+ t_timestamp_month is t_timestamp.month,
243
+ t_timestamp_year is t_timestamp.year,
244
+ }
245
+ `).malloyResultMatches(runtime, {
246
+ t_date: new Date('2020-03-02'),
247
+ t_date_month: new Date('2020-03-01'),
248
+ t_date_year: new Date('2020-01-01'),
249
+ t_timestamp: new Date('2020-03-02T12:35:56.000Z'),
250
+ t_timestamp_second: new Date('2020-03-02T12:35:56.000Z'),
251
+ t_timestamp_minute: new Date('2020-03-02T12:35:00.000Z'),
252
+ t_timestamp_hour: new Date('2020-03-02T12:00:00.000Z'),
253
+ t_timestamp_date: new Date('2020-03-02'),
254
+ t_timestamp_month: new Date('2020-03-01'),
255
+ t_timestamp_year: new Date('2020-01-01'),
256
+ });
257
+ });
332
258
 
333
259
  it('named query metadata undefined', async () => {
334
260
  const result = await expressionModel
335
261
  .loadQuery(
336
262
  `
337
- query: aircraft->{
263
+ run: aircraft->{
338
264
  aggregate: aircraft_count is count()
339
265
  }
340
266
  `
@@ -349,11 +275,7 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
349
275
 
350
276
  it('named query metadata named', async () => {
351
277
  const result = await expressionModel
352
- .loadQuery(
353
- `
354
- query: aircraft->by_manufacturer
355
- `
356
- )
278
+ .loadQuery('run: aircraft->by_manufacturer')
357
279
  .run();
358
280
  expect(result.resultExplore.name).toBe('by_manufacturer');
359
281
  });
@@ -362,7 +284,7 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
362
284
  const result = await expressionModel
363
285
  .loadQuery(
364
286
  `
365
- query: aircraft->by_manufacturer->{ aggregate: c is count()}
287
+ run: aircraft->by_manufacturer->{ aggregate: c is count()}
366
288
  `
367
289
  )
368
290
  .run();
@@ -372,84 +294,57 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
372
294
  });
373
295
 
374
296
  it('filtered explores basic', async () => {
375
- const result = await expressionModel
376
- .loadQuery(
377
- `
378
- source: b is aircraft{ where: aircraft_models.manufacturer ? ~'B%' }
379
-
380
- query: b->{aggregate: m_count is count(aircraft_models.manufacturer) }
381
- `
382
- )
383
- .run();
384
- expect(result.data.path(0, 'm_count').value).toBe(63);
297
+ await expect(`
298
+ run: aircraft extend { where: aircraft_models.manufacturer ? ~'B%' }
299
+ -> {aggregate: m_count is count(aircraft_models.manufacturer) }
300
+ `).malloyResultMatches(expressionModel, {m_count: 63});
385
301
  });
386
302
 
387
303
  it('sql cast', async () => {
388
- const result = await expressionModel
389
- .loadQuery(
390
- `
391
- query: aircraft -> {
392
- group_by: a is "312"::"integer"
393
- }
394
- `
395
- )
396
- .run();
397
- expect(result.data.path(0, 'a').isNumber()).toBe(true);
398
- expect(result.data.path(0, 'a').number.value).toBe(312);
399
-
400
- if (runtime.connection.name !== 'postgres') {
401
- const result = await expressionModel
402
- .loadQuery(
403
- `
404
- query: aircraft -> {
405
- group_by: a is "312":::"integer"
406
- }
407
- `
408
- )
409
- .run();
410
- expect(result.data.path(0, 'a').isNumber()).toBe(true);
411
- expect(result.data.path(0, 'a').number.value).toBe(312);
412
- }
304
+ await expect(`
305
+ run: aircraft -> {
306
+ group_by: a is "312"::"integer"
307
+ }
308
+ `).malloyResultMatches(expressionModel, {a: 312});
413
309
  });
414
310
 
415
- it('many_field.sum() has correct locality', async () => {
416
- const result = await expressionModel
417
- .loadQuery(
418
- `
419
-
420
- source: a is table('malloytest.aircraft')
421
-
422
- source: am is table('malloytest.aircraft_models') extend {
423
- join_many: a on a.aircraft_model_code = a.aircraft_model_code
424
- dimension: a_year_built is a.year_built
425
- }
311
+ testIf(runtime.connection.name !== 'postgres')('sql safe cast', async () => {
312
+ await expect(`
313
+ run: ${databaseName}.sql('SELECT 1') -> { select:
314
+ bad_date is '123':::date
315
+ bad_number is 'abc':::number
316
+ good_number is "312":::"integer"
317
+ }
318
+ `).malloyResultMatches(expressionModel, {
319
+ bad_date: null,
320
+ bad_number: null,
321
+ good_number: 312,
322
+ });
323
+ });
426
324
 
427
- // run: a -> {
428
- // aggregate: avg_year_built is avg(year_built)
429
- // }
325
+ it('many_field.sum() has correct locality', async () => {
326
+ await expect(`
327
+ source: a is ${databaseName}.table('malloytest.aircraft')
328
+ source: am is ${databaseName}.table('malloytest.aircraft_models') extend {
329
+ join_many: a on a.aircraft_model_code = a.aircraft_model_code
330
+ dimension: a_year_built is a.year_built
331
+ }
430
332
 
431
- run: am -> {
432
- aggregate: avg_a_year_built1 is a_year_built.avg()
433
- aggregate: avg_a_year_built2 is a.avg(a_year_built)
434
- }
435
- `
436
- )
437
- .run();
438
- expect(
439
- Math.floor(result.data.path(0, 'avg_a_year_built1').number.value)
440
- ).toBe(1969);
441
- expect(
442
- Math.floor(result.data.path(0, 'avg_a_year_built2').number.value)
443
- ).toBe(1969);
333
+ run: am -> {
334
+ aggregate: avg_a_year_built1 is floor(a_year_built.avg())
335
+ aggregate: avg_a_year_built2 is floor(a.avg(a_year_built))
336
+ }
337
+ `).malloyResultMatches(runtime, {
338
+ avg_a_year_built1: 1969,
339
+ avg_a_year_built2: 1969,
340
+ });
444
341
  });
445
342
 
446
343
  testIf(runtime.supportsNesting)(
447
344
  'query with aliasname used twice',
448
345
  async () => {
449
- const result = await expressionModel
450
- .loadQuery(
451
- `
452
- query: aircraft->{
346
+ await expect(`
347
+ run: aircraft->{
453
348
  group_by: first is substr(city,1,1)
454
349
  aggregate: aircraft_count is count()
455
350
  nest: aircraft is {
@@ -466,166 +361,118 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
466
361
  aircraft_count
467
362
  order_by: 2 desc, 1
468
363
  }
469
- `
470
- )
471
- .run();
472
- expect(result.data.path(0, 'first_three').value).toBe('SAB');
364
+ `).malloyResultMatches(expressionModel, {first_three: 'SAB'});
473
365
  }
474
366
  );
475
367
 
476
- it.skip('join foreign_key reverse', async () => {
477
- const result = await expressionModel
478
- .loadQuery(
479
- `
480
- source: a is table('malloytest.aircraft') {
481
- primary_key: tail_num
482
- measure: aircraft_count is count()
483
- }
484
- query: table('malloytest.aircraft_models') {
485
- primary_key: aircraft_model_code
486
- join_many: a on a.aircraft_model_code
487
-
488
- some_measures is {
489
- aggregate: am_count is count()
490
- aggregate: a.aircraft_count
491
- }
492
- } -> some_measure
493
- `
494
- )
495
- .run();
496
- expect(result.data.path(0, 'first_three').value).toBe('SAN');
497
- });
498
-
499
- it('joined filtered explores', async () => {
500
- const result = await expressionModel
501
- .loadQuery(
502
- `
503
- source: a_models is table('malloytest.aircraft_models'){
504
- where: manufacturer ? ~'B%'
505
- primary_key: aircraft_model_code
506
- measure:model_count is count()
507
- }
368
+ it('joined filtered sources', async () => {
369
+ await expect(`
370
+ source: a_models is ${databaseName}.table('malloytest.aircraft_models') extend {
371
+ where: manufacturer ? ~'B%'
372
+ primary_key: aircraft_model_code
373
+ measure:model_count is count()
374
+ }
508
375
 
509
- source: aircraft2 is table('malloytest.aircraft'){
510
- join_one: model is a_models with aircraft_model_code
511
- measure: aircraft_count is count()
512
- }
376
+ source: aircraft2 is ${databaseName}.table('malloytest.aircraft') extend {
377
+ join_one: model is a_models with aircraft_model_code
378
+ measure: aircraft_count is count()
379
+ }
513
380
 
514
- query: aircraft2->{
515
- aggregate:
516
- model.model_count
517
- aircraft_count
518
- }
519
- `
520
- )
521
- .run();
522
- expect(result.data.path(0, 'model_count').value).toBe(244);
523
- expect(result.data.path(0, 'aircraft_count').value).toBe(3599);
381
+ run: aircraft2->{
382
+ aggregate:
383
+ model.model_count
384
+ aircraft_count
385
+ }
386
+ `).malloyResultMatches(expressionModel, {
387
+ model_count: 244,
388
+ aircraft_count: 3599,
389
+ });
524
390
  });
525
391
 
526
392
  it('joined filtered explores with dependancies', async () => {
527
- const result = await expressionModel
528
- .loadQuery(
529
- `
530
- source: bo_models is
531
- from(
532
- table('malloytest.aircraft_models') {? manufacturer ? ~ 'BO%' }
533
- -> { select: aircraft_model_code, manufacturer, seats }
534
- ) {
393
+ await expect(`
394
+ source: bo_models is
395
+ ${databaseName}.table('malloytest.aircraft_models') extend { where: manufacturer ? ~ 'BO%' }
396
+ -> { select: aircraft_model_code, manufacturer, seats }
397
+ extend {
535
398
  primary_key: aircraft_model_code
536
399
  measure: bo_count is count()
537
400
  }
538
-
539
- source: b_models is
540
- from(
541
- table('malloytest.aircraft_models') {? manufacturer ? ~ 'B%' }
542
- -> { select: aircraft_model_code, manufacturer, seats }
543
- ) {
401
+ source: b_models is
402
+ ${databaseName}.table('malloytest.aircraft_models') extend { where: manufacturer ? ~ 'B%' }
403
+ -> { select: aircraft_model_code, manufacturer, seats }
404
+ extend {
544
405
  where: bo_models.seats > 200
545
406
  primary_key: aircraft_model_code
546
407
  measure: b_count is count()
547
408
  join_one: bo_models with aircraft_model_code
548
409
  }
549
410
 
550
- source: models is table('malloytest.aircraft_models') {
551
- join_one: b_models with aircraft_model_code
552
- measure: model_count is count()
553
- }
411
+ source: models is ${databaseName}.table('malloytest.aircraft_models') extend {
412
+ join_one: b_models with aircraft_model_code
413
+ measure: model_count is count()
414
+ }
554
415
 
555
- query: models -> {
556
- aggregate: model_count
557
- aggregate: b_models.b_count
558
- -- aggregate: b_models.bo_models.bo_count
559
- }
560
- `
561
- )
562
- .run();
563
- expect(result.data.path(0, 'model_count').value).toBe(60461);
564
- expect(result.data.path(0, 'b_count').value).toBe(355);
416
+ run: models -> {
417
+ aggregate: model_count
418
+ aggregate: b_models.b_count
419
+ -- aggregate: b_models.bo_models.bo_count
420
+ }
421
+ `).malloyResultMatches(runtime, {model_count: 60461, b_count: 355});
565
422
  });
566
423
 
567
- it('group by explore - simple group by', async () => {
568
- const result = await expressionModel
569
- .loadQuery(
570
- `
571
- query: aircraft->{
572
- group_by: aircraft_models
573
- aggregate: aircraft_count
574
- }
575
- `
576
- )
577
- .run();
578
- expect(result.data.path(0, 'aircraft_count').value).toBe(58);
579
- expect(result.data.path(0, 'aircraft_models_id').value).toBe('7102802');
424
+ it('group by join - simple group by', async () => {
425
+ await expect(`
426
+ run: aircraft->{
427
+ group_by: aircraft_models
428
+ aggregate: aircraft_count
429
+ }
430
+ `).malloyResultMatches(expressionModel, {
431
+ aircraft_models_id: '7102802',
432
+ aircraft_count: 58,
433
+ });
580
434
  });
581
435
 
582
436
  it('group by explore - pipeline', async () => {
583
- const result = await expressionModel
584
- .loadQuery(
585
- `
586
- query: aircraft->{
587
- group_by: aircraft_models
588
- aggregate: aircraft_count
589
- } -> {
590
- group_by: aircraft_models.manufacturer
591
- aggregate: aircraft_count is aircraft_count.sum()
592
- }
593
- `
594
- )
595
- .run();
596
- expect(result.data.path(0, 'aircraft_count').value).toBe(1048);
597
- expect(result.data.path(0, 'manufacturer').value).toBe('CESSNA');
437
+ await expect(`
438
+ run: aircraft->{
439
+ group_by: aircraft_models
440
+ aggregate: aircraft_count
441
+ } -> {
442
+ group_by: aircraft_models.manufacturer
443
+ aggregate: aircraft_count is aircraft_count.sum()
444
+ }
445
+ `).malloyResultMatches(expressionModel, {
446
+ aircraft_count: 1048,
447
+ manufacturer: 'CESSNA',
448
+ });
598
449
  });
599
450
 
600
451
  it('group by explore - pipeline 2 levels', async () => {
601
- const result = await expressionModel
602
- .loadQuery(
603
- `
604
- source: f is table('malloytest.flights'){
605
- join_one: a is table('malloytest.aircraft') {
606
- join_one: state_facts is table('malloytest.state_facts'){primary_key: state} with state
452
+ await expect(`
453
+ run: ${databaseName}.table('malloytest.flights') extend {
454
+ join_one: a is ${databaseName}.table('malloytest.aircraft') extend {
455
+ join_one: state_facts
456
+ is ${databaseName}.table('malloytest.state_facts') extend {primary_key: state}
457
+ with state
607
458
  } on tail_num = a.tail_num
608
- }
609
-
610
- query: f-> {
459
+ } -> {
611
460
  group_by: a.state_facts
612
461
  aggregate: flight_count is count()
613
462
  } -> {
614
463
  group_by: state_facts.popular_name
615
464
  aggregate: flight_count is flight_count.sum()
616
465
  }
617
- `
618
- )
619
- .run();
620
- // console.log(result.data.toObject());
621
- expect(result.data.path(0, 'flight_count').value).toBe(199726);
622
- expect(result.data.path(0, 'popular_name').value).toBe('Isabella');
466
+ `).malloyResultMatches(runtime, {
467
+ flight_count: 199726,
468
+ popular_name: 'Isabella',
469
+ });
623
470
  });
624
471
  });
625
472
 
626
473
  describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
627
- const sqlEq = mkSqlEqWith(runtime, {
628
- malloy: `+ {
474
+ const sqlEq = mkSqlEqWith(runtime, databaseName, {
475
+ malloy: `extend {
629
476
  dimension: friName is 'friday'
630
477
  dimension: friDay is 5
631
478
  dimension: satName is 'saturday'
@@ -684,14 +531,11 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
684
531
  expect(await sqlEq(`'${back}${tick}'`, tick)).isSqlEq();
685
532
  });
686
533
  test('quote double quote', async () => {
687
- await expect(runtime).queryMatches(
688
- `sql: x is {connection:"${databaseName}" select:"""SELECT 1 as x"""}
689
- query: from_sql(x) -> {
534
+ await expect(
535
+ `run: ${databaseName}.sql("SELECT 1") -> {
690
536
  select: double_quote is "${back}${dq}"
691
- }
692
- `,
693
- {double_quote: '"'}
694
- );
537
+ }`
538
+ ).malloyResultMatches(runtime, {double_quote: '"'});
695
539
  });
696
540
  test('quote backslash', async () => {
697
541
  expect(await sqlEq(`'${back}${back}'`, back)).isSqlEq();
@@ -699,36 +543,34 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
699
543
  });
700
544
 
701
545
  test('nullish ?? operator', async () => {
702
- await expect(runtime).queryMatches(
703
- `sql: nullTest is { connection: "${databaseName}" select: """
546
+ await expect(
547
+ `run: ${databaseName}.sql("""
704
548
  SELECT '' as null_value, '' as string_value
705
549
  UNION ALL SELECT null, 'correct'
706
- """ }
707
- query: from_sql(nullTest) -> {
550
+ """) -> {
708
551
  where: null_value = null
709
552
  select:
710
553
  found_null is null_value ?? 'correct',
711
554
  else_pass is string_value ?? 'incorrect'
712
555
  literal_null is null ?? 'correct'
713
- }`,
714
- {found_null: 'correct', else_pass: 'correct', literal_null: 'correct'}
715
- );
556
+ }`
557
+ ).malloyResultMatches(runtime, {
558
+ found_null: 'correct',
559
+ else_pass: 'correct',
560
+ literal_null: 'correct',
561
+ });
716
562
  });
717
563
 
718
564
  test('dimension expressions expanded with parens properly', async () => {
719
- await expect(runtime).queryMatches(
720
- `
721
- sql: tbl is { connection: "${databaseName}" select: """SELECT 1 as n"""}
722
- query: from_sql(tbl) + {
565
+ await expect(
566
+ `run: ${databaseName}.sql("SELECT 1") extend {
723
567
  dimension: fot is (false) or (true)
724
568
  } -> {
725
569
  select:
726
570
  no_paren is false and fot
727
571
  paren is false and (fot)
728
- }
729
- `,
730
- {paren: false, no_paren: false}
731
- );
572
+ }`
573
+ ).malloyResultMatches(runtime, {paren: false, no_paren: false});
732
574
  });
733
575
  });
734
576