@malloydata/malloy-tests 0.0.125 → 0.0.126-dev240305182920
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/dist/databases/all/expr.spec.js +8 -5
- package/dist/databases/all/expr.spec.js.map +1 -1
- package/dist/databases/all/functions.spec.js +16 -7
- package/dist/databases/all/functions.spec.js.map +1 -1
- package/dist/databases/all/nomodel.spec.js +45 -19
- package/dist/databases/all/nomodel.spec.js.map +1 -1
- package/dist/databases/all/orderby.spec.js +1 -1
- package/dist/databases/all/orderby.spec.js.map +1 -1
- package/dist/databases/all/sql_expressions.spec.js +3 -2
- package/dist/databases/all/sql_expressions.spec.js.map +1 -1
- package/dist/databases/all/time.spec.js +7 -7
- package/dist/databases/all/time.spec.js.map +1 -1
- package/dist/runtimes.d.ts +4 -0
- package/dist/runtimes.js +50 -18
- package/dist/runtimes.js.map +1 -1
- package/dist/util/db-jest-matchers.js +4 -0
- package/dist/util/db-jest-matchers.js.map +1 -1
- package/package.json +7 -6
- package/snowflake/uploaddata.sql +267 -0
- package/src/databases/all/expr.spec.ts +35 -24
- package/src/databases/all/functions.spec.ts +13 -10
- package/src/databases/all/nomodel.spec.ts +58 -23
- package/src/databases/all/orderby.spec.ts +6 -3
- package/src/databases/all/sql_expressions.spec.ts +3 -2
- package/src/databases/all/time.spec.ts +13 -8
- package/src/runtimes.ts +57 -21
- package/src/util/db-jest-matchers.ts +8 -0
- package/tsconfig.json +3 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
-- to run
|
|
2
|
+
|
|
3
|
+
-- cd test/snowflake
|
|
4
|
+
-- snowsql -f uploadddate.sql
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
drop database malloytestdb;
|
|
8
|
+
create database malloytestdb;
|
|
9
|
+
|
|
10
|
+
use malloytestdb;
|
|
11
|
+
create schema malloytest;
|
|
12
|
+
|
|
13
|
+
CREATE OR REPLACE FILE FORMAT PARQUET_SCHEMA_DETECTION
|
|
14
|
+
TYPE = PARQUET
|
|
15
|
+
BINARY_AS_TEXT = FALSE;
|
|
16
|
+
|
|
17
|
+
PUT file://../data/duckdb/aircraft.parquet @~/staged;
|
|
18
|
+
|
|
19
|
+
CREATE OR REPLACE TABLE aircraft
|
|
20
|
+
USING TEMPLATE (
|
|
21
|
+
SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*))
|
|
22
|
+
FROM TABLE(
|
|
23
|
+
INFER_SCHEMA(
|
|
24
|
+
LOCATION=>'@~/staged/aircraft.parquet',
|
|
25
|
+
FILE_FORMAT => 'PARQUET_SCHEMA_DETECTION')
|
|
26
|
+
)
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
COPY INTO malloytest.aircraft
|
|
30
|
+
FROM '@~/staged/aircraft.parquet'
|
|
31
|
+
FILE_FORMAT = 'PARQUET_SCHEMA_DETECTION'
|
|
32
|
+
MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE
|
|
33
|
+
ON_ERROR = CONTINUE;
|
|
34
|
+
|
|
35
|
+
PUT file://../data/duckdb/aircraft_models.parquet @~/staged;
|
|
36
|
+
|
|
37
|
+
CREATE OR REPLACE TABLE aircraft_models
|
|
38
|
+
USING TEMPLATE (
|
|
39
|
+
SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*))
|
|
40
|
+
FROM TABLE(
|
|
41
|
+
INFER_SCHEMA(
|
|
42
|
+
LOCATION=>'@~/staged/aircraft_models.parquet',
|
|
43
|
+
FILE_FORMAT => 'PARQUET_SCHEMA_DETECTION')
|
|
44
|
+
)
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
COPY INTO malloytest.aircraft_models
|
|
48
|
+
FROM '@~/staged/aircraft_models.parquet'
|
|
49
|
+
FILE_FORMAT = 'PARQUET_SCHEMA_DETECTION'
|
|
50
|
+
MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE
|
|
51
|
+
ON_ERROR = CONTINUE;
|
|
52
|
+
|
|
53
|
+
PUT file://../data/duckdb/airports.parquet @~/staged;
|
|
54
|
+
|
|
55
|
+
CREATE OR REPLACE TABLE airports
|
|
56
|
+
USING TEMPLATE (
|
|
57
|
+
SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*))
|
|
58
|
+
FROM TABLE(
|
|
59
|
+
INFER_SCHEMA(
|
|
60
|
+
LOCATION=>'@~/staged/airports.parquet',
|
|
61
|
+
FILE_FORMAT => 'PARQUET_SCHEMA_DETECTION')
|
|
62
|
+
)
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
COPY INTO malloytest.airports
|
|
66
|
+
FROM '@~/staged/airports.parquet'
|
|
67
|
+
FILE_FORMAT = 'PARQUET_SCHEMA_DETECTION'
|
|
68
|
+
MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE
|
|
69
|
+
ON_ERROR = CONTINUE;
|
|
70
|
+
|
|
71
|
+
PUT file://../data/duckdb/alltypes.parquet @~/staged;
|
|
72
|
+
|
|
73
|
+
CREATE OR REPLACE TABLE alltypes
|
|
74
|
+
USING TEMPLATE (
|
|
75
|
+
SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*))
|
|
76
|
+
FROM TABLE(
|
|
77
|
+
INFER_SCHEMA(
|
|
78
|
+
LOCATION=>'@~/staged/alltypes.parquet',
|
|
79
|
+
FILE_FORMAT => 'PARQUET_SCHEMA_DETECTION')
|
|
80
|
+
)
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
COPY INTO malloytest.alltypes
|
|
84
|
+
FROM '@~/staged/alltypes.parquet'
|
|
85
|
+
FILE_FORMAT = 'PARQUET_SCHEMA_DETECTION'
|
|
86
|
+
MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE
|
|
87
|
+
ON_ERROR = CONTINUE;
|
|
88
|
+
|
|
89
|
+
PUT file://../data/duckdb/alltypes2.parquet @~/staged;
|
|
90
|
+
|
|
91
|
+
CREATE OR REPLACE TABLE alltypes2
|
|
92
|
+
USING TEMPLATE (
|
|
93
|
+
SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*))
|
|
94
|
+
FROM TABLE(
|
|
95
|
+
INFER_SCHEMA(
|
|
96
|
+
LOCATION=>'@~/staged/alltypes2.parquet',
|
|
97
|
+
FILE_FORMAT => 'PARQUET_SCHEMA_DETECTION')
|
|
98
|
+
)
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
COPY INTO malloytest.alltypes2
|
|
102
|
+
FROM '@~/staged/alltypes2.parquet'
|
|
103
|
+
FILE_FORMAT = 'PARQUET_SCHEMA_DETECTION'
|
|
104
|
+
MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE
|
|
105
|
+
ON_ERROR = CONTINUE;
|
|
106
|
+
|
|
107
|
+
PUT file://../data/duckdb/bq_medicare_test.parquet @~/staged;
|
|
108
|
+
|
|
109
|
+
CREATE OR REPLACE TABLE bq_medicare_test
|
|
110
|
+
USING TEMPLATE (
|
|
111
|
+
SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*))
|
|
112
|
+
FROM TABLE(
|
|
113
|
+
INFER_SCHEMA(
|
|
114
|
+
LOCATION=>'@~/staged/bq_medicare_test.parquet',
|
|
115
|
+
FILE_FORMAT => 'PARQUET_SCHEMA_DETECTION')
|
|
116
|
+
)
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
COPY INTO malloytest.bq_medicare_test
|
|
120
|
+
FROM '@~/staged/bq_medicare_test.parquet'
|
|
121
|
+
FILE_FORMAT = 'PARQUET_SCHEMA_DETECTION'
|
|
122
|
+
MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE
|
|
123
|
+
ON_ERROR = CONTINUE;
|
|
124
|
+
|
|
125
|
+
PUT file://../data/duckdb/carriers.parquet @~/staged;
|
|
126
|
+
|
|
127
|
+
CREATE OR REPLACE TABLE carriers
|
|
128
|
+
USING TEMPLATE (
|
|
129
|
+
SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*))
|
|
130
|
+
FROM TABLE(
|
|
131
|
+
INFER_SCHEMA(
|
|
132
|
+
LOCATION=>'@~/staged/carriers.parquet',
|
|
133
|
+
FILE_FORMAT => 'PARQUET_SCHEMA_DETECTION')
|
|
134
|
+
)
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
COPY INTO malloytest.carriers
|
|
138
|
+
FROM '@~/staged/carriers.parquet'
|
|
139
|
+
FILE_FORMAT = 'PARQUET_SCHEMA_DETECTION'
|
|
140
|
+
MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE
|
|
141
|
+
ON_ERROR = CONTINUE;
|
|
142
|
+
|
|
143
|
+
PUT file://../data/duckdb/flights.parquet @~/staged;
|
|
144
|
+
|
|
145
|
+
CREATE OR REPLACE TABLE flights
|
|
146
|
+
USING TEMPLATE (
|
|
147
|
+
SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*))
|
|
148
|
+
FROM TABLE(
|
|
149
|
+
INFER_SCHEMA(
|
|
150
|
+
LOCATION=>'@~/staged/flights.parquet',
|
|
151
|
+
FILE_FORMAT => 'PARQUET_SCHEMA_DETECTION')
|
|
152
|
+
)
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
COPY INTO malloytest.flights
|
|
156
|
+
FROM '@~/staged/flights.parquet'
|
|
157
|
+
FILE_FORMAT = 'PARQUET_SCHEMA_DETECTION'
|
|
158
|
+
MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE
|
|
159
|
+
ON_ERROR = CONTINUE;
|
|
160
|
+
|
|
161
|
+
PUT file://../data/duckdb/flights_partitioned.parquet @~/staged;
|
|
162
|
+
|
|
163
|
+
CREATE OR REPLACE TABLE flights_partitioned
|
|
164
|
+
USING TEMPLATE (
|
|
165
|
+
SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*))
|
|
166
|
+
FROM TABLE(
|
|
167
|
+
INFER_SCHEMA(
|
|
168
|
+
LOCATION=>'@~/staged/flights_partitioned.parquet',
|
|
169
|
+
FILE_FORMAT => 'PARQUET_SCHEMA_DETECTION')
|
|
170
|
+
)
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
COPY INTO malloytest.flights_partitioned
|
|
174
|
+
FROM '@~/staged/flights_partitioned.parquet'
|
|
175
|
+
FILE_FORMAT = 'PARQUET_SCHEMA_DETECTION'
|
|
176
|
+
MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE
|
|
177
|
+
ON_ERROR = CONTINUE;
|
|
178
|
+
|
|
179
|
+
PUT file://../data/duckdb/ga_sample.parquet @~/staged;
|
|
180
|
+
|
|
181
|
+
CREATE OR REPLACE TABLE ga_sample
|
|
182
|
+
USING TEMPLATE (
|
|
183
|
+
SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*))
|
|
184
|
+
FROM TABLE(
|
|
185
|
+
INFER_SCHEMA(
|
|
186
|
+
LOCATION=>'@~/staged/ga_sample.parquet',
|
|
187
|
+
FILE_FORMAT => 'PARQUET_SCHEMA_DETECTION')
|
|
188
|
+
)
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
COPY INTO malloytest.ga_sample
|
|
192
|
+
FROM '@~/staged/ga_sample.parquet'
|
|
193
|
+
FILE_FORMAT = 'PARQUET_SCHEMA_DETECTION'
|
|
194
|
+
MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE
|
|
195
|
+
ON_ERROR = CONTINUE;
|
|
196
|
+
|
|
197
|
+
PUT file://../data/duckdb/numbers.parquet @~/staged;
|
|
198
|
+
|
|
199
|
+
CREATE OR REPLACE TABLE numbers
|
|
200
|
+
USING TEMPLATE (
|
|
201
|
+
SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*))
|
|
202
|
+
FROM TABLE(
|
|
203
|
+
INFER_SCHEMA(
|
|
204
|
+
LOCATION=>'@~/staged/numbers.parquet',
|
|
205
|
+
FILE_FORMAT => 'PARQUET_SCHEMA_DETECTION')
|
|
206
|
+
)
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
COPY INTO malloytest.numbers
|
|
210
|
+
FROM '@~/staged/numbers.parquet'
|
|
211
|
+
FILE_FORMAT = 'PARQUET_SCHEMA_DETECTION'
|
|
212
|
+
MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE
|
|
213
|
+
ON_ERROR = CONTINUE;
|
|
214
|
+
|
|
215
|
+
PUT file://../data/duckdb/state_facts.parquet @~/staged;
|
|
216
|
+
|
|
217
|
+
CREATE OR REPLACE TABLE state_facts
|
|
218
|
+
USING TEMPLATE (
|
|
219
|
+
SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*))
|
|
220
|
+
FROM TABLE(
|
|
221
|
+
INFER_SCHEMA(
|
|
222
|
+
LOCATION=>'@~/staged/state_facts.parquet',
|
|
223
|
+
FILE_FORMAT => 'PARQUET_SCHEMA_DETECTION')
|
|
224
|
+
)
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
COPY INTO malloytest.state_facts
|
|
228
|
+
FROM '@~/staged/state_facts.parquet'
|
|
229
|
+
FILE_FORMAT = 'PARQUET_SCHEMA_DETECTION'
|
|
230
|
+
MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE
|
|
231
|
+
ON_ERROR = CONTINUE;
|
|
232
|
+
|
|
233
|
+
PUT file://../data/duckdb/words.parquet @~/staged;
|
|
234
|
+
|
|
235
|
+
CREATE OR REPLACE TABLE words
|
|
236
|
+
USING TEMPLATE (
|
|
237
|
+
SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*))
|
|
238
|
+
FROM TABLE(
|
|
239
|
+
INFER_SCHEMA(
|
|
240
|
+
LOCATION=>'@~/staged/words.parquet',
|
|
241
|
+
FILE_FORMAT => 'PARQUET_SCHEMA_DETECTION')
|
|
242
|
+
)
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
COPY INTO malloytest.words
|
|
246
|
+
FROM '@~/staged/words.parquet'
|
|
247
|
+
FILE_FORMAT = 'PARQUET_SCHEMA_DETECTION'
|
|
248
|
+
MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE
|
|
249
|
+
ON_ERROR = CONTINUE;
|
|
250
|
+
|
|
251
|
+
PUT file://../data/duckdb/words_bigger.parquet @~/staged;
|
|
252
|
+
|
|
253
|
+
CREATE OR REPLACE TABLE words_bigger
|
|
254
|
+
USING TEMPLATE (
|
|
255
|
+
SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*))
|
|
256
|
+
FROM TABLE(
|
|
257
|
+
INFER_SCHEMA(
|
|
258
|
+
LOCATION=>'@~/staged/words_bigger.parquet',
|
|
259
|
+
FILE_FORMAT => 'PARQUET_SCHEMA_DETECTION')
|
|
260
|
+
)
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
COPY INTO malloytest.words_bigger
|
|
264
|
+
FROM '@~/staged/words_bigger.parquet'
|
|
265
|
+
FILE_FORMAT = 'PARQUET_SCHEMA_DETECTION'
|
|
266
|
+
MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE
|
|
267
|
+
ON_ERROR = CONTINUE;
|
|
@@ -58,6 +58,9 @@ source: aircraft is ${databaseName}.table('malloytest.aircraft') extend {
|
|
|
58
58
|
describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
|
|
59
59
|
const expressionModel = runtime.loadModel(modelText(databaseName));
|
|
60
60
|
// basic calculations for sum, filtered sum, without a join.
|
|
61
|
+
|
|
62
|
+
const q = runtime.getQuoter();
|
|
63
|
+
|
|
61
64
|
it('basic calculations', async () => {
|
|
62
65
|
await expect(`
|
|
63
66
|
run: aircraft_models->{
|
|
@@ -228,8 +231,11 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
|
|
|
228
231
|
});
|
|
229
232
|
|
|
230
233
|
// TODO not sure why this test needs to be skipped on postgres, feels like an oversight
|
|
231
|
-
|
|
232
|
-
|
|
234
|
+
// NOTE: unless underlying type is stored as a timestamp snowflake does not support extraction
|
|
235
|
+
testIf(!['postgres', 'snowflake'].includes(databaseName))(
|
|
236
|
+
'model: dates named',
|
|
237
|
+
async () => {
|
|
238
|
+
await expect(`
|
|
233
239
|
run: ${databaseName}.table('malloytest.alltypes')->{
|
|
234
240
|
group_by:
|
|
235
241
|
t_date,
|
|
@@ -244,18 +250,19 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
|
|
|
244
250
|
t_timestamp_year is t_timestamp.year,
|
|
245
251
|
}
|
|
246
252
|
`).malloyResultMatches(runtime, {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
253
|
+
t_date: new Date('2020-03-02'),
|
|
254
|
+
t_date_month: new Date('2020-03-01'),
|
|
255
|
+
t_date_year: new Date('2020-01-01'),
|
|
256
|
+
t_timestamp: new Date('2020-03-02T12:35:56.000Z'),
|
|
257
|
+
t_timestamp_second: new Date('2020-03-02T12:35:56.000Z'),
|
|
258
|
+
t_timestamp_minute: new Date('2020-03-02T12:35:00.000Z'),
|
|
259
|
+
t_timestamp_hour: new Date('2020-03-02T12:00:00.000Z'),
|
|
260
|
+
t_timestamp_date: new Date('2020-03-02'),
|
|
261
|
+
t_timestamp_month: new Date('2020-03-01'),
|
|
262
|
+
t_timestamp_year: new Date('2020-01-01'),
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
);
|
|
259
266
|
|
|
260
267
|
it('named query metadata undefined', async () => {
|
|
261
268
|
const result = await expressionModel
|
|
@@ -309,19 +316,22 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
|
|
|
309
316
|
`).malloyResultMatches(expressionModel, {a: 312});
|
|
310
317
|
});
|
|
311
318
|
|
|
312
|
-
testIf(runtime.connection.name
|
|
313
|
-
|
|
319
|
+
testIf(!['postgres', 'snowflake'].includes(runtime.connection.name))(
|
|
320
|
+
'sql safe cast',
|
|
321
|
+
async () => {
|
|
322
|
+
await expect(`
|
|
314
323
|
run: ${databaseName}.sql('SELECT 1') -> { select:
|
|
315
324
|
bad_date is '123':::date
|
|
316
325
|
bad_number is 'abc':::number
|
|
317
326
|
good_number is "312":::"integer"
|
|
318
327
|
}
|
|
319
328
|
`).malloyResultMatches(expressionModel, {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
329
|
+
bad_date: null,
|
|
330
|
+
bad_number: null,
|
|
331
|
+
good_number: 312,
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
);
|
|
325
335
|
|
|
326
336
|
it('many_field.sum() has correct locality', async () => {
|
|
327
337
|
await expect(`
|
|
@@ -433,7 +443,7 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
|
|
|
433
443
|
source: a is ${databaseName}.table('malloytest.aircraft_models') extend { where: aircraft_model_code ? '0270202' }
|
|
434
444
|
|
|
435
445
|
run: a -> {
|
|
436
|
-
group_by: string_1 is sql_string(
|
|
446
|
+
group_by: string_1 is sql_string('UPPER(\${TABLE}.${q`manufacturer`})')
|
|
437
447
|
}
|
|
438
448
|
`).malloyResultMatches(expressionModel, {
|
|
439
449
|
string_1: 'AHRENS AIRCRAFT CORP.',
|
|
@@ -579,7 +589,7 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
|
|
|
579
589
|
});
|
|
580
590
|
});
|
|
581
591
|
|
|
582
|
-
it('joined filtered explores with
|
|
592
|
+
it('joined filtered explores with dependencies', async () => {
|
|
583
593
|
await expect(`
|
|
584
594
|
source: bo_models is
|
|
585
595
|
${databaseName}.table('malloytest.aircraft_models') extend { where: manufacturer ? ~ 'BO%' }
|
|
@@ -613,6 +623,7 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
|
|
|
613
623
|
});
|
|
614
624
|
|
|
615
625
|
describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
|
|
626
|
+
const q = runtime.getQuoter();
|
|
616
627
|
const sqlEq = mkSqlEqWith(runtime, databaseName, {
|
|
617
628
|
malloy: `extend {
|
|
618
629
|
dimension: friName is 'friday'
|
|
@@ -687,7 +698,7 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
|
|
|
687
698
|
test('nullish ?? operator', async () => {
|
|
688
699
|
await expect(
|
|
689
700
|
`run: ${databaseName}.sql("""
|
|
690
|
-
SELECT '' as null_value, '' as string_value
|
|
701
|
+
SELECT '' as ${q`null_value`}, '' as ${q`string_value`}
|
|
691
702
|
UNION ALL SELECT null, 'correct'
|
|
692
703
|
""") -> {
|
|
693
704
|
where: null_value = null
|
|
@@ -111,6 +111,11 @@ expressionModels.forEach((expressionModel, databaseName) => {
|
|
|
111
111
|
|
|
112
112
|
describe('concat', () => {
|
|
113
113
|
it(`works - ${databaseName}`, async () => {
|
|
114
|
+
const expected = {
|
|
115
|
+
'bigquery': 'foo2003-01-01 12:00:00+00',
|
|
116
|
+
'snowflake': 'foo2003-01-01 12:00:00.000',
|
|
117
|
+
};
|
|
118
|
+
|
|
114
119
|
await funcTestMultiple(
|
|
115
120
|
["concat('foo', 'bar')", 'foobar'],
|
|
116
121
|
["concat(1, 'bar')", '1bar'],
|
|
@@ -121,9 +126,7 @@ expressionModels.forEach((expressionModel, databaseName) => {
|
|
|
121
126
|
["concat('foo', @2003)", 'foo2003-01-01'],
|
|
122
127
|
[
|
|
123
128
|
"concat('foo', @2003-01-01 12:00:00)",
|
|
124
|
-
databaseName
|
|
125
|
-
? 'foo2003-01-01 12:00:00+00'
|
|
126
|
-
: 'foo2003-01-01 12:00:00',
|
|
129
|
+
expected[databaseName] ?? 'foo2003-01-01 12:00:00',
|
|
127
130
|
],
|
|
128
131
|
// TODO Maybe implement consistent null behavior
|
|
129
132
|
// ["concat('foo', null)", null],
|
|
@@ -251,7 +254,7 @@ expressionModels.forEach((expressionModel, databaseName) => {
|
|
|
251
254
|
|
|
252
255
|
describe('stddev', () => {
|
|
253
256
|
// TODO symmetric aggregates don't work with custom aggregate functions in BQ currently
|
|
254
|
-
if (
|
|
257
|
+
if (['bigquery', 'snowflake'].includes(databaseName)) return;
|
|
255
258
|
it(`works - ${databaseName}`, async () => {
|
|
256
259
|
await funcTestAgg('round(stddev(aircraft_models.seats))', 29);
|
|
257
260
|
});
|
|
@@ -906,13 +909,13 @@ expressionModels.forEach((expressionModel, databaseName) => {
|
|
|
906
909
|
describe('coalesce', () => {
|
|
907
910
|
it(`works - ${databaseName}`, async () => {
|
|
908
911
|
await funcTestMultiple(
|
|
909
|
-
["coalesce('a')", 'a'],
|
|
912
|
+
// ["coalesce('a')", 'a'],
|
|
910
913
|
["coalesce('a', 'b')", 'a'],
|
|
911
914
|
["coalesce(null, 'a', 'b')", 'a'],
|
|
912
915
|
["coalesce(null, 'b')", 'b'],
|
|
913
916
|
["coalesce('a', null)", 'a'],
|
|
914
|
-
['coalesce(null, null)', null]
|
|
915
|
-
['coalesce(null)', null]
|
|
917
|
+
['coalesce(null, null)', null]
|
|
918
|
+
// ['coalesce(null)', null]
|
|
916
919
|
);
|
|
917
920
|
});
|
|
918
921
|
});
|
|
@@ -931,11 +934,11 @@ expressionModels.forEach((expressionModel, databaseName) => {
|
|
|
931
934
|
it(`works - ${databaseName}`, async () => {
|
|
932
935
|
await funcTestMultiple(
|
|
933
936
|
['chr(65)', 'A'],
|
|
934
|
-
['chr(255)', 'ÿ']
|
|
935
|
-
['chr(null)', null],
|
|
937
|
+
['chr(255)', 'ÿ']
|
|
936
938
|
// BigQuery's documentation says that `chr(0)` returns the empty string, but it doesn't,
|
|
937
939
|
// it actually returns the null character. We generate code so that it does this.
|
|
938
|
-
['chr(0)', '']
|
|
940
|
+
// ['chr(0)', '']
|
|
941
|
+
// ['chr(null)', null]
|
|
939
942
|
);
|
|
940
943
|
});
|
|
941
944
|
});
|
|
@@ -46,6 +46,8 @@ function getSplitFunction(db: string) {
|
|
|
46
46
|
`string_to_array(${column}, '${splitChar}')`,
|
|
47
47
|
'duckdb_wasm': (column: string, splitChar: string) =>
|
|
48
48
|
`string_to_array(${column}, '${splitChar}')`,
|
|
49
|
+
'snowflake': (column: string, splitChar: string) =>
|
|
50
|
+
`split(${column}, '${splitChar}')`,
|
|
49
51
|
}[db];
|
|
50
52
|
}
|
|
51
53
|
|
|
@@ -54,6 +56,8 @@ afterAll(async () => {
|
|
|
54
56
|
});
|
|
55
57
|
|
|
56
58
|
runtimes.runtimeMap.forEach((runtime, databaseName) => {
|
|
59
|
+
const q = runtime.getQuoter();
|
|
60
|
+
|
|
57
61
|
// Issue: #1284
|
|
58
62
|
it(`parenthesize output field values - ${databaseName}`, async () => {
|
|
59
63
|
await expect(`
|
|
@@ -436,6 +440,29 @@ runtimes.runtimeMap.forEach((runtime, databaseName) => {
|
|
|
436
440
|
});
|
|
437
441
|
});
|
|
438
442
|
|
|
443
|
+
it(`nest/unnest -basic - ${databaseName}`, async () => {
|
|
444
|
+
// in a joined table when the joined is leafiest
|
|
445
|
+
// we need to make sure we don't count rows that
|
|
446
|
+
// don't match the join.
|
|
447
|
+
await expect(`
|
|
448
|
+
run: ${databaseName}.table('malloytest.state_facts') -> {
|
|
449
|
+
group_by: state
|
|
450
|
+
aggregate: c is airport_count.sum()
|
|
451
|
+
nest: p is {
|
|
452
|
+
group_by: popular_name
|
|
453
|
+
aggregate: d is airport_count.sum()
|
|
454
|
+
}
|
|
455
|
+
} -> {
|
|
456
|
+
group_by: state, c
|
|
457
|
+
aggregate: p.d.sum()
|
|
458
|
+
}
|
|
459
|
+
`).malloyResultMatches(runtime, {
|
|
460
|
+
state: 'TX',
|
|
461
|
+
c: 1845,
|
|
462
|
+
d: 1845,
|
|
463
|
+
});
|
|
464
|
+
});
|
|
465
|
+
|
|
439
466
|
it(`count at root should not use distinct key - ${databaseName}`, async () => {
|
|
440
467
|
const q = await runtime
|
|
441
468
|
.loadQuery(
|
|
@@ -521,7 +548,7 @@ runtimes.runtimeMap.forEach((runtime, databaseName) => {
|
|
|
521
548
|
it(`avg ignore null- ${databaseName}`, async () => {
|
|
522
549
|
await expect(`
|
|
523
550
|
source: one is ${databaseName}.sql("""
|
|
524
|
-
SELECT 2 as a
|
|
551
|
+
SELECT 2 as ${q`a`}
|
|
525
552
|
UNION ALL SELECT 4
|
|
526
553
|
UNION ALL SELECT null
|
|
527
554
|
""")
|
|
@@ -729,21 +756,21 @@ runtimes.runtimeMap.forEach((runtime, databaseName) => {
|
|
|
729
756
|
|
|
730
757
|
it(`run simple sql - ${databaseName}`, async () => {
|
|
731
758
|
const result = await runtime
|
|
732
|
-
.loadQuery(
|
|
759
|
+
.loadQuery(`run: conn.sql('select 1 as ${q`one`}')`)
|
|
733
760
|
.run();
|
|
734
761
|
expect(result.data.value[0]['one']).toBe(1);
|
|
735
762
|
});
|
|
736
763
|
|
|
737
764
|
it(`simple sql is exactly as written - ${databaseName}`, async () => {
|
|
738
765
|
const result = await runtime
|
|
739
|
-
.loadQuery(
|
|
766
|
+
.loadQuery(`run: conn.sql('select 1 as ${q`one`}')`)
|
|
740
767
|
.run();
|
|
741
768
|
if (databaseName === 'postgres') {
|
|
742
769
|
expect(result.sql).toBe(`WITH __stage0 AS (
|
|
743
|
-
select 1 as one)
|
|
770
|
+
select 1 as ${q`one`})
|
|
744
771
|
SELECT row_to_json(finalStage) as row FROM __stage0 AS finalStage`);
|
|
745
772
|
} else {
|
|
746
|
-
expect(result.sql).toBe(
|
|
773
|
+
expect(result.sql).toBe(`select 1 as ${q`one`}`);
|
|
747
774
|
}
|
|
748
775
|
expect(result.resultExplore).not.toBeUndefined();
|
|
749
776
|
});
|
|
@@ -752,7 +779,7 @@ SELECT row_to_json(finalStage) as row FROM __stage0 AS finalStage`);
|
|
|
752
779
|
const result = await runtime
|
|
753
780
|
.loadQuery(
|
|
754
781
|
`
|
|
755
|
-
query: q is conn.sql(
|
|
782
|
+
query: q is conn.sql('select 1 as ${q`one`}')
|
|
756
783
|
source: s is q
|
|
757
784
|
run: s -> { select: * }
|
|
758
785
|
`
|
|
@@ -861,7 +888,7 @@ SELECT row_to_json(finalStage) as row FROM __stage0 AS finalStage`);
|
|
|
861
888
|
}
|
|
862
889
|
);
|
|
863
890
|
|
|
864
|
-
const sql1234 = `${databaseName}.sql(
|
|
891
|
+
const sql1234 = `${databaseName}.sql('SELECT 1 as ${q`a`}, 2 as ${q`b`} UNION ALL SELECT 3, 4')`;
|
|
865
892
|
|
|
866
893
|
it(`sql as source - ${databaseName}`, async () => {
|
|
867
894
|
await expect(`
|
|
@@ -877,7 +904,7 @@ SELECT row_to_json(finalStage) as row FROM __stage0 AS finalStage`);
|
|
|
877
904
|
const turduckenQuery = `
|
|
878
905
|
run: ${databaseName}.sql("""
|
|
879
906
|
SELECT
|
|
880
|
-
'something' as
|
|
907
|
+
'something' as SOMETHING,
|
|
881
908
|
*
|
|
882
909
|
FROM %{
|
|
883
910
|
${databaseName}.table('malloytest.state_facts') -> {
|
|
@@ -930,7 +957,7 @@ SELECT row_to_json(finalStage) as row FROM __stage0 AS finalStage`);
|
|
|
930
957
|
it(`regexp match- ${databaseName}`, async () => {
|
|
931
958
|
await expect(`
|
|
932
959
|
run: ${databaseName}.sql("""
|
|
933
|
-
SELECT 'hello mom' as a, 'cheese tastes good' as b
|
|
960
|
+
SELECT 'hello mom' as ${q`a`}, 'cheese tastes good' as ${q`b`}
|
|
934
961
|
UNION ALL SELECT 'lloyd is a bozo', 'michael likes poetry'
|
|
935
962
|
""") -> {
|
|
936
963
|
aggregate: llo is count() {where: a ~ r'llo'}
|
|
@@ -942,21 +969,24 @@ SELECT row_to_json(finalStage) as row FROM __stage0 AS finalStage`);
|
|
|
942
969
|
it(`substitution precedence- ${databaseName}`, async () => {
|
|
943
970
|
await expect(`
|
|
944
971
|
run: ${databaseName}.sql("""
|
|
945
|
-
SELECT 5 as a, 2 as b
|
|
972
|
+
SELECT 5 as ${q`a`}, 2 as ${q`b`}
|
|
946
973
|
UNION ALL SELECT 3, 4
|
|
947
974
|
""") -> {
|
|
948
975
|
extend: {dimension: c is b + 4}
|
|
949
|
-
select: x is
|
|
976
|
+
select: x is a * c
|
|
950
977
|
}
|
|
951
978
|
`).malloyResultMatches(runtime, {x: 30});
|
|
952
979
|
});
|
|
953
980
|
|
|
954
|
-
|
|
955
|
-
|
|
981
|
+
testIf(runtime.supportsNesting)(
|
|
982
|
+
`array unnest - ${databaseName}`,
|
|
983
|
+
async () => {
|
|
984
|
+
const splitFN = getSplitFunction(databaseName);
|
|
985
|
+
await expect(`
|
|
956
986
|
run: ${databaseName}.sql("""
|
|
957
987
|
SELECT
|
|
958
|
-
city,
|
|
959
|
-
${
|
|
988
|
+
${q`city`},
|
|
989
|
+
${splitFN!(q`city`, ' ')} as ${q`words`}
|
|
960
990
|
FROM ${rootDbPath(databaseName)}malloytest.aircraft
|
|
961
991
|
""") -> {
|
|
962
992
|
where: words.value != null
|
|
@@ -964,16 +994,20 @@ SELECT row_to_json(finalStage) as row FROM __stage0 AS finalStage`);
|
|
|
964
994
|
aggregate: c is count()
|
|
965
995
|
}
|
|
966
996
|
`).malloyResultMatches(runtime, {c: 145});
|
|
967
|
-
|
|
997
|
+
}
|
|
998
|
+
);
|
|
968
999
|
|
|
969
1000
|
// make sure we can count the total number of elements when fanning out.
|
|
970
|
-
|
|
971
|
-
|
|
1001
|
+
testIf(runtime.supportsNesting)(
|
|
1002
|
+
`array unnest x 2 - ${databaseName}`,
|
|
1003
|
+
async () => {
|
|
1004
|
+
const splitFN = getSplitFunction(databaseName);
|
|
1005
|
+
await expect(`
|
|
972
1006
|
run: ${databaseName}.sql("""
|
|
973
1007
|
SELECT
|
|
974
|
-
city,
|
|
975
|
-
${
|
|
976
|
-
${
|
|
1008
|
+
${q`city`},
|
|
1009
|
+
${splitFN!(q`city`, ' ')} as ${q`words`},
|
|
1010
|
+
${splitFN!(q`city`, 'A')} as ${q`abreak`}
|
|
977
1011
|
FROM ${rootDbPath(databaseName)}malloytest.aircraft
|
|
978
1012
|
WHERE city IS NOT null
|
|
979
1013
|
""") -> {
|
|
@@ -982,7 +1016,8 @@ SELECT row_to_json(finalStage) as row FROM __stage0 AS finalStage`);
|
|
|
982
1016
|
c is words.count()
|
|
983
1017
|
a is abreak.count()
|
|
984
1018
|
}`).malloyResultMatches(runtime, {b: 3552, c: 4586, a: 6601});
|
|
985
|
-
|
|
1019
|
+
}
|
|
1020
|
+
);
|
|
986
1021
|
|
|
987
1022
|
testIf(runtime.supportsNesting)(`nest null - ${databaseName}`, async () => {
|
|
988
1023
|
const result = await runtime
|
|
@@ -1120,7 +1155,7 @@ SELECT row_to_json(finalStage) as row FROM __stage0 AS finalStage`);
|
|
|
1120
1155
|
const back = '\\';
|
|
1121
1156
|
test('backslash quote', async () => {
|
|
1122
1157
|
await expect(`
|
|
1123
|
-
run: ${databaseName}.sql(
|
|
1158
|
+
run: ${databaseName}.sql('SELECT 1') -> {
|
|
1124
1159
|
select: tick is '${back}${tick}'
|
|
1125
1160
|
}
|
|
1126
1161
|
`).malloyResultMatches(runtime, {tick});
|
|
@@ -87,8 +87,10 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
|
|
|
87
87
|
`).malloyResultMatches(orderByModel, {});
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
testIf(runtime.supportsNesting)(
|
|
91
|
+
`reserved words are quoted in turtles - ${databaseName}`,
|
|
92
|
+
async () => {
|
|
93
|
+
await expect(`
|
|
92
94
|
run: models->{
|
|
93
95
|
nest: withx is {
|
|
94
96
|
group_by: select is UPPER(manufacturer)
|
|
@@ -100,7 +102,8 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
|
|
|
100
102
|
fetch is withx.fetch
|
|
101
103
|
}
|
|
102
104
|
`).malloyResultMatches(orderByModel, {});
|
|
103
|
-
|
|
105
|
+
}
|
|
106
|
+
);
|
|
104
107
|
|
|
105
108
|
it.skip('reserved words in structure definitions', async () => {
|
|
106
109
|
await expect(`
|