@malloydata/malloy-tests 0.0.95-dev231019211822 → 0.0.95-dev231024220124

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