@malloydata/malloy-tests 0.0.434 → 0.0.436
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/CONTEXT.md +5 -2
- package/mssql/connection_string.ts +19 -3
- package/mssql/mssql_start.sh +19 -13
- package/mssql/mssql_stop.sh +2 -2
- package/package.json +12 -11
- package/src/core/experimental-dialects.spec.ts +125 -41
- package/src/core/persist.spec.ts +275 -3
- package/src/databases/all/db_filter_expressions.spec.ts +7 -0
- package/src/databases/all/db_index.spec.ts +4 -2
- package/src/databases/all/expr.spec.ts +9 -8
- package/src/databases/all/functions.spec.ts +83 -57
- package/src/databases/all/new-matchers.spec.ts +17 -11
- package/src/databases/all/orderby.spec.ts +19 -12
- package/src/databases/all/test-select.spec.ts +5 -2
- package/src/databases/all/time.spec.ts +191 -45
- package/src/databases/sqlserver/sqlserver.spec.ts +509 -0
- package/src/runtimes.ts +49 -10
- package/src/test-select.ts +10 -14
- package/tsconfig.json +3 -0
|
@@ -274,11 +274,11 @@ describe.each(runtimes.runtimeList)('%s date and time', (dbName, runtime) => {
|
|
|
274
274
|
});
|
|
275
275
|
});
|
|
276
276
|
|
|
277
|
-
test.when(
|
|
277
|
+
test.when(timestamptz)(
|
|
278
278
|
'extract from timestamptz without query timezone',
|
|
279
279
|
async () => {
|
|
280
280
|
// TIMESTAMPTZ representing midnight UTC
|
|
281
|
-
// Without query timezone, extract should happen in UTC
|
|
281
|
+
// Without query timezone, extract should happen in UTC
|
|
282
282
|
// Expected: hour = 0, day = 20
|
|
283
283
|
await expect(
|
|
284
284
|
`run: ${dbName}.sql("SELECT 1 as x") -> {
|
|
@@ -291,6 +291,80 @@ describe.each(runtimes.runtimeList)('%s date and time', (dbName, runtime) => {
|
|
|
291
291
|
}
|
|
292
292
|
);
|
|
293
293
|
|
|
294
|
+
// 20:00 on the 30th in Mexico City is 02:00 on the 31st in UTC. With no
|
|
295
|
+
// query time zone the value is read in UTC, not in the zone it was written in.
|
|
296
|
+
describe('timestamptz written in another zone', () => {
|
|
297
|
+
const tzModel = () =>
|
|
298
|
+
mkTestModel(runtime, {
|
|
299
|
+
tzdata: [
|
|
300
|
+
{
|
|
301
|
+
tstz: TV.timestamptz('2020-01-30 20:00:00[America/Mexico_City]'),
|
|
302
|
+
same_instant: TV.timestamp('2020-01-31 02:00:00'),
|
|
303
|
+
same_digits: TV.timestamp('2020-01-30 20:00:00'),
|
|
304
|
+
},
|
|
305
|
+
],
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test.when(timestamptz)('extract', async () => {
|
|
309
|
+
await expect(
|
|
310
|
+
'run: tzdata -> { select: h is hour(tstz), d is day(tstz) }'
|
|
311
|
+
).toMatchResult(tzModel(), {h: 2, d: 31});
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
test.when(timestamptz)('truncate', async () => {
|
|
315
|
+
await expect('run: tzdata -> { select: d is tstz.day }').toMatchResult(
|
|
316
|
+
tzModel(),
|
|
317
|
+
{d: '2020-01-31T00:00:00.000Z'}
|
|
318
|
+
);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
test.when(timestamptz)('add a month', async () => {
|
|
322
|
+
// Jan 31 + 1 month is Feb 29; Jan 30 + 1 month in Mexico City is Mar 1 UTC
|
|
323
|
+
await expect(
|
|
324
|
+
'run: tzdata -> { select: next is tstz + 1 month }'
|
|
325
|
+
).toMatchResult(tzModel(), {next: '2020-02-29T02:00:00.000Z'});
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
test.when(timestamptz)('cast to date', async () => {
|
|
329
|
+
await expect('run: tzdata -> { select: d is tstz::date }').toMatchResult(
|
|
330
|
+
tzModel(),
|
|
331
|
+
{d: '2020-01-31'}
|
|
332
|
+
);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
test.when(timestamptz)('cast keeps the instant', async () => {
|
|
336
|
+
await expect(`
|
|
337
|
+
run: tzdata -> {
|
|
338
|
+
select:
|
|
339
|
+
ts is tstz::timestamp
|
|
340
|
+
same is pick 'yes' when tstz::timestamp = tstz else 'no'
|
|
341
|
+
back is pick 'yes' when same_instant::timestamptz = tstz else 'no'
|
|
342
|
+
}
|
|
343
|
+
`).toMatchResult(tzModel(), {
|
|
344
|
+
ts: '2020-01-31T02:00:00.000Z',
|
|
345
|
+
same: 'yes',
|
|
346
|
+
back: 'yes',
|
|
347
|
+
});
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
test.when(timestamptz)('compare to timestamp', async () => {
|
|
351
|
+
await expect(`
|
|
352
|
+
run: tzdata -> {
|
|
353
|
+
select:
|
|
354
|
+
eq_instant is pick 'yes' when tstz = same_instant else 'no'
|
|
355
|
+
eq_digits is pick 'yes' when tstz = same_digits else 'no'
|
|
356
|
+
gt_digits is pick 'yes' when tstz > same_digits else 'no'
|
|
357
|
+
lt_digits is pick 'yes' when same_digits < tstz else 'no'
|
|
358
|
+
}
|
|
359
|
+
`).toMatchResult(tzModel(), {
|
|
360
|
+
eq_instant: 'yes',
|
|
361
|
+
eq_digits: 'no',
|
|
362
|
+
gt_digits: 'yes',
|
|
363
|
+
lt_digits: 'yes',
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
|
|
294
368
|
describe('date truncation', () => {
|
|
295
369
|
test('date trunc day', async () => {
|
|
296
370
|
const eq = sqlEq('t_date.day', '@2021-02-24');
|
|
@@ -526,16 +600,16 @@ describe.each(runtimes.runtimeList)('%s date and time', (dbName, runtime) => {
|
|
|
526
600
|
});
|
|
527
601
|
await expect(`
|
|
528
602
|
run: fourTimes -> { select:
|
|
529
|
-
isBefore is tbefore ? @2026-01-01
|
|
530
|
-
isFirst is tfirst ? @2026-01-01
|
|
531
|
-
isLast is tlast ? @2026-01-01
|
|
532
|
-
isAfter is tafter ? @2026-01-01
|
|
603
|
+
isBefore is pick 'in' when tbefore ? @2026-01-01 else 'out'
|
|
604
|
+
isFirst is pick 'in' when tfirst ? @2026-01-01 else 'out'
|
|
605
|
+
isLast is pick 'in' when tlast ? @2026-01-01 else 'out'
|
|
606
|
+
isAfter is pick 'in' when tafter ? @2026-01-01 else 'out'
|
|
533
607
|
}
|
|
534
608
|
`).toMatchResult(tm, {
|
|
535
|
-
isBefore:
|
|
536
|
-
isFirst:
|
|
537
|
-
isLast:
|
|
538
|
-
isAfter:
|
|
609
|
+
isBefore: 'out',
|
|
610
|
+
isFirst: 'in',
|
|
611
|
+
isLast: 'in',
|
|
612
|
+
isAfter: 'out',
|
|
539
613
|
});
|
|
540
614
|
});
|
|
541
615
|
});
|
|
@@ -730,6 +804,7 @@ describe.each(runtimes.runtimeList)('%s: tz literals', (dbName, runtime) => {
|
|
|
730
804
|
|
|
731
805
|
describe.each(runtimes.runtimeList)('%s: query tz', (dbName, runtime) => {
|
|
732
806
|
const testModel = wrapTestModel(runtime, '');
|
|
807
|
+
const timestamptz = runtime.dialect.hasTimestamptz;
|
|
733
808
|
const ts = new TestSelect(runtime.dialect);
|
|
734
809
|
const selectMidnight = `"""${ts.generate({
|
|
735
810
|
utc_midnight_ts: ts.mk_timestamp('2020-02-20 00:00:00'),
|
|
@@ -762,7 +837,7 @@ describe.each(runtimes.runtimeList)('%s: query tz', (dbName, runtime) => {
|
|
|
762
837
|
).toMatchResult(testModel, {mex_midnight: 18, mex_day: 19});
|
|
763
838
|
});
|
|
764
839
|
|
|
765
|
-
test.when(
|
|
840
|
+
test.when(timestamptz)(
|
|
766
841
|
'extract from timestamptz with query timezone',
|
|
767
842
|
async () => {
|
|
768
843
|
// TIMESTAMPTZ representing midnight UTC
|
|
@@ -792,6 +867,16 @@ describe.each(runtimes.runtimeList)('%s: query tz', (dbName, runtime) => {
|
|
|
792
867
|
).toMatchResult(testModel, {mex_day: mex_19.toJSDate()});
|
|
793
868
|
});
|
|
794
869
|
|
|
870
|
+
test('truncate hour in a zone a half hour off UTC', async () => {
|
|
871
|
+
// 02:10 in Kolkata is 20:40 UTC, and the Kolkata hour starts at 20:30
|
|
872
|
+
await expect(
|
|
873
|
+
`run: ${dbName}.sql("SELECT 1 as x") -> {
|
|
874
|
+
timezone: 'Asia/Kolkata'
|
|
875
|
+
select: kol_hour is @2020-01-31 02:10:00.hour
|
|
876
|
+
}`
|
|
877
|
+
).toMatchResult(testModel, {kol_hour: '2020-01-30T20:30:00.000Z'});
|
|
878
|
+
});
|
|
879
|
+
|
|
795
880
|
test('truncate week', async () => {
|
|
796
881
|
// the 19th in mexico is a wednesday, so trunc to the 15th
|
|
797
882
|
const mex_19 = LuxonDateTime.fromISO('2020-02-19T00:00:00', {zone});
|
|
@@ -814,18 +899,15 @@ describe.each(runtimes.runtimeList)('%s: query tz', (dbName, runtime) => {
|
|
|
814
899
|
}`
|
|
815
900
|
).toMatchResult(testModel, {mex_date: '2020-02-19'});
|
|
816
901
|
});
|
|
817
|
-
test.when(
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
await expect(
|
|
821
|
-
`run: ${dbName}.sql("SELECT 1 as x") -> {
|
|
902
|
+
test.when(timestamptz)('cast timestamptz to date', async () => {
|
|
903
|
+
await expect(
|
|
904
|
+
`run: ${dbName}.sql("SELECT 1 as x") -> {
|
|
822
905
|
timezone: '${zone}'
|
|
823
906
|
extend: { dimension: utc_tstz is @2020-02-20 00:00:00[UTC]::timestamptz }
|
|
824
907
|
select: mex_date is utc_tstz::date
|
|
825
908
|
}`
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
);
|
|
909
|
+
).toMatchResult(testModel, {mex_date: '2020-02-19'});
|
|
910
|
+
});
|
|
829
911
|
test('cast date to timestamp', async () => {
|
|
830
912
|
await expect(
|
|
831
913
|
`run: ${dbName}.sql(${selectMidnight}) -> {
|
|
@@ -842,31 +924,95 @@ describe.each(runtimes.runtimeList)('%s: query tz', (dbName, runtime) => {
|
|
|
842
924
|
}`
|
|
843
925
|
).toMatchResult(testModel, {d2020: '2020-02-20'});
|
|
844
926
|
});
|
|
845
|
-
test.when(
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
await expect(
|
|
849
|
-
`run: ${dbName}.sql(${selectMidnight}) -> {
|
|
927
|
+
test.when(timestamptz)('cast date to timestamptz', async () => {
|
|
928
|
+
await expect(
|
|
929
|
+
`run: ${dbName}.sql(${selectMidnight}) -> {
|
|
850
930
|
timezone: '${zone}'
|
|
851
931
|
select: mex_date is date_2020::timestamptz
|
|
852
932
|
}`
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
);
|
|
933
|
+
).toMatchResult(testModel, {mex_date: zone_2020.toJSDate()});
|
|
934
|
+
});
|
|
856
935
|
|
|
857
|
-
test.when(
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
936
|
+
test.when(timestamptz)('compare timestamptz to range', async () => {
|
|
937
|
+
const tzModel = mkTestModel(runtime, {
|
|
938
|
+
tzdata: [
|
|
939
|
+
{updated: TV.timestamptz('2020-01-15 00:00:00[America/Mexico_City]')},
|
|
940
|
+
],
|
|
941
|
+
});
|
|
942
|
+
await expect(
|
|
943
|
+
"run: tzdata -> { select: cmp is pick 'in' when updated ? @2020-01 else 'out' }"
|
|
944
|
+
).toMatchResult(tzModel, {cmp: 'in'});
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
// 11:00 on the 31st in Tokyo is 20:00 on the 30th in Mexico City. With a
|
|
948
|
+
// query time zone the value is read there, not in the zone it was written in.
|
|
949
|
+
describe('timestamptz written in another zone', () => {
|
|
950
|
+
const tzModel = () =>
|
|
951
|
+
mkTestModel(runtime, {
|
|
861
952
|
tzdata: [
|
|
862
|
-
{
|
|
953
|
+
{
|
|
954
|
+
tstz: TV.timestamptz('2020-01-31 11:00:00[Asia/Tokyo]'),
|
|
955
|
+
same_instant: TV.timestamp('2020-01-31 02:00:00'),
|
|
956
|
+
},
|
|
863
957
|
],
|
|
864
958
|
});
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
959
|
+
|
|
960
|
+
test.when(timestamptz)('extract', async () => {
|
|
961
|
+
await expect(`
|
|
962
|
+
run: tzdata -> {
|
|
963
|
+
timezone: '${zone}'
|
|
964
|
+
select: h is hour(tstz), d is day(tstz)
|
|
965
|
+
}
|
|
966
|
+
`).toMatchResult(tzModel(), {h: 20, d: 30});
|
|
967
|
+
});
|
|
968
|
+
|
|
969
|
+
test.when(timestamptz)('truncate', async () => {
|
|
970
|
+
const mex_30 = LuxonDateTime.fromISO('2020-01-30T00:00:00', {zone});
|
|
971
|
+
await expect(`
|
|
972
|
+
run: tzdata -> {
|
|
973
|
+
timezone: '${zone}'
|
|
974
|
+
select: d is tstz.day
|
|
975
|
+
}
|
|
976
|
+
`).toMatchResult(tzModel(), {d: mex_30.toJSDate()});
|
|
977
|
+
});
|
|
978
|
+
|
|
979
|
+
test.when(timestamptz)('add a month', async () => {
|
|
980
|
+
// Jan 30 + 1 month is Feb 29 in Mexico City; Jan 31 + 1 month in Tokyo
|
|
981
|
+
// or UTC is a day earlier
|
|
982
|
+
const mex_29 = LuxonDateTime.fromISO('2020-02-29T20:00:00', {zone});
|
|
983
|
+
await expect(`
|
|
984
|
+
run: tzdata -> {
|
|
985
|
+
timezone: '${zone}'
|
|
986
|
+
select: next is tstz + 1 month
|
|
987
|
+
}
|
|
988
|
+
`).toMatchResult(tzModel(), {next: mex_29.toJSDate()});
|
|
989
|
+
});
|
|
990
|
+
|
|
991
|
+
test.when(timestamptz)('cast to date', async () => {
|
|
992
|
+
await expect(`
|
|
993
|
+
run: tzdata -> {
|
|
994
|
+
timezone: '${zone}'
|
|
995
|
+
select: d is tstz::date
|
|
996
|
+
}
|
|
997
|
+
`).toMatchResult(tzModel(), {d: '2020-01-30'});
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
test.when(timestamptz)('cast keeps the instant', async () => {
|
|
1001
|
+
await expect(`
|
|
1002
|
+
run: tzdata -> {
|
|
1003
|
+
timezone: '${zone}'
|
|
1004
|
+
select:
|
|
1005
|
+
ts is tstz::timestamp
|
|
1006
|
+
same is pick 'yes' when tstz::timestamp = tstz else 'no'
|
|
1007
|
+
back is pick 'yes' when same_instant::timestamptz = tstz else 'no'
|
|
1008
|
+
}
|
|
1009
|
+
`).toMatchResult(tzModel(), {
|
|
1010
|
+
ts: '2020-01-31T02:00:00.000Z',
|
|
1011
|
+
same: 'yes',
|
|
1012
|
+
back: 'yes',
|
|
1013
|
+
});
|
|
1014
|
+
});
|
|
1015
|
+
});
|
|
870
1016
|
|
|
871
1017
|
// Test for timezone rendering issue with nested queries
|
|
872
1018
|
test.when(runtime.supportsNesting)(
|
|
@@ -946,16 +1092,16 @@ describe.each(runtimes.runtimeList)('%s: query tz', (dbName, runtime) => {
|
|
|
946
1092
|
timezone: 'Europe/Dublin'
|
|
947
1093
|
select:
|
|
948
1094
|
june1_correct,
|
|
949
|
-
month_ok is by_month = june1_correct, by_month
|
|
950
|
-
day_ok is by_day = june1_correct, by_day
|
|
951
|
-
hour_ok is by_hour = june1_correct, by_hour
|
|
952
|
-
quarter_ok is by_quarter = august1_correct, by_quarter
|
|
1095
|
+
month_ok is pick 'yes' when by_month = june1_correct else 'no', by_month
|
|
1096
|
+
day_ok is pick 'yes' when by_day = june1_correct else 'no', by_day
|
|
1097
|
+
hour_ok is pick 'yes' when by_hour = june1_correct else 'no', by_hour
|
|
1098
|
+
quarter_ok is pick 'yes' when by_quarter = august1_correct else 'no', by_quarter
|
|
953
1099
|
}`
|
|
954
1100
|
).toMatchResult(testModel, {
|
|
955
|
-
month_ok:
|
|
956
|
-
day_ok:
|
|
957
|
-
hour_ok:
|
|
958
|
-
quarter_ok:
|
|
1101
|
+
month_ok: 'yes',
|
|
1102
|
+
day_ok: 'yes',
|
|
1103
|
+
hour_ok: 'yes',
|
|
1104
|
+
quarter_ok: 'yes',
|
|
959
1105
|
});
|
|
960
1106
|
});
|
|
961
1107
|
});
|