@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.
- package/README.md +213 -1
- package/dist/api.spec.d.ts +1 -1
- package/dist/api.spec.js +6 -13
- package/dist/api.spec.js.map +1 -1
- package/dist/databases/all/db_index.spec.js +21 -41
- package/dist/databases/all/db_index.spec.js.map +1 -1
- package/dist/databases/all/expr.spec.js +262 -339
- package/dist/databases/all/expr.spec.js.map +1 -1
- package/dist/databases/all/functions.spec.js +37 -35
- package/dist/databases/all/functions.spec.js.map +1 -1
- package/dist/databases/all/join.spec.js +125 -169
- package/dist/databases/all/join.spec.js.map +1 -1
- package/dist/databases/all/nomodel.spec.js +335 -594
- package/dist/databases/all/nomodel.spec.js.map +1 -1
- package/dist/databases/all/orderby.spec.js +82 -128
- package/dist/databases/all/orderby.spec.js.map +1 -1
- package/dist/databases/all/sql_expressions.spec.js +27 -43
- package/dist/databases/all/sql_expressions.spec.js.map +1 -1
- package/dist/databases/all/time.spec.js +63 -103
- package/dist/databases/all/time.spec.js.map +1 -1
- package/dist/databases/bigquery/double_truncation.spec.js +1 -1
- package/dist/databases/bigquery/handexpr.spec.js +12 -12
- package/dist/databases/bigquery/injestion_time_partitioning.spec.js +22 -22
- package/dist/databases/bigquery/joined_filters.spec.js +3 -3
- package/dist/databases/bigquery/json.spec.d.ts +1 -1
- package/dist/databases/bigquery/json.spec.js +25 -45
- package/dist/databases/bigquery/json.spec.js.map +1 -1
- package/dist/databases/bigquery/malloy_query.spec.d.ts +1 -1
- package/dist/databases/bigquery/malloy_query.spec.js +47 -48
- package/dist/databases/bigquery/malloy_query.spec.js.map +1 -1
- package/dist/databases/bigquery/time.spec.js +9 -13
- package/dist/databases/bigquery/time.spec.js.map +1 -1
- package/dist/databases/bigquery/wildcard_table_names.spec.js +19 -19
- package/dist/databases/bigquery-duckdb/nested_source_table.spec.js +53 -87
- package/dist/databases/bigquery-duckdb/nested_source_table.spec.js.map +1 -1
- package/dist/databases/bigquery-postgres/multi_connection.spec.js +5 -20
- package/dist/databases/bigquery-postgres/multi_connection.spec.js.map +1 -1
- package/dist/databases/bigquery-postgres/streaming.spec.js +6 -6
- package/dist/databases/bigquery-postgres/streaming.spec.js.map +1 -1
- package/dist/databases/duckdb/duckdb.spec.js +24 -33
- package/dist/databases/duckdb/duckdb.spec.js.map +1 -1
- package/dist/databases/postgres/postgres.spec.js +46 -67
- package/dist/databases/postgres/postgres.spec.js.map +1 -1
- package/dist/jestMatcher.spec.d.ts +1 -0
- package/dist/jestMatcher.spec.js +81 -0
- package/dist/jestMatcher.spec.js.map +1 -0
- package/dist/render/render.spec.js +10 -12
- package/dist/render/render.spec.js.map +1 -1
- package/dist/tags.spec.js +22 -2
- package/dist/tags.spec.js.map +1 -1
- package/dist/util/db-jest-matchers.d.ts +17 -6
- package/dist/util/db-jest-matchers.js +81 -20
- package/dist/util/db-jest-matchers.js.map +1 -1
- package/dist/util/index.d.ts +1 -2
- package/dist/util/index.js +11 -13
- package/dist/util/index.js.map +1 -1
- package/package.json +6 -6
- package/src/api.spec.ts +7 -16
- package/src/databases/all/db_index.spec.ts +22 -48
- package/src/databases/all/expr.spec.ts +273 -431
- package/src/databases/all/functions.spec.ts +37 -35
- package/src/databases/all/join.spec.ts +130 -196
- package/src/databases/all/nomodel.spec.ts +333 -689
- package/src/databases/all/orderby.spec.ts +87 -161
- package/src/databases/all/sql_expressions.spec.ts +29 -49
- package/src/databases/all/time.spec.ts +73 -130
- package/src/databases/bigquery/double_truncation.spec.ts +1 -1
- package/src/databases/bigquery/handexpr.spec.ts +12 -12
- package/src/databases/bigquery/injestion_time_partitioning.spec.ts +22 -22
- package/src/databases/bigquery/joined_filters.spec.ts +3 -3
- package/src/databases/bigquery/json.spec.ts +25 -49
- package/src/databases/bigquery/malloy_query.spec.ts +47 -54
- package/src/databases/bigquery/time.spec.ts +13 -17
- package/src/databases/bigquery/wildcard_table_names.spec.ts +19 -19
- package/src/databases/bigquery-duckdb/nested_source_table.spec.ts +56 -98
- package/src/databases/bigquery-postgres/multi_connection.spec.ts +5 -23
- package/src/databases/bigquery-postgres/streaming.spec.ts +12 -6
- package/src/databases/duckdb/duckdb.spec.ts +31 -43
- package/src/databases/postgres/postgres.spec.ts +54 -84
- package/src/jestMatcher.spec.ts +88 -0
- package/src/render/render.spec.ts +10 -12
- package/src/tags.spec.ts +22 -2
- package/src/util/db-jest-matchers.ts +106 -32
- 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
|
-
|
|
32
|
-
|
|
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) {
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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:
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
|
|
195
|
-
|
|
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
|
-
|
|
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(
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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
|
-
|
|
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
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
)
|
|
303
|
-
|
|
304
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
376
|
-
.
|
|
377
|
-
|
|
378
|
-
|
|
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
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
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
|
-
|
|
416
|
-
|
|
417
|
-
.
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
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
|
-
|
|
428
|
-
|
|
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
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
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
|
-
|
|
450
|
-
|
|
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
|
|
477
|
-
|
|
478
|
-
.
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
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
|
-
|
|
510
|
-
|
|
511
|
-
|
|
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
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
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
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
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
|
-
|
|
540
|
-
|
|
541
|
-
|
|
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
|
-
|
|
551
|
-
|
|
552
|
-
|
|
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
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
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
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
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
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
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
|
-
|
|
602
|
-
.
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
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
|
-
|
|
620
|
-
|
|
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(
|
|
688
|
-
`
|
|
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(
|
|
703
|
-
`
|
|
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
|
-
|
|
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(
|
|
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
|
|