@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.
@@ -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
- testIf(databaseName !== 'postgres')('model: dates named', async () => {
232
- await expect(`
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
- t_date: new Date('2020-03-02'),
248
- t_date_month: new Date('2020-03-01'),
249
- t_date_year: new Date('2020-01-01'),
250
- t_timestamp: new Date('2020-03-02T12:35:56.000Z'),
251
- t_timestamp_second: new Date('2020-03-02T12:35:56.000Z'),
252
- t_timestamp_minute: new Date('2020-03-02T12:35:00.000Z'),
253
- t_timestamp_hour: new Date('2020-03-02T12:00:00.000Z'),
254
- t_timestamp_date: new Date('2020-03-02'),
255
- t_timestamp_month: new Date('2020-03-01'),
256
- t_timestamp_year: new Date('2020-01-01'),
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 !== 'postgres')('sql safe cast', async () => {
313
- await expect(`
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
- bad_date: null,
321
- bad_number: null,
322
- good_number: 312,
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("UPPER(\${TABLE}.manufacturer)")
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 dependancies', async () => {
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 === 'bigquery'
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 (databaseName === 'bigquery') return;
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('run: conn.sql("select 1 as one")')
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('run: conn.sql("select 1 as one")')
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('select 1 as one');
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("select 1 as one")
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("SELECT 1 as a, 2 as b UNION ALL SELECT 3, 4")`;
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 something,
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 a * c
976
+ select: x is a * c
950
977
  }
951
978
  `).malloyResultMatches(runtime, {x: 30});
952
979
  });
953
980
 
954
- it(`array unnest - ${databaseName}`, async () => {
955
- await expect(`
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
- ${getSplitFunction(databaseName)!('city', ' ')} as words
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
- it(`array unnest x 2 - ${databaseName}`, async () => {
971
- await expect(`
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
- ${getSplitFunction(databaseName)!('city', ' ')} as words,
976
- ${getSplitFunction(databaseName)!('city', 'A')} as abreak
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("SELECT 1") -> {
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
- it(`reserved words are quoted in turtles - ${databaseName}`, async () => {
91
- await expect(`
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(`