"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const dbt_1 = require("../types/dbt");
const field_1 = require("../types/field");
const timeFrames_1 = require("../types/timeFrames");
const timeFrames_2 = require("./timeFrames");
describe('TimeFrames', () => {
    describe('getSqlForTruncatedDate', () => {
        test('should get sql where stat of the week is Wednesday', async () => {
            expect(timeFrames_2.timeFrameConfigs[timeFrames_1.TimeFrames.WEEK].getSql(dbt_1.SupportedDbtAdapter.POSTGRES, timeFrames_1.TimeFrames.WEEK, '${TABLE}.created', field_1.DimensionType.TIMESTAMP, timeFrames_2.WeekDay.WEDNESDAY)).toEqual("(DATE_TRUNC('WEEK', (${TABLE}.created - interval '2 days')) + interval '2 days')");
            expect(timeFrames_2.timeFrameConfigs[timeFrames_1.TimeFrames.WEEK].getSql(dbt_1.SupportedDbtAdapter.REDSHIFT, timeFrames_1.TimeFrames.WEEK, '${TABLE}.created', field_1.DimensionType.TIMESTAMP, timeFrames_2.WeekDay.WEDNESDAY)).toEqual("(DATE_TRUNC('WEEK', (${TABLE}.created - interval '2 days')) + interval '2 days')");
            expect(timeFrames_2.timeFrameConfigs[timeFrames_1.TimeFrames.WEEK].getSql(dbt_1.SupportedDbtAdapter.DUCKDB, timeFrames_1.TimeFrames.WEEK, '${TABLE}.created', field_1.DimensionType.TIMESTAMP, timeFrames_2.WeekDay.WEDNESDAY)).toEqual("(DATE_TRUNC('WEEK', (${TABLE}.created - interval '2 days')) + interval '2 days')");
            expect(timeFrames_2.timeFrameConfigs[timeFrames_1.TimeFrames.WEEK].getSql(dbt_1.SupportedDbtAdapter.BIGQUERY, timeFrames_1.TimeFrames.WEEK, '${TABLE}.created', field_1.DimensionType.TIMESTAMP, timeFrames_2.WeekDay.WEDNESDAY)).toEqual('TIMESTAMP_TRUNC(${TABLE}.created, WEEK(WEDNESDAY))');
            expect(timeFrames_2.timeFrameConfigs[timeFrames_1.TimeFrames.WEEK].getSql(dbt_1.SupportedDbtAdapter.DATABRICKS, timeFrames_1.TimeFrames.WEEK, '${TABLE}.created', field_1.DimensionType.TIMESTAMP, timeFrames_2.WeekDay.WEDNESDAY)).toEqual("DATEADD(DAY, 2, DATE_TRUNC('WEEK', DATEADD(DAY, -2, ${TABLE}.created)))");
            expect(timeFrames_2.timeFrameConfigs[timeFrames_1.TimeFrames.WEEK].getSql(dbt_1.SupportedDbtAdapter.SNOWFLAKE, timeFrames_1.TimeFrames.WEEK, '${TABLE}.created', field_1.DimensionType.TIMESTAMP, timeFrames_2.WeekDay.WEDNESDAY)).toEqual("DATE_TRUNC('WEEK', ${TABLE}.created)");
            // ClickHouse: toStartOfWeek(date, 1) uses mode 1 (Monday base), matching Postgres DATE_TRUNC('week')
            expect(timeFrames_2.timeFrameConfigs[timeFrames_1.TimeFrames.WEEK].getSql(dbt_1.SupportedDbtAdapter.CLICKHOUSE, timeFrames_1.TimeFrames.WEEK, '${TABLE}.created', field_1.DimensionType.TIMESTAMP, timeFrames_2.WeekDay.WEDNESDAY)).toEqual('addDays(toStartOfWeek(addDays(${TABLE}.created, -2), 1), 2)');
        });
        test('BigQuery wrapped path shifts to a naive DATETIME, truncates, and re-attaches the zone (merge)', () => {
            expect((0, timeFrames_2.getSqlForTruncatedDate)(dbt_1.SupportedDbtAdapter.BIGQUERY, timeFrames_1.TimeFrames.DAY, '${TABLE}.created', field_1.DimensionType.TIMESTAMP, undefined, 'America/New_York')).toEqual("TIMESTAMP(DATETIME_TRUNC(DATETIME(TIMESTAMP(${TABLE}.created), 'America/New_York'), DAY), 'America/New_York')");
        });
        test('UTC target with default (UTC) source short-circuits the wrap', () => {
            // BigQuery: avoids TIMESTAMP() cast + 3-arg overload that defeats
            // partition pruning when both sides are UTC.
            expect((0, timeFrames_2.getSqlForTruncatedDate)(dbt_1.SupportedDbtAdapter.BIGQUERY, timeFrames_1.TimeFrames.DAY, '${TABLE}.created', field_1.DimensionType.TIMESTAMP, undefined, 'UTC')).toEqual('TIMESTAMP_TRUNC(${TABLE}.created, DAY)');
            expect((0, timeFrames_2.getSqlForTruncatedDate)(dbt_1.SupportedDbtAdapter.POSTGRES, timeFrames_1.TimeFrames.DAY, '${TABLE}.created', field_1.DimensionType.TIMESTAMP, undefined, 'UTC')).toEqual("DATE_TRUNC('DAY', ${TABLE}.created)");
            expect((0, timeFrames_2.getSqlForTruncatedDate)(dbt_1.SupportedDbtAdapter.SNOWFLAKE, timeFrames_1.TimeFrames.DAY, '${TABLE}.created', field_1.DimensionType.TIMESTAMP, undefined, 'UTC')).toEqual("DATE_TRUNC('DAY', ${TABLE}.created)");
        });
        test('Matching non-UTC target and source short-circuits the wrap', () => {
            const tz = 'America/New_York';
            expect((0, timeFrames_2.getSqlForTruncatedDate)(dbt_1.SupportedDbtAdapter.BIGQUERY, timeFrames_1.TimeFrames.DAY, '${TABLE}.created', field_1.DimensionType.TIMESTAMP, undefined, tz, tz)).toEqual('TIMESTAMP_TRUNC(${TABLE}.created, DAY)');
            expect((0, timeFrames_2.getSqlForTruncatedDate)(dbt_1.SupportedDbtAdapter.SNOWFLAKE, timeFrames_1.TimeFrames.DAY, '${TABLE}.created', field_1.DimensionType.TIMESTAMP, undefined, tz, tz)).toEqual("DATE_TRUNC('DAY', ${TABLE}.created)");
            expect((0, timeFrames_2.getSqlForTruncatedDate)(dbt_1.SupportedDbtAdapter.POSTGRES, timeFrames_1.TimeFrames.DAY, '${TABLE}.created', field_1.DimensionType.TIMESTAMP, undefined, tz, tz)).toEqual("DATE_TRUNC('DAY', ${TABLE}.created)");
        });
        test('BigQuery 2-arg TIMESTAMP_TRUNC keeps original expr unchanged (DATETIME overload still applies)', () => {
            expect(timeFrames_2.timeFrameConfigs[timeFrames_1.TimeFrames.DAY].getSql(dbt_1.SupportedDbtAdapter.BIGQUERY, timeFrames_1.TimeFrames.DAY, '${TABLE}.created', field_1.DimensionType.TIMESTAMP)).toEqual('TIMESTAMP_TRUNC(${TABLE}.created, DAY)');
        });
        test('should get sql where start of the week is Monday for ClickHouse', () => {
            // Monday (startOfWeek=0): must pass mode 1 to toStartOfWeek() so it returns Monday not Sunday
            expect(timeFrames_2.timeFrameConfigs[timeFrames_1.TimeFrames.WEEK].getSql(dbt_1.SupportedDbtAdapter.CLICKHOUSE, timeFrames_1.TimeFrames.WEEK, '${TABLE}.created', field_1.DimensionType.TIMESTAMP, timeFrames_2.WeekDay.MONDAY)).toEqual('addDays(toStartOfWeek(addDays(${TABLE}.created, -0), 1), 0)');
        });
        test('ClickHouse SECOND truncation lifts to DateTime64 (toStartOfSecond rejects plain DateTime)', () => {
            expect(timeFrames_2.timeFrameConfigs[timeFrames_1.TimeFrames.SECOND].getSql(dbt_1.SupportedDbtAdapter.CLICKHOUSE, timeFrames_1.TimeFrames.SECOND, '${TABLE}.created', field_1.DimensionType.TIMESTAMP)).toEqual('toStartOfSecond(toDateTime64(${TABLE}.created, 3))');
        });
        test('ClickHouse MILLISECOND truncation lifts to DateTime64 (toStartOfMillisecond rejects plain DateTime)', () => {
            expect(timeFrames_2.timeFrameConfigs[timeFrames_1.TimeFrames.MILLISECOND].getSql(dbt_1.SupportedDbtAdapter.CLICKHOUSE, timeFrames_1.TimeFrames.MILLISECOND, '${TABLE}.created', field_1.DimensionType.TIMESTAMP)).toEqual('toStartOfMillisecond(toDateTime64(${TABLE}.created, 3))');
        });
    });
    describe('getSqlForDatePart - DAY_OF_WEEK_INDEX with startOfWeek', () => {
        const col = '${TABLE}.created';
        const tf = timeFrames_1.TimeFrames.DAY_OF_WEEK_INDEX;
        const dt = field_1.DimensionType.DATE;
        test('should adjust day of week index for Monday start', () => {
            // BigQuery: native DAYOFWEEK 1=Sun..7=Sat, offset for Monday = 2
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.BIGQUERY, tf, col, dt, timeFrames_2.WeekDay.MONDAY)).toEqual(`MOD(EXTRACT(DAYOFWEEK FROM ${col}) - 2 + 7, 7) + 1`);
            // PostgreSQL: native DOW 0=Sun..6=Sat, offset for Monday = 1
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.POSTGRES, tf, col, dt, timeFrames_2.WeekDay.MONDAY)).toEqual(`MOD(CAST(DATE_PART('DOW', ${col}) AS INT) - 1 + 7, 7) + 1`);
            // Redshift uses same config as PostgreSQL
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.REDSHIFT, tf, col, dt, timeFrames_2.WeekDay.MONDAY)).toEqual(`MOD(CAST(DATE_PART('DOW', ${col}) AS INT) - 1 + 7, 7) + 1`);
            // Databricks: native DOW 0=Sun..6=Sat, offset for Monday = 1
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.DATABRICKS, tf, col, dt, timeFrames_2.WeekDay.MONDAY)).toEqual(`MOD(CAST(DATE_PART('DOW', ${col}) AS INT) - 1 + 7, 7) + 1`);
            // Trino: native DOW (ISO) 1=Mon..7=Sun, offset for Monday = 1
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.TRINO, tf, col, dt, timeFrames_2.WeekDay.MONDAY)).toEqual(`MOD(EXTRACT(DOW FROM ${col}) - 1 + 7, 7) + 1`);
            // Athena uses Trino config
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.ATHENA, tf, col, dt, timeFrames_2.WeekDay.MONDAY)).toEqual(`MOD(EXTRACT(DOW FROM ${col}) - 1 + 7, 7) + 1`);
            // ClickHouse: native toDayOfWeek (ISO) 1=Mon..7=Sun, offset for Monday = 1
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.CLICKHOUSE, tf, col, dt, timeFrames_2.WeekDay.MONDAY)).toEqual(`modulo(toDayOfWeek(${col}) - 1 + 7, 7) + 1`);
        });
        test('should adjust day of week index for Sunday start', () => {
            // BigQuery: offset for Sunday = (6+1)%7+1 = 0+1 = 1
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.BIGQUERY, tf, col, dt, timeFrames_2.WeekDay.SUNDAY)).toEqual(`MOD(EXTRACT(DAYOFWEEK FROM ${col}) - 1 + 7, 7) + 1`);
            // PostgreSQL: offset for Sunday = (6+1)%7 = 0
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.POSTGRES, tf, col, dt, timeFrames_2.WeekDay.SUNDAY)).toEqual(`MOD(CAST(DATE_PART('DOW', ${col}) AS INT) - 0 + 7, 7) + 1`);
            // Trino: offset for Sunday = 6+1 = 7
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.TRINO, tf, col, dt, timeFrames_2.WeekDay.SUNDAY)).toEqual(`MOD(EXTRACT(DOW FROM ${col}) - 7 + 7, 7) + 1`);
            // ClickHouse: offset for Sunday = 6+1 = 7
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.CLICKHOUSE, tf, col, dt, timeFrames_2.WeekDay.SUNDAY)).toEqual(`modulo(toDayOfWeek(${col}) - 7 + 7, 7) + 1`);
        });
        test('should not adjust day of week index when startOfWeek is not set', () => {
            // Without startOfWeek, native behavior is preserved
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.BIGQUERY, tf, col, dt)).toEqual(`EXTRACT(DAYOFWEEK FROM ${col})`);
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.POSTGRES, tf, col, dt)).toEqual(`DATE_PART('DOW', ${col})`);
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.DUCKDB, tf, col, dt)).toEqual(`DATE_PART('DOW', ${col})`);
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.TRINO, tf, col, dt)).toEqual(`EXTRACT(DOW FROM ${col})`);
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.CLICKHOUSE, tf, col, dt)).toEqual(`toDayOfWeek(${col})`);
            // Snowflake: always uses session variable, never adjusts
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.SNOWFLAKE, tf, col, dt, timeFrames_2.WeekDay.MONDAY)).toEqual(`DATE_PART('DOW', ${col})`);
        });
    });
    describe('getSqlForDatePart - ClickHouse WEEK_NUM with startOfWeek', () => {
        const col = '${TABLE}.created';
        const tf = timeFrames_1.TimeFrames.WEEK_NUM;
        const dt = field_1.DimensionType.DATE;
        test('Monday start: toWeek mode 3 (ISO) matches Postgres EXTRACT(WEEK), fixes US-default off-by-one', () => {
            // toWeek(d) defaults to mode 0 (US, Sunday-base, 0–53). Mode 3 is
            // ISO 8601 (Monday-base), matching every other warehouse adapter.
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.CLICKHOUSE, tf, col, dt, timeFrames_2.WeekDay.MONDAY)).toEqual(`toWeek(addDays(${col}, -0), 3)`);
        });
        test('Wednesday start: shift date back by 2 days before extracting ISO week', () => {
            expect(timeFrames_2.timeFrameConfigs[tf].getSql(dbt_1.SupportedDbtAdapter.CLICKHOUSE, tf, col, dt, timeFrames_2.WeekDay.WEDNESDAY)).toEqual(`toWeek(addDays(${col}, -2), 3)`);
        });
    });
    describe('getSqlForDatePartName - ClickHouse', () => {
        const col = '${TABLE}.created';
        const dt = field_1.DimensionType.DATE;
        test('DAY_OF_WEEK_NAME uses dateName(weekday, ...) — toDayOfWeekName does not exist in ClickHouse', () => {
            expect(timeFrames_2.timeFrameConfigs[timeFrames_1.TimeFrames.DAY_OF_WEEK_NAME].getSql(dbt_1.SupportedDbtAdapter.CLICKHOUSE, timeFrames_1.TimeFrames.DAY_OF_WEEK_NAME, col, dt, timeFrames_2.WeekDay.MONDAY)).toEqual(`dateName('weekday', ${col})`);
        });
        test('MONTH_NAME uses monthName(...) — toMonthName does not exist in ClickHouse', () => {
            expect(timeFrames_2.timeFrameConfigs[timeFrames_1.TimeFrames.MONTH_NAME].getSql(dbt_1.SupportedDbtAdapter.CLICKHOUSE, timeFrames_1.TimeFrames.MONTH_NAME, col, dt, timeFrames_2.WeekDay.MONDAY)).toEqual(`monthName(${col})`);
        });
        test('QUARTER_NAME stays as concat(Q, toQuarter(...))', () => {
            expect(timeFrames_2.timeFrameConfigs[timeFrames_1.TimeFrames.QUARTER_NAME].getSql(dbt_1.SupportedDbtAdapter.CLICKHOUSE, timeFrames_1.TimeFrames.QUARTER_NAME, col, dt, timeFrames_2.WeekDay.MONDAY)).toEqual(`concat('Q', toString(toQuarter(${col})))`);
        });
    });
    describe('isSubDayGranularity', () => {
        test('SUB_DAY_GRANULARITIES matches timeFrameConfigs that produce TIMESTAMP', () => {
            // Map from DateGranularity to TimeFrames for the sub-day ones
            const subDayTimeFrames = {
                [timeFrames_1.DateGranularity.SECOND]: timeFrames_1.TimeFrames.SECOND,
                [timeFrames_1.DateGranularity.MINUTE]: timeFrames_1.TimeFrames.MINUTE,
                [timeFrames_1.DateGranularity.HOUR]: timeFrames_1.TimeFrames.HOUR,
            };
            for (const g of timeFrames_2.SUB_DAY_GRANULARITIES) {
                const tf = subDayTimeFrames[g];
                const dimType = timeFrames_2.timeFrameConfigs[tf].getDimensionType(field_1.DimensionType.DATE);
                expect(dimType).toBe(field_1.DimensionType.TIMESTAMP);
            }
        });
        test('standard granularities not in SUB_DAY produce DATE', () => {
            const dayAndAbove = [
                {
                    granularity: timeFrames_1.DateGranularity.DAY,
                    timeFrame: timeFrames_1.TimeFrames.DAY,
                },
                {
                    granularity: timeFrames_1.DateGranularity.WEEK,
                    timeFrame: timeFrames_1.TimeFrames.WEEK,
                },
                {
                    granularity: timeFrames_1.DateGranularity.MONTH,
                    timeFrame: timeFrames_1.TimeFrames.MONTH,
                },
                {
                    granularity: timeFrames_1.DateGranularity.QUARTER,
                    timeFrame: timeFrames_1.TimeFrames.QUARTER,
                },
                {
                    granularity: timeFrames_1.DateGranularity.YEAR,
                    timeFrame: timeFrames_1.TimeFrames.YEAR,
                },
            ];
            for (const { granularity, timeFrame } of dayAndAbove) {
                expect((0, timeFrames_2.isSubDayGranularity)(granularity)).toBe(false);
                const dimType = timeFrames_2.timeFrameConfigs[timeFrame].getDimensionType(field_1.DimensionType.DATE);
                expect(dimType).toBe(field_1.DimensionType.DATE);
            }
        });
        test('identifies sub-day granularities correctly', () => {
            expect((0, timeFrames_2.isSubDayGranularity)(timeFrames_1.DateGranularity.SECOND)).toBe(true);
            expect((0, timeFrames_2.isSubDayGranularity)(timeFrames_1.DateGranularity.MINUTE)).toBe(true);
            expect((0, timeFrames_2.isSubDayGranularity)(timeFrames_1.DateGranularity.HOUR)).toBe(true);
            expect((0, timeFrames_2.isSubDayGranularity)(timeFrames_1.DateGranularity.DAY)).toBe(false);
            expect((0, timeFrames_2.isSubDayGranularity)(timeFrames_1.DateGranularity.YEAR)).toBe(false);
        });
    });
    describe('getDateDimension', () => {
        test('should parse dates', async () => {
            // Invalid date granularities
            expect((0, timeFrames_2.getDateDimension)('dimension')).toEqual({});
            expect((0, timeFrames_2.getDateDimension)('dimension_date')).toEqual({});
            expect((0, timeFrames_2.getDateDimension)('dimension_raw')).toEqual({});
            // Valid date granularities
            expect((0, timeFrames_2.getDateDimension)('dimension_second')).toEqual({
                baseDimensionId: `dimension`,
                newTimeFrame: timeFrames_1.TimeFrames.SECOND,
            });
            expect((0, timeFrames_2.getDateDimension)('dimension_minute')).toEqual({
                baseDimensionId: `dimension`,
                newTimeFrame: timeFrames_1.TimeFrames.MINUTE,
            });
            expect((0, timeFrames_2.getDateDimension)('dimension_hour')).toEqual({
                baseDimensionId: `dimension`,
                newTimeFrame: timeFrames_1.TimeFrames.HOUR,
            });
            expect((0, timeFrames_2.getDateDimension)('dimension_day')).toEqual({
                baseDimensionId: `dimension`,
                newTimeFrame: timeFrames_1.TimeFrames.DAY,
            });
            expect((0, timeFrames_2.getDateDimension)('table_my_dimension_day')).toEqual({
                baseDimensionId: `table_my_dimension`,
                newTimeFrame: timeFrames_1.TimeFrames.DAY,
            });
            expect((0, timeFrames_2.getDateDimension)('dimension_week')).toEqual({
                baseDimensionId: `dimension`,
                newTimeFrame: timeFrames_1.TimeFrames.WEEK,
            });
            expect((0, timeFrames_2.getDateDimension)('dimension_month')).toEqual({
                baseDimensionId: `dimension`,
                newTimeFrame: timeFrames_1.TimeFrames.MONTH,
            });
            expect((0, timeFrames_2.getDateDimension)('dimension_quarter')).toEqual({
                baseDimensionId: `dimension`,
                newTimeFrame: timeFrames_1.TimeFrames.QUARTER,
            });
            expect((0, timeFrames_2.getDateDimension)('dimension_year')).toEqual({
                baseDimensionId: `dimension`,
                newTimeFrame: timeFrames_1.TimeFrames.YEAR,
            });
        });
    });
    describe('dateTruncTimezoneConversions', () => {
        // Trino's client serializes `timestamp with time zone` as
        // "YYYY-MM-DD HH:mm:ss.SSS <zone>", which dayjs/moment can't parse.
        // `toUTC` must cast back to a naive `timestamp` so downstream parsing
        // works.
        test('Trino toUTC returns a naive timestamp at the correct UTC instant', () => {
            const { toUTC } = timeFrames_2.dateTruncTimezoneConversions[dbt_1.SupportedDbtAdapter.TRINO];
            expect(toUTC('truncated', 'America/New_York')).toEqual(`CAST(with_timezone(truncated, 'America/New_York') AT TIME ZONE 'UTC' AS timestamp)`);
        });
        test('Trino toProjectTz returns a naive timestamp in the project zone', () => {
            const { toProjectTz } = timeFrames_2.dateTruncTimezoneConversions[dbt_1.SupportedDbtAdapter.TRINO];
            expect(toProjectTz('column', 'America/New_York')).toEqual(`CAST(column AT TIME ZONE 'America/New_York' AS timestamp)`);
        });
        test('Athena mirrors Trino', () => {
            const trino = timeFrames_2.dateTruncTimezoneConversions[dbt_1.SupportedDbtAdapter.TRINO];
            const athena = timeFrames_2.dateTruncTimezoneConversions[dbt_1.SupportedDbtAdapter.ATHENA];
            expect(athena.toUTC('x', 'UTC')).toEqual(trino.toUTC('x', 'UTC'));
            expect(athena.toProjectTz('x', 'UTC')).toEqual(trino.toProjectTz('x', 'UTC'));
        });
        test('ClickHouse toProjectTz renders project-TZ wall-clock to a naive UTC-labelled DateTime64 (merge, ms-preserving)', () => {
            const { toProjectTz } = timeFrames_2.dateTruncTimezoneConversions[dbt_1.SupportedDbtAdapter.CLICKHOUSE];
            expect(toProjectTz('col', 'America/New_York')).toEqual(`toDateTime64(formatDateTime(toTimeZone(col, 'America/New_York'), '%Y-%m-%d %H:%i:%S.%f'), 3, 'UTC')`);
        });
        test('ClickHouse toUTC re-parses the truncated wall-clock as project-local, collapsing the DST fold (ms-preserving)', () => {
            const { toUTC } = timeFrames_2.dateTruncTimezoneConversions[dbt_1.SupportedDbtAdapter.CLICKHOUSE];
            expect(toUTC('truncated', 'America/New_York')).toEqual(`toTimeZone(toDateTime64(formatDateTime(truncated, '%Y-%m-%d %H:%i:%S.%f'), 3, 'America/New_York'), 'UTC')`);
        });
        test('BigQuery toProjectTz shifts a TIMESTAMP-coerced instant into a naive project-TZ DATETIME (merge)', () => {
            const { toProjectTz } = timeFrames_2.dateTruncTimezoneConversions[dbt_1.SupportedDbtAdapter.BIGQUERY];
            expect(toProjectTz('col', 'America/New_York')).toEqual(`DATETIME(TIMESTAMP(col), 'America/New_York')`);
        });
        test('BigQuery toUTC re-attaches the project zone to recover a real instant (merge)', () => {
            const { toUTC } = timeFrames_2.dateTruncTimezoneConversions[dbt_1.SupportedDbtAdapter.BIGQUERY];
            expect(toUTC('truncated', 'America/New_York')).toEqual(`TIMESTAMP(truncated, 'America/New_York')`);
        });
        test('Snowflake toProjectTz defaults sourceTimezone to UTC', () => {
            const { toProjectTz } = timeFrames_2.dateTruncTimezoneConversions[dbt_1.SupportedDbtAdapter.SNOWFLAKE];
            expect(toProjectTz('col', 'America/New_York')).toEqual(`CONVERT_TIMEZONE('UTC', 'America/New_York', col)`);
        });
        test('Snowflake toProjectTz threads explicit sourceTimezone into CONVERT_TIMEZONE', () => {
            const { toProjectTz } = timeFrames_2.dateTruncTimezoneConversions[dbt_1.SupportedDbtAdapter.SNOWFLAKE];
            expect(toProjectTz('col', 'America/New_York', 'America/New_York')).toEqual(`CONVERT_TIMEZONE('America/New_York', 'America/New_York', col)`);
        });
    });
    describe('getSqlForTruncatedDate type guard for DATE', () => {
        const tz = 'America/New_York';
        const col = 'my_col';
        test.each([
            [dbt_1.SupportedDbtAdapter.POSTGRES, `DATE_TRUNC('DAY', ${col})`],
            [dbt_1.SupportedDbtAdapter.REDSHIFT, `DATE_TRUNC('DAY', ${col})`],
            [dbt_1.SupportedDbtAdapter.DUCKDB, `DATE_TRUNC('DAY', ${col})`],
            [dbt_1.SupportedDbtAdapter.SNOWFLAKE, `DATE_TRUNC('DAY', ${col})`],
            [dbt_1.SupportedDbtAdapter.DATABRICKS, `DATE_TRUNC('DAY', ${col})`],
            [dbt_1.SupportedDbtAdapter.TRINO, `DATE_TRUNC('DAY', ${col})`],
            [dbt_1.SupportedDbtAdapter.ATHENA, `DATE_TRUNC('DAY', ${col})`],
            [dbt_1.SupportedDbtAdapter.CLICKHOUSE, `toStartOfDay(${col})`],
        ])('%s: DATE dimension with timezone skips tz round-trip', (adapter, expected) => {
            expect((0, timeFrames_2.getSqlForTruncatedDate)(adapter, timeFrames_1.TimeFrames.DAY, col, field_1.DimensionType.DATE, null, tz)).toEqual(expected);
        });
        test('TIMESTAMP dimension with timezone still gets tz round-trip (Postgres)', () => {
            expect((0, timeFrames_2.getSqlForTruncatedDate)(dbt_1.SupportedDbtAdapter.POSTGRES, timeFrames_1.TimeFrames.DAY, col, field_1.DimensionType.TIMESTAMP, null, tz)).toEqual(`(DATE_TRUNC('DAY', (${col})::timestamptz AT TIME ZONE '${tz}')) AT TIME ZONE '${tz}'`);
        });
        // GLITCH-452: with castDayOrCoarserToDate, a day-or-coarser trunc casts the
        // project-wall-clock value to DATE and drops the toUTC round-trip-back.
        test('day grain with castDayOrCoarserToDate casts the wall-clock trunc to DATE (Postgres)', () => {
            expect((0, timeFrames_2.getSqlForTruncatedDate)(dbt_1.SupportedDbtAdapter.POSTGRES, timeFrames_1.TimeFrames.DAY, col, field_1.DimensionType.TIMESTAMP, null, tz, undefined, true)).toEqual(`CAST(DATE_TRUNC('DAY', (${col})::timestamptz AT TIME ZONE '${tz}') AS DATE)`);
        });
        // GLITCH-452: sub-day grains are real instants — castDayOrCoarserToDate must
        // not cast them; they keep the TIMESTAMP round-trip.
        test('sub-day grain ignores castDayOrCoarserToDate and keeps the timestamp round-trip (Postgres)', () => {
            expect((0, timeFrames_2.getSqlForTruncatedDate)(dbt_1.SupportedDbtAdapter.POSTGRES, timeFrames_1.TimeFrames.HOUR, col, field_1.DimensionType.TIMESTAMP, null, tz, undefined, true)).toEqual(`(DATE_TRUNC('HOUR', (${col})::timestamptz AT TIME ZONE '${tz}')) AT TIME ZONE '${tz}'`);
        });
        // GLITCH-452: a UTC project short-circuits the round-trip, but day-grain
        // output must still be a real DATE.
        test('UTC project (no round-trip) still casts day grain to DATE (Postgres)', () => {
            expect((0, timeFrames_2.getSqlForTruncatedDate)(dbt_1.SupportedDbtAdapter.POSTGRES, timeFrames_1.TimeFrames.DAY, col, field_1.DimensionType.TIMESTAMP, null, 'UTC', undefined, true)).toEqual(`CAST(DATE_TRUNC('DAY', ${col}) AS DATE)`);
        });
        // GLITCH-509: BigQuery now shifts to a naive DATETIME before truncating,
        // so the day-grain trunc is already a tz-midnight wall-clock value and the
        // generic CAST(... AS DATE) reads the right calendar date (no positive-
        // offset off-by-one). Verified on BigQuery: Asia/Tokyo 15:00Z buckets to
        // the same calendar day.
        test('BigQuery day grain casts the naive DATETIME trunc to DATE (merge)', () => {
            expect((0, timeFrames_2.getSqlForTruncatedDate)(dbt_1.SupportedDbtAdapter.BIGQUERY, timeFrames_1.TimeFrames.DAY, col, field_1.DimensionType.TIMESTAMP, null, tz, undefined, true)).toEqual(`CAST(DATETIME_TRUNC(DATETIME(TIMESTAMP(${col}), '${tz}'), DAY) AS DATE)`);
        });
        test('TIMESTAMP dimension with timezone still gets tz round-trip (Snowflake)', () => {
            expect((0, timeFrames_2.getSqlForTruncatedDate)(dbt_1.SupportedDbtAdapter.SNOWFLAKE, timeFrames_1.TimeFrames.DAY, col, field_1.DimensionType.TIMESTAMP, null, tz)).toEqual(`CONVERT_TIMEZONE('${tz}', 'UTC', DATE_TRUNC('DAY', CONVERT_TIMEZONE('UTC', '${tz}', ${col})))`);
        });
        // When Snowflake's translator wrap is disabled and columns are stored
        // in dataTimezone, the inner CONVERT_TIMEZONE source must be that data
        // timezone — not the hardcoded 'UTC'.
        test('Snowflake threads non-UTC sourceTimezone into both CONVERT_TIMEZONE wraps', () => {
            const sourceTz = 'America/New_York';
            const queryTz = 'America/Los_Angeles';
            expect((0, timeFrames_2.getSqlForTruncatedDate)(dbt_1.SupportedDbtAdapter.SNOWFLAKE, timeFrames_1.TimeFrames.DAY, col, field_1.DimensionType.TIMESTAMP, null, queryTz, sourceTz)).toEqual(`CONVERT_TIMEZONE('${queryTz}', 'UTC', DATE_TRUNC('DAY', CONVERT_TIMEZONE('${sourceTz}', '${queryTz}', ${col})))`);
        });
    });
    describe('extractableTimeFrames', () => {
        test('contains numeric and Name EXTRACT-style intervals, not truncatable ones', () => {
            expect(timeFrames_2.extractableTimeFrames.has(timeFrames_1.TimeFrames.DAY_OF_WEEK_INDEX)).toBe(true);
            expect(timeFrames_2.extractableTimeFrames.has(timeFrames_1.TimeFrames.MONTH_NUM)).toBe(true);
            expect(timeFrames_2.extractableTimeFrames.has(timeFrames_1.TimeFrames.HOUR_OF_DAY_NUM)).toBe(true);
            expect(timeFrames_2.extractableTimeFrames.has(timeFrames_1.TimeFrames.DAY_OF_WEEK_NAME)).toBe(true);
            expect(timeFrames_2.extractableTimeFrames.has(timeFrames_1.TimeFrames.MONTH_NAME)).toBe(true);
            expect(timeFrames_2.extractableTimeFrames.has(timeFrames_1.TimeFrames.QUARTER_NAME)).toBe(true);
            expect(timeFrames_2.extractableTimeFrames.has(timeFrames_1.TimeFrames.DAY)).toBe(false);
            expect(timeFrames_2.extractableTimeFrames.has(timeFrames_1.TimeFrames.WEEK)).toBe(false);
            expect(timeFrames_2.extractableTimeFrames.has(timeFrames_1.TimeFrames.RAW)).toBe(false);
        });
    });
    describe('dateExtractsTimezoneConversions', () => {
        test('BigQuery coerces to TIMESTAMP and emits AT TIME ZONE inside the EXTRACT input', () => {
            expect(timeFrames_2.dateExtractsTimezoneConversions[dbt_1.SupportedDbtAdapter.BIGQUERY].toExtractInputTz('col', 'America/New_York')).toEqual(`TIMESTAMP(col) AT TIME ZONE 'America/New_York'`);
        });
        test('Snowflake uses CONVERT_TIMEZONE', () => {
            expect(timeFrames_2.dateExtractsTimezoneConversions[dbt_1.SupportedDbtAdapter.SNOWFLAKE].toExtractInputTz('col', 'America/New_York')).toEqual(`CONVERT_TIMEZONE('UTC', 'America/New_York', col)`);
        });
        test('Snowflake threads explicit sourceTimezone into CONVERT_TIMEZONE', () => {
            expect(timeFrames_2.dateExtractsTimezoneConversions[dbt_1.SupportedDbtAdapter.SNOWFLAKE].toExtractInputTz('col', 'America/New_York', 'America/New_York')).toEqual(`CONVERT_TIMEZONE('America/New_York', 'America/New_York', col)`);
        });
        test('Postgres / Redshift / DuckDB share the timestamptz cast form', () => {
            const expected = `(col)::timestamptz AT TIME ZONE 'America/New_York'`;
            expect(timeFrames_2.dateExtractsTimezoneConversions[dbt_1.SupportedDbtAdapter.POSTGRES].toExtractInputTz('col', 'America/New_York')).toEqual(expected);
            expect(timeFrames_2.dateExtractsTimezoneConversions[dbt_1.SupportedDbtAdapter.REDSHIFT].toExtractInputTz('col', 'America/New_York')).toEqual(expected);
            expect(timeFrames_2.dateExtractsTimezoneConversions[dbt_1.SupportedDbtAdapter.DUCKDB].toExtractInputTz('col', 'America/New_York')).toEqual(expected);
        });
        test('Trino / Athena cast back to naive timestamp', () => {
            const expected = `CAST(col AT TIME ZONE 'America/New_York' AS timestamp)`;
            expect(timeFrames_2.dateExtractsTimezoneConversions[dbt_1.SupportedDbtAdapter.TRINO].toExtractInputTz('col', 'America/New_York')).toEqual(expected);
            expect(timeFrames_2.dateExtractsTimezoneConversions[dbt_1.SupportedDbtAdapter.ATHENA].toExtractInputTz('col', 'America/New_York')).toEqual(expected);
        });
        test('Databricks composes from_utc/to_utc with current_timezone', () => {
            expect(timeFrames_2.dateExtractsTimezoneConversions[dbt_1.SupportedDbtAdapter.DATABRICKS].toExtractInputTz('col', 'America/New_York')).toEqual(`from_utc_timestamp(to_utc_timestamp(col, current_timezone()), 'America/New_York')`);
        });
        test('ClickHouse wraps with toTimeZone (mirrors DATE_TRUNC pattern)', () => {
            expect(timeFrames_2.dateExtractsTimezoneConversions[dbt_1.SupportedDbtAdapter.CLICKHOUSE].toExtractInputTz('col', 'America/New_York')).toEqual(`toTimeZone(col, 'America/New_York')`);
        });
    });
    describe('getSqlForDatePart with timezone', () => {
        const tz = 'America/New_York';
        const col = 'event_ts';
        // DAY_OF_WEEK_INDEX (no startOfWeek) — exercises the bare extract path.
        test.each([
            [
                dbt_1.SupportedDbtAdapter.BIGQUERY,
                `EXTRACT(DAYOFWEEK FROM TIMESTAMP(${col}) AT TIME ZONE '${tz}')`,
            ],
            [
                dbt_1.SupportedDbtAdapter.SNOWFLAKE,
                `DATE_PART('DOW', CONVERT_TIMEZONE('UTC', '${tz}', ${col}))`,
            ],
            [
                dbt_1.SupportedDbtAdapter.POSTGRES,
                `DATE_PART('DOW', (${col})::timestamptz AT TIME ZONE '${tz}')`,
            ],
            [
                dbt_1.SupportedDbtAdapter.REDSHIFT,
                `DATE_PART('DOW', (${col})::timestamptz AT TIME ZONE '${tz}')`,
            ],
            [
                dbt_1.SupportedDbtAdapter.DUCKDB,
                `DATE_PART('DOW', (${col})::timestamptz AT TIME ZONE '${tz}')`,
            ],
            [
                dbt_1.SupportedDbtAdapter.DATABRICKS,
                `DATE_PART('DOW', from_utc_timestamp(to_utc_timestamp(${col}, current_timezone()), '${tz}'))`,
            ],
            [
                dbt_1.SupportedDbtAdapter.TRINO,
                `EXTRACT(DOW FROM CAST(${col} AT TIME ZONE '${tz}' AS timestamp))`,
            ],
            [
                dbt_1.SupportedDbtAdapter.ATHENA,
                `EXTRACT(DOW FROM CAST(${col} AT TIME ZONE '${tz}' AS timestamp))`,
            ],
            [
                dbt_1.SupportedDbtAdapter.CLICKHOUSE,
                `toDayOfWeek(toTimeZone(${col}, '${tz}'))`,
            ],
        ])('%s: DAY_OF_WEEK_INDEX wraps input in tz', (adapter, expected) => {
            expect((0, timeFrames_2.getSqlForDatePart)(adapter, timeFrames_1.TimeFrames.DAY_OF_WEEK_INDEX, col, field_1.DimensionType.TIMESTAMP, null, tz)).toEqual(expected);
        });
        // MONTH_NUM — exercises the standard EXTRACT(part FROM ...) path.
        test.each([
            [
                dbt_1.SupportedDbtAdapter.BIGQUERY,
                `EXTRACT(MONTH FROM TIMESTAMP(${col}) AT TIME ZONE '${tz}')`,
            ],
            [
                dbt_1.SupportedDbtAdapter.SNOWFLAKE,
                `DATE_PART('MONTH', CONVERT_TIMEZONE('UTC', '${tz}', ${col}))`,
            ],
            [
                dbt_1.SupportedDbtAdapter.POSTGRES,
                `DATE_PART('MONTH', (${col})::timestamptz AT TIME ZONE '${tz}')`,
            ],
            [
                dbt_1.SupportedDbtAdapter.REDSHIFT,
                `DATE_PART('MONTH', (${col})::timestamptz AT TIME ZONE '${tz}')`,
            ],
            [
                dbt_1.SupportedDbtAdapter.DUCKDB,
                `DATE_PART('MONTH', (${col})::timestamptz AT TIME ZONE '${tz}')`,
            ],
            [
                dbt_1.SupportedDbtAdapter.DATABRICKS,
                `DATE_PART('MONTH', from_utc_timestamp(to_utc_timestamp(${col}, current_timezone()), '${tz}'))`,
            ],
            [
                dbt_1.SupportedDbtAdapter.TRINO,
                `EXTRACT(MONTH FROM CAST(${col} AT TIME ZONE '${tz}' AS timestamp))`,
            ],
            [
                dbt_1.SupportedDbtAdapter.ATHENA,
                `EXTRACT(MONTH FROM CAST(${col} AT TIME ZONE '${tz}' AS timestamp))`,
            ],
            [
                dbt_1.SupportedDbtAdapter.CLICKHOUSE,
                `toMonth(toTimeZone(${col}, '${tz}'))`,
            ],
        ])('%s: MONTH_NUM wraps input in tz', (adapter, expected) => {
            expect((0, timeFrames_2.getSqlForDatePart)(adapter, timeFrames_1.TimeFrames.MONTH_NUM, col, field_1.DimensionType.TIMESTAMP, null, tz)).toEqual(expected);
        });
        test('flag-off (no timezone arg): byte-identical to bare EXTRACT', () => {
            expect((0, timeFrames_2.getSqlForDatePart)(dbt_1.SupportedDbtAdapter.POSTGRES, timeFrames_1.TimeFrames.DAY_OF_WEEK_INDEX, col, field_1.DimensionType.TIMESTAMP)).toEqual(`DATE_PART('DOW', ${col})`);
            expect((0, timeFrames_2.getSqlForDatePart)(dbt_1.SupportedDbtAdapter.BIGQUERY, timeFrames_1.TimeFrames.MONTH_NUM, col, field_1.DimensionType.TIMESTAMP)).toEqual(`EXTRACT(MONTH FROM ${col})`);
        });
        test('target timezone matching source timezone short-circuits the wrap', () => {
            // UTC default source — most common BQ case, partition-pruning sensitive.
            expect((0, timeFrames_2.getSqlForDatePart)(dbt_1.SupportedDbtAdapter.BIGQUERY, timeFrames_1.TimeFrames.MONTH_NUM, col, field_1.DimensionType.TIMESTAMP, null, 'UTC')).toEqual(`EXTRACT(MONTH FROM ${col})`);
            expect((0, timeFrames_2.getSqlForDatePart)(dbt_1.SupportedDbtAdapter.POSTGRES, timeFrames_1.TimeFrames.DAY_OF_WEEK_INDEX, col, field_1.DimensionType.TIMESTAMP, null, 'UTC')).toEqual(`DATE_PART('DOW', ${col})`);
            // Explicit matching non-UTC pair.
            expect((0, timeFrames_2.getSqlForDatePart)(dbt_1.SupportedDbtAdapter.BIGQUERY, timeFrames_1.TimeFrames.MONTH_NUM, col, field_1.DimensionType.TIMESTAMP, null, 'America/New_York', 'America/New_York')).toEqual(`EXTRACT(MONTH FROM ${col})`);
            expect((0, timeFrames_2.getSqlForDatePart)(dbt_1.SupportedDbtAdapter.POSTGRES, timeFrames_1.TimeFrames.DAY_OF_WEEK_INDEX, col, field_1.DimensionType.TIMESTAMP, null, 'America/New_York', 'America/New_York')).toEqual(`DATE_PART('DOW', ${col})`);
        });
        test('DATE base dimension with timezone short-circuits (no wrap)', () => {
            expect((0, timeFrames_2.getSqlForDatePart)(dbt_1.SupportedDbtAdapter.POSTGRES, timeFrames_1.TimeFrames.DAY_OF_WEEK_INDEX, col, field_1.DimensionType.DATE, null, tz)).toEqual(`DATE_PART('DOW', ${col})`);
            expect((0, timeFrames_2.getSqlForDatePart)(dbt_1.SupportedDbtAdapter.BIGQUERY, timeFrames_1.TimeFrames.MONTH_NUM, col, field_1.DimensionType.DATE, null, tz)).toEqual(`EXTRACT(MONTH FROM ${col})`);
        });
        test('WEEK_NUM with non-default startOfWeek composes with the tz wrap (Postgres)', () => {
            expect((0, timeFrames_2.getSqlForDatePart)(dbt_1.SupportedDbtAdapter.POSTGRES, timeFrames_1.TimeFrames.WEEK_NUM, col, field_1.DimensionType.TIMESTAMP, timeFrames_2.WeekDay.WEDNESDAY, tz)).toEqual(`DATE_PART('WEEK', ((${col})::timestamptz AT TIME ZONE '${tz}' - interval '2 days'))`);
        });
        test('WEEK_NUM with non-default startOfWeek composes with the tz wrap (BigQuery)', () => {
            expect((0, timeFrames_2.getSqlForDatePart)(dbt_1.SupportedDbtAdapter.BIGQUERY, timeFrames_1.TimeFrames.WEEK_NUM, col, field_1.DimensionType.TIMESTAMP, timeFrames_2.WeekDay.WEDNESDAY, tz)).toEqual(`EXTRACT(WEEK(WEDNESDAY) FROM TIMESTAMP(${col}) AT TIME ZONE '${tz}')`);
        });
        test('DAY_OF_WEEK_INDEX with startOfWeek composes mod arithmetic with tz wrap (Postgres)', () => {
            expect((0, timeFrames_2.getSqlForDatePart)(dbt_1.SupportedDbtAdapter.POSTGRES, timeFrames_1.TimeFrames.DAY_OF_WEEK_INDEX, col, field_1.DimensionType.TIMESTAMP, timeFrames_2.WeekDay.MONDAY, tz)).toEqual(`MOD(CAST(DATE_PART('DOW', (${col})::timestamptz AT TIME ZONE '${tz}') AS INT) - 1 + 7, 7) + 1`);
        });
        test('DAY_OF_WEEK_INDEX with startOfWeek composes mod arithmetic with tz wrap (BigQuery)', () => {
            expect((0, timeFrames_2.getSqlForDatePart)(dbt_1.SupportedDbtAdapter.BIGQUERY, timeFrames_1.TimeFrames.DAY_OF_WEEK_INDEX, col, field_1.DimensionType.TIMESTAMP, timeFrames_2.WeekDay.MONDAY, tz)).toEqual(`MOD(EXTRACT(DAYOFWEEK FROM TIMESTAMP(${col}) AT TIME ZONE '${tz}') - 2 + 7, 7) + 1`);
        });
        // Snowflake EXTRACT path must use the column's actual source timezone
        // when the translator wrap is disabled.
        test('Snowflake threads non-UTC sourceTimezone into EXTRACT input wrap', () => {
            const sourceTz = 'America/New_York';
            const queryTz = 'America/Los_Angeles';
            expect((0, timeFrames_2.getSqlForDatePart)(dbt_1.SupportedDbtAdapter.SNOWFLAKE, timeFrames_1.TimeFrames.MONTH_NUM, col, field_1.DimensionType.TIMESTAMP, null, queryTz, sourceTz)).toEqual(`DATE_PART('MONTH', CONVERT_TIMEZONE('${sourceTz}', '${queryTz}', ${col}))`);
        });
    });
    describe('getSqlForDatePartName with timezone (Name variants)', () => {
        const tz = 'America/New_York';
        const col = 'event_ts';
        test.each([
            [
                dbt_1.SupportedDbtAdapter.BIGQUERY,
                `FORMAT_TIMESTAMP('%A', TIMESTAMP(${col}), '${tz}')`,
            ],
            [
                dbt_1.SupportedDbtAdapter.POSTGRES,
                `TO_CHAR((${col})::timestamptz AT TIME ZONE '${tz}', 'FMDay')`,
            ],
            [
                dbt_1.SupportedDbtAdapter.SNOWFLAKE,
                `DECODE(TO_CHAR(CONVERT_TIMEZONE('UTC', '${tz}', ${col}), 'DY'), 'Mon', 'Monday', 'Tue', 'Tuesday', 'Wed', 'Wednesday', 'Thu', 'Thursday', 'Fri', 'Friday', 'Sat', 'Saturday', 'Sun', 'Sunday')`,
            ],
            [
                dbt_1.SupportedDbtAdapter.DATABRICKS,
                `DATE_FORMAT(from_utc_timestamp(to_utc_timestamp(${col}, current_timezone()), '${tz}'), 'EEEE')`,
            ],
            [
                dbt_1.SupportedDbtAdapter.CLICKHOUSE,
                `dateName('weekday', toTimeZone(${col}, '${tz}'))`,
            ],
            [
                dbt_1.SupportedDbtAdapter.TRINO,
                `date_format(CAST(${col} AT TIME ZONE '${tz}' AS timestamp), '%W')`,
            ],
        ])('%s: DAY_OF_WEEK_NAME wraps input in tz', (adapter, expected) => {
            expect((0, timeFrames_2.getSqlForDatePartName)(adapter, timeFrames_1.TimeFrames.DAY_OF_WEEK_NAME, col, field_1.DimensionType.TIMESTAMP, null, tz)).toEqual(expected);
        });
        test('DATE base dimension with timezone short-circuits (Postgres)', () => {
            expect((0, timeFrames_2.getSqlForDatePartName)(dbt_1.SupportedDbtAdapter.POSTGRES, timeFrames_1.TimeFrames.MONTH_NAME, col, field_1.DimensionType.DATE, null, tz)).toEqual(`TO_CHAR(${col}, 'FMMonth')`);
        });
        test('flag-off: byte-identical to bare format', () => {
            expect((0, timeFrames_2.getSqlForDatePartName)(dbt_1.SupportedDbtAdapter.POSTGRES, timeFrames_1.TimeFrames.MONTH_NAME, col, field_1.DimensionType.TIMESTAMP)).toEqual(`TO_CHAR(${col}, 'FMMonth')`);
            expect((0, timeFrames_2.getSqlForDatePartName)(dbt_1.SupportedDbtAdapter.BIGQUERY, timeFrames_1.TimeFrames.MONTH_NAME, col, field_1.DimensionType.TIMESTAMP)).toEqual(`FORMAT_DATETIME('%B', ${col})`);
        });
        test('target timezone matching source timezone short-circuits the wrap', () => {
            expect((0, timeFrames_2.getSqlForDatePartName)(dbt_1.SupportedDbtAdapter.BIGQUERY, timeFrames_1.TimeFrames.MONTH_NAME, col, field_1.DimensionType.TIMESTAMP, null, 'UTC')).toEqual(`FORMAT_DATETIME('%B', ${col})`);
            expect((0, timeFrames_2.getSqlForDatePartName)(dbt_1.SupportedDbtAdapter.POSTGRES, timeFrames_1.TimeFrames.MONTH_NAME, col, field_1.DimensionType.TIMESTAMP, null, 'America/New_York', 'America/New_York')).toEqual(`TO_CHAR(${col}, 'FMMonth')`);
            expect((0, timeFrames_2.getSqlForDatePartName)(dbt_1.SupportedDbtAdapter.BIGQUERY, timeFrames_1.TimeFrames.MONTH_NAME, col, field_1.DimensionType.TIMESTAMP, null, 'America/New_York', 'America/New_York')).toEqual(`FORMAT_DATETIME('%B', ${col})`);
        });
        test.each([
            [timeFrames_1.TimeFrames.DAY_OF_WEEK_NAME, '%A'],
            [timeFrames_1.TimeFrames.MONTH_NAME, '%B'],
            [timeFrames_1.TimeFrames.QUARTER_NAME, 'Q%Q'],
        ])('BigQuery %s: native FORMAT_TIMESTAMP with tz arg (no AT TIME ZONE)', (timeFrame, format) => {
            expect((0, timeFrames_2.getSqlForDatePartName)(dbt_1.SupportedDbtAdapter.BIGQUERY, timeFrame, col, field_1.DimensionType.TIMESTAMP, null, tz)).toEqual(`FORMAT_TIMESTAMP('${format}', TIMESTAMP(${col}), '${tz}')`);
        });
    });
    describe('getTimeFramesWithProjectDefaults', () => {
        it('returns built-in defaults unchanged when no additions are given', () => {
            expect((0, timeFrames_2.getTimeFramesWithProjectDefaults)(field_1.DimensionType.DATE)).toEqual([
                timeFrames_1.TimeFrames.DAY,
                timeFrames_1.TimeFrames.WEEK,
                timeFrames_1.TimeFrames.MONTH,
                timeFrames_1.TimeFrames.QUARTER,
                timeFrames_1.TimeFrames.YEAR,
            ]);
            expect((0, timeFrames_2.getTimeFramesWithProjectDefaults)(field_1.DimensionType.TIMESTAMP)).toEqual([
                timeFrames_1.TimeFrames.RAW,
                timeFrames_1.TimeFrames.DAY,
                timeFrames_1.TimeFrames.WEEK,
                timeFrames_1.TimeFrames.MONTH,
                timeFrames_1.TimeFrames.QUARTER,
                timeFrames_1.TimeFrames.YEAR,
            ]);
        });
        it('appends timestamp additions after the built-in defaults', () => {
            expect((0, timeFrames_2.getTimeFramesWithProjectDefaults)(field_1.DimensionType.TIMESTAMP, {
                date: [],
                timestamp: [timeFrames_1.TimeFrames.HOUR],
            })).toEqual([
                timeFrames_1.TimeFrames.RAW,
                timeFrames_1.TimeFrames.DAY,
                timeFrames_1.TimeFrames.WEEK,
                timeFrames_1.TimeFrames.MONTH,
                timeFrames_1.TimeFrames.QUARTER,
                timeFrames_1.TimeFrames.YEAR,
                timeFrames_1.TimeFrames.HOUR,
            ]);
        });
        it('appends a custom granularity name for date dimensions', () => {
            expect((0, timeFrames_2.getTimeFramesWithProjectDefaults)(field_1.DimensionType.DATE, {
                date: ['fiscal_week'],
                timestamp: [],
            })).toEqual([
                timeFrames_1.TimeFrames.DAY,
                timeFrames_1.TimeFrames.WEEK,
                timeFrames_1.TimeFrames.MONTH,
                timeFrames_1.TimeFrames.QUARTER,
                timeFrames_1.TimeFrames.YEAR,
                'fiscal_week',
            ]);
        });
        it('de-duplicates an addition that already exists in the built-in defaults', () => {
            expect((0, timeFrames_2.getTimeFramesWithProjectDefaults)(field_1.DimensionType.DATE, {
                date: [timeFrames_1.TimeFrames.DAY],
                timestamp: [],
            })).toEqual([
                timeFrames_1.TimeFrames.DAY,
                timeFrames_1.TimeFrames.WEEK,
                timeFrames_1.TimeFrames.MONTH,
                timeFrames_1.TimeFrames.QUARTER,
                timeFrames_1.TimeFrames.YEAR,
            ]);
        });
    });
});
//# sourceMappingURL=timeFrames.test.js.map