"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const field_1 = require("../types/field");
const filter_1 = require("../types/filter");
const timeFrames_1 = require("../types/timeFrames");
const filters_1 = require("./filters");
const filters_mock_1 = require("./filters.mock");
jest.mock('uuid', () => ({
    v4: jest.fn(() => 'uuid'),
}));
describe('addDashboardFiltersToMetricQuery', () => {
    test('should override the chart AND filter group with dashboard filters', async () => {
        const result = (0, filters_1.addDashboardFiltersToMetricQuery)(filters_mock_1.metricQueryWithAndFilters, filters_mock_1.dashboardFilters);
        expect(result).toEqual(filters_mock_1.expectedChartWithOverrideDashboardFilters);
    });
    test('should override the chart OR filter group with dashboard filters', async () => {
        const result = (0, filters_1.addDashboardFiltersToMetricQuery)(filters_mock_1.metricQueryWithOrFilters, filters_mock_1.dashboardFilters);
        expect(result).toEqual(filters_mock_1.expectedChartWithOverrideDashboardORFilters);
    });
    test('should merge dashboard metric filters into the metric query', () => {
        const result = (0, filters_1.addDashboardFiltersToMetricQuery)(filters_mock_1.metricQueryWithAndFilters, filters_mock_1.dashboardFiltersWithMetrics);
        expect(result.filters.metrics).toBeDefined();
        expect(result.filters.metrics.and).toHaveLength(1);
        expect(result.filters.metrics.and[0]).toMatchObject({
            target: { fieldId: 'a_metric1' },
            operator: filter_1.FilterOperator.GREATER_THAN,
            values: [100],
        });
    });
    test('should override existing chart metric filter with same target from dashboard', () => {
        const result = (0, filters_1.addDashboardFiltersToMetricQuery)(filters_mock_1.metricQueryWithExistingMetricFilters, filters_mock_1.dashboardFiltersWithMetrics);
        expect(result.filters.metrics).toBeDefined();
        const metricFilters = result.filters.metrics.and;
        // Dashboard metric filter overrides the existing chart metric filter with same fieldId
        expect(metricFilters).toContainEqual(expect.objectContaining({
            target: { fieldId: 'a_metric1' },
            operator: filter_1.FilterOperator.GREATER_THAN,
            values: [100],
        }));
    });
    test('should return metric query unchanged when dashboard has no filters', () => {
        const result = (0, filters_1.addDashboardFiltersToMetricQuery)(filters_mock_1.metricQueryWithAndFilters, filters_mock_1.emptyDashboardFilters);
        expect(result.filters.dimensions).toBeDefined();
        expect(result.filters.metrics.and).toHaveLength(0);
        expect(result.filters.tableCalculations.and).toHaveLength(0);
    });
    test('should not affect dimension filters when adding metric filters', () => {
        const result = (0, filters_1.addDashboardFiltersToMetricQuery)(filters_mock_1.metricQueryWithAndFilters, filters_mock_1.dashboardFiltersWithMetrics);
        expect(result.filters.dimensions.and).toContainEqual(expect.objectContaining({
            target: { fieldId: 'a_dim1' },
            operator: filter_1.FilterOperator.EQUALS,
            values: ['1', '2', '3'],
        }));
    });
});
describe('overrideChartFilter', () => {
    test('should override the chart and group filter', async () => {
        const result = (0, filters_1.overrideChartFilter)(filters_mock_1.chartAndFilterGroup, filters_mock_1.dashboardFilterWithSameTargetAndOperator, {});
        expect(result).toEqual({
            id: 'fillter-group-1',
            and: [
                {
                    id: '5',
                    target: { fieldId: 'field-1' },
                    values: ['1', '2', '3'],
                    disabled: false,
                    operator: filter_1.FilterOperator.EQUALS,
                },
                {
                    id: '2',
                    target: { fieldId: 'field-2' },
                    values: ['2'],
                    disabled: false,
                    operator: filter_1.FilterOperator.EQUALS,
                },
            ],
        });
    });
    test('should override the chart or group filter', async () => {
        const result = (0, filters_1.overrideChartFilter)(filters_mock_1.chartOrFilterGroup, filters_mock_1.dashboardFilterWithSameTargetAndOperator, {});
        expect(result).toEqual({
            id: 'fillter-group-1',
            or: [
                {
                    id: '5',
                    target: { fieldId: 'field-1' },
                    values: ['1', '2', '3'],
                    disabled: false,
                    operator: filter_1.FilterOperator.EQUALS,
                },
                {
                    id: '4',
                    target: { fieldId: 'field-2' },
                    values: ['2'],
                    disabled: false,
                    operator: filter_1.FilterOperator.EQUALS,
                },
            ],
        });
    });
    test('should override the chart group filter when operator is different', async () => {
        const result = (0, filters_1.overrideChartFilter)(filters_mock_1.chartAndFilterGroup, filters_mock_1.dashboardFilterWithSameTargetButDifferentOperator, {});
        expect(result).toEqual({
            id: 'fillter-group-1',
            and: [
                {
                    id: '5',
                    target: { fieldId: 'field-1' },
                    values: ['1', '2', '3'],
                    disabled: false,
                    operator: filter_1.FilterOperator.NOT_EQUALS,
                },
                {
                    id: '2',
                    target: { fieldId: 'field-2' },
                    values: ['2'],
                    disabled: false,
                    operator: filter_1.FilterOperator.EQUALS,
                },
            ],
        });
    });
});
describe('addFilterRule', () => {
    test('should add custom sql dimension filter to dimensions group', async () => {
        const result = (0, filters_1.addFilterRule)({
            filters: {},
            field: filters_mock_1.customSqlDimension,
        });
        expect(result).toEqual(filters_mock_1.expectedFiltersWithCustomSqlDimension);
    });
});
describe('createFilterRuleFromField — time-interval DATE dims', () => {
    const monthDim = (baseType) => ({
        ...(0, filters_mock_1.dimension)('created_at_month', 'orders'),
        type: field_1.DimensionType.DATE,
        timeInterval: timeFrames_1.TimeFrames.MONTH,
        timeIntervalBaseDimensionName: 'created_at',
        timeIntervalBaseDimensionType: baseType,
    });
    // Paris Nov 2024 = 2024-10-31T23:00:00Z (UTC instant emitted by the
    // DATE_TRUNC round-trip for a TIMESTAMP-base interval).
    const parisNovInstant = '2024-10-31T23:00:00Z';
    // NY Nov 2024 = 2024-11-01T05:00:00Z.
    const nyNovInstant = '2024-11-01T05:00:00Z';
    // DATE-base interval emits a calendar value anchored at UTC midnight.
    const dateBaseNov = '2024-11-01T00:00:00Z';
    test('TIMESTAMP-base: positive offset filter value matches displayed month', () => {
        const rule = (0, filters_1.createFilterRuleFromField)(monthDim(field_1.DimensionType.TIMESTAMP), parisNovInstant, 'Europe/Paris');
        expect(rule.values).toEqual(['2024-11']);
    });
    test('TIMESTAMP-base: negative offset filter value matches displayed month', () => {
        const rule = (0, filters_1.createFilterRuleFromField)(monthDim(field_1.DimensionType.TIMESTAMP), nyNovInstant, 'America/New_York');
        expect(rule.values).toEqual(['2024-11']);
    });
    test('TIMESTAMP-base: no timezone falls back to UTC extraction (pre-fix behavior)', () => {
        const rule = (0, filters_1.createFilterRuleFromField)(monthDim(field_1.DimensionType.TIMESTAMP), parisNovInstant);
        // Without project TZ, the UTC instant's calendar month is October.
        expect(rule.values).toEqual(['2024-10']);
    });
    test('DATE-base: negative offset must NOT shift the calendar date back', () => {
        const rule = (0, filters_1.createFilterRuleFromField)(monthDim(field_1.DimensionType.DATE), dateBaseNov, 'America/New_York');
        // Shifting "Nov 1 UTC" into NY would land on Oct 31 — must not happen.
        expect(rule.values).toEqual(['2024-11']);
    });
    test('DATE-base: positive offset also stays on the calendar date', () => {
        const rule = (0, filters_1.createFilterRuleFromField)(monthDim(field_1.DimensionType.DATE), dateBaseNov, 'Asia/Tokyo');
        expect(rule.values).toEqual(['2024-11']);
    });
    test('plain DATE column (no timeInterval): negative offset must NOT shift', () => {
        const plainDateDim = {
            ...(0, filters_mock_1.dimension)('order_date', 'orders'),
            type: field_1.DimensionType.DATE,
        };
        const rule = (0, filters_1.createFilterRuleFromField)(plainDateDim, '2024-11-01', 'America/New_York');
        // Plain DATE columns are calendar values — shifting into NY would
        // land on Oct 31 and silently corrupt the filter.
        expect(rule.values).toEqual(['2024-11-01']);
    });
    test('plain DATE column (no timeInterval): positive offset must NOT shift', () => {
        const plainDateDim = {
            ...(0, filters_mock_1.dimension)('order_date', 'orders'),
            type: field_1.DimensionType.DATE,
        };
        const rule = (0, filters_1.createFilterRuleFromField)(plainDateDim, '2024-11-01', 'Asia/Tokyo');
        expect(rule.values).toEqual(['2024-11-01']);
    });
});
describe('createFilterRuleFromModelRequiredFilterRule', () => {
    test('should create a correct FilterRule', () => {
        const result = (0, filters_1.createFilterRuleFromModelRequiredFilterRule)((0, filters_mock_1.modelRequiredFilterRule)('dimension'), 'tableName');
        expect(result).toEqual((0, filters_mock_1.expectedRequiredResult)('dimension', 'tableName'));
    });
});
describe('isFilterRuleInQuery', () => {
    test('should correctly determine if a filter rule is in the query', () => {
        const filterGroupWithFilterRule = {
            id: 'mockGroupId',
            and: [filters_mock_1.filterRule],
        };
        const filterGroupWithoutFilterRule = {
            id: 'mockGroupId',
            and: [],
        };
        expect((0, filters_1.isFilterRuleInQuery)((0, filters_mock_1.dimension)('dim', 'table'), filters_mock_1.filterRule, filterGroupWithFilterRule, filters_mock_1.mockExplore)).toEqual(true);
        expect((0, filters_1.isFilterRuleInQuery)((0, filters_mock_1.dimension)('dim', 'table'), filters_mock_1.filterRule, filterGroupWithoutFilterRule, filters_mock_1.mockExplore)).toEqual(false);
    });
    test('should not treat string-derived time dimensions as satisfying required date filters', () => {
        const exploreWithStringDerivedTimeDimension = {
            ...filters_mock_1.mockExplore,
            tables: {
                ...filters_mock_1.mockExplore.tables,
                orders: {
                    ...filters_mock_1.mockExplore.tables.orders,
                    dimensions: {
                        ...filters_mock_1.mockExplore.tables.orders.dimensions,
                        order_date: {
                            name: 'order_date',
                            label: 'Order Date',
                            table: 'orders',
                            tableLabel: 'Orders',
                            compiledSql: 'order_date',
                            tablesReferences: [],
                            sql: 'order_date',
                            hidden: false,
                            fieldType: field_1.FieldType.DIMENSION,
                            type: field_1.DimensionType.DATE,
                            isIntervalBase: true,
                        },
                        order_date_fiscal_quarter: {
                            name: 'order_date_fiscal_quarter',
                            label: 'Order Date Fiscal Quarter',
                            table: 'orders',
                            tableLabel: 'Orders',
                            compiledSql: 'order_date_fiscal_quarter',
                            tablesReferences: [],
                            sql: 'order_date_fiscal_quarter',
                            hidden: false,
                            fieldType: field_1.FieldType.DIMENSION,
                            type: field_1.DimensionType.STRING,
                            timeIntervalBaseDimensionName: 'order_date',
                            customTimeInterval: 'fiscal_quarter',
                        },
                    },
                },
            },
        };
        const requiredFilter = (0, filters_mock_1.expectedRequiredResult)('order_date', 'orders');
        const filtersWithOnlyStringDerivedDimension = {
            id: 'mockGroupId',
            and: [
                {
                    id: 'string-derived-filter',
                    target: { fieldId: 'orders_order_date_fiscal_quarter' },
                    operator: filter_1.FilterOperator.EQUALS,
                    values: ['FY2024-Q1'],
                },
            ],
        };
        expect((0, filters_1.isFilterRuleInQuery)(exploreWithStringDerivedTimeDimension.tables.orders.dimensions
            .order_date, requiredFilter, filtersWithOnlyStringDerivedDimension, exploreWithStringDerivedTimeDimension)).toEqual(false);
    });
    test('should treat date-derived time dimensions as satisfying required date filters', () => {
        const exploreWithDateDerivedTimeDimension = {
            ...filters_mock_1.mockExplore,
            tables: {
                ...filters_mock_1.mockExplore.tables,
                orders: {
                    ...filters_mock_1.mockExplore.tables.orders,
                    dimensions: {
                        ...filters_mock_1.mockExplore.tables.orders.dimensions,
                        order_date: {
                            name: 'order_date',
                            label: 'Order Date',
                            table: 'orders',
                            tableLabel: 'Orders',
                            compiledSql: 'order_date',
                            tablesReferences: [],
                            sql: 'order_date',
                            hidden: false,
                            fieldType: field_1.FieldType.DIMENSION,
                            type: field_1.DimensionType.DATE,
                            isIntervalBase: true,
                        },
                        order_date_biweekly: {
                            name: 'order_date_biweekly',
                            label: 'Order Date Biweekly',
                            table: 'orders',
                            tableLabel: 'Orders',
                            compiledSql: 'order_date_biweekly',
                            tablesReferences: [],
                            sql: 'order_date_biweekly',
                            hidden: false,
                            fieldType: field_1.FieldType.DIMENSION,
                            type: field_1.DimensionType.DATE,
                            timeIntervalBaseDimensionName: 'order_date',
                            customTimeInterval: 'biweekly',
                        },
                    },
                },
            },
        };
        const requiredFilter = (0, filters_mock_1.expectedRequiredResult)('order_date', 'orders');
        const filtersWithOnlyDateDerivedDimension = {
            id: 'mockGroupId',
            and: [
                {
                    id: 'date-derived-filter',
                    target: { fieldId: 'orders_order_date_biweekly' },
                    operator: filter_1.FilterOperator.IN_THE_PAST,
                    values: [14],
                    settings: {
                        unitOfTime: 'days',
                    },
                },
            ],
        };
        expect((0, filters_1.isFilterRuleInQuery)(exploreWithDateDerivedTimeDimension.tables.orders.dimensions
            .order_date, requiredFilter, filtersWithOnlyDateDerivedDimension, exploreWithDateDerivedTimeDimension)).toEqual(true);
    });
    test('should require an exact match when the required filter targets a custom derived time dimension', () => {
        const exploreWithSiblingStringDerivedTimeDimensions = {
            ...filters_mock_1.mockExplore,
            tables: {
                ...filters_mock_1.mockExplore.tables,
                orders: {
                    ...filters_mock_1.mockExplore.tables.orders,
                    dimensions: {
                        ...filters_mock_1.mockExplore.tables.orders.dimensions,
                        order_date: {
                            name: 'order_date',
                            label: 'Order Date',
                            table: 'orders',
                            tableLabel: 'Orders',
                            compiledSql: 'order_date',
                            tablesReferences: [],
                            sql: 'order_date',
                            hidden: false,
                            fieldType: field_1.FieldType.DIMENSION,
                            type: field_1.DimensionType.DATE,
                            isIntervalBase: true,
                        },
                        order_date_fiscal_year: {
                            name: 'order_date_fiscal_year',
                            label: 'Order Date Fiscal Year',
                            table: 'orders',
                            tableLabel: 'Orders',
                            compiledSql: 'order_date_fiscal_year',
                            tablesReferences: [],
                            sql: 'order_date_fiscal_year',
                            hidden: false,
                            fieldType: field_1.FieldType.DIMENSION,
                            type: field_1.DimensionType.STRING,
                            timeIntervalBaseDimensionName: 'order_date',
                            customTimeInterval: 'fiscal_year',
                        },
                        order_date_fiscal_quarter: {
                            name: 'order_date_fiscal_quarter',
                            label: 'Order Date Fiscal Quarter',
                            table: 'orders',
                            tableLabel: 'Orders',
                            compiledSql: 'order_date_fiscal_quarter',
                            tablesReferences: [],
                            sql: 'order_date_fiscal_quarter',
                            hidden: false,
                            fieldType: field_1.FieldType.DIMENSION,
                            type: field_1.DimensionType.STRING,
                            timeIntervalBaseDimensionName: 'order_date',
                            customTimeInterval: 'fiscal_quarter',
                        },
                    },
                },
            },
        };
        const requiredFilter = (0, filters_mock_1.expectedRequiredResult)('order_date_fiscal_year', 'orders');
        const filtersWithSiblingDerivedDimensionOnly = {
            id: 'mockGroupId',
            and: [
                {
                    id: 'sibling-derived-filter',
                    target: { fieldId: 'orders_order_date_fiscal_quarter' },
                    operator: filter_1.FilterOperator.EQUALS,
                    values: ['FY2024-Q1'],
                },
            ],
        };
        expect((0, filters_1.isFilterRuleInQuery)(exploreWithSiblingStringDerivedTimeDimensions.tables.orders
            .dimensions.order_date_fiscal_year, requiredFilter, filtersWithSiblingDerivedDimensionOnly, exploreWithSiblingStringDerivedTimeDimensions)).toEqual(false);
    });
    test('should allow sibling standard time dimensions when the required filter targets a standard derived time dimension', () => {
        const exploreWithStandardDerivedTimeDimensions = {
            ...filters_mock_1.mockExplore,
            tables: {
                ...filters_mock_1.mockExplore.tables,
                orders: {
                    ...filters_mock_1.mockExplore.tables.orders,
                    dimensions: {
                        ...filters_mock_1.mockExplore.tables.orders.dimensions,
                        order_date_week: {
                            ...filters_mock_1.mockExplore.tables.orders.dimensions
                                .order_date_week,
                            timeInterval: timeFrames_1.TimeFrames.WEEK,
                        },
                        order_date_month: {
                            ...filters_mock_1.mockExplore.tables.orders.dimensions
                                .order_date_month,
                            timeInterval: timeFrames_1.TimeFrames.MONTH,
                        },
                    },
                },
            },
        };
        const requiredFilter = (0, filters_mock_1.expectedRequiredResult)('order_date_week', 'orders');
        const filtersWithSiblingStandardDimension = {
            id: 'mockGroupId',
            and: [
                {
                    id: 'sibling-standard-filter',
                    target: { fieldId: 'orders_order_date_month' },
                    operator: filter_1.FilterOperator.EQUALS,
                    values: ['2024-09-01'],
                },
            ],
        };
        expect((0, filters_1.isFilterRuleInQuery)(exploreWithStandardDerivedTimeDimensions.tables.orders
            .dimensions.order_date_week, requiredFilter, filtersWithSiblingStandardDimension, exploreWithStandardDerivedTimeDimensions)).toEqual(true);
    });
});
describe('reduceRequiredDimensionFiltersToFilterRules', () => {
    test('should correctly reduce required dimension filters to filter rules', () => {
        // Define mock data
        const mockRequiredFilters = [
            (0, filters_mock_1.modelRequiredFilterRule)('order_date_week'),
            (0, filters_mock_1.joinedModelRequiredFilterRule)('customers.created_at_week', 'customers'),
        ];
        const emptyFilters = {
            dimensions: {
                id: 'mockGroupId',
                and: [],
            },
        };
        const result = (0, filters_1.reduceRequiredDimensionFiltersToFilterRules)(mockRequiredFilters, emptyFilters.dimensions, filters_mock_1.mockExploreWithJoinedTable);
        const expectedFilterRuleResult = [
            (0, filters_mock_1.expectedRequiredResult)('order_date_week', 'orders'),
            (0, filters_mock_1.expectedRequiredResult)('created_at_week', 'customers'),
        ];
        expect(result).toEqual(expectedFilterRuleResult);
    });
    test('should keep required date filters when only string-derived time filters are present', () => {
        const exploreWithStringDerivedTimeDimension = {
            ...filters_mock_1.mockExplore,
            tables: {
                ...filters_mock_1.mockExplore.tables,
                orders: {
                    ...filters_mock_1.mockExplore.tables.orders,
                    dimensions: {
                        ...filters_mock_1.mockExplore.tables.orders.dimensions,
                        order_date: {
                            name: 'order_date',
                            label: 'Order Date',
                            table: 'orders',
                            tableLabel: 'Orders',
                            compiledSql: 'order_date',
                            tablesReferences: [],
                            sql: 'order_date',
                            hidden: false,
                            fieldType: field_1.FieldType.DIMENSION,
                            type: field_1.DimensionType.DATE,
                            isIntervalBase: true,
                        },
                        order_date_fiscal_quarter: {
                            name: 'order_date_fiscal_quarter',
                            label: 'Order Date Fiscal Quarter',
                            table: 'orders',
                            tableLabel: 'Orders',
                            compiledSql: 'order_date_fiscal_quarter',
                            tablesReferences: [],
                            sql: 'order_date_fiscal_quarter',
                            hidden: false,
                            fieldType: field_1.FieldType.DIMENSION,
                            type: field_1.DimensionType.STRING,
                            timeIntervalBaseDimensionName: 'order_date',
                            customTimeInterval: 'fiscal_quarter',
                        },
                    },
                },
            },
        };
        const filtersWithOnlyStringDerivedDimension = {
            dimensions: {
                id: 'mockGroupId',
                and: [
                    {
                        id: 'string-derived-filter',
                        target: { fieldId: 'orders_order_date_fiscal_quarter' },
                        operator: filter_1.FilterOperator.EQUALS,
                        values: ['FY2024-Q1'],
                    },
                ],
            },
        };
        const result = (0, filters_1.reduceRequiredDimensionFiltersToFilterRules)([(0, filters_mock_1.modelRequiredFilterRule)('order_date')], filtersWithOnlyStringDerivedDimension.dimensions, exploreWithStringDerivedTimeDimension);
        expect(result).toEqual([
            (0, filters_mock_1.expectedRequiredResult)('order_date', 'orders'),
        ]);
    });
    test('should keep required derived time filters when only a sibling derived time filter is present', () => {
        const exploreWithSiblingStringDerivedTimeDimensions = {
            ...filters_mock_1.mockExplore,
            tables: {
                ...filters_mock_1.mockExplore.tables,
                orders: {
                    ...filters_mock_1.mockExplore.tables.orders,
                    dimensions: {
                        ...filters_mock_1.mockExplore.tables.orders.dimensions,
                        order_date: {
                            name: 'order_date',
                            label: 'Order Date',
                            table: 'orders',
                            tableLabel: 'Orders',
                            compiledSql: 'order_date',
                            tablesReferences: [],
                            sql: 'order_date',
                            hidden: false,
                            fieldType: field_1.FieldType.DIMENSION,
                            type: field_1.DimensionType.DATE,
                            isIntervalBase: true,
                        },
                        order_date_fiscal_year: {
                            name: 'order_date_fiscal_year',
                            label: 'Order Date Fiscal Year',
                            table: 'orders',
                            tableLabel: 'Orders',
                            compiledSql: 'order_date_fiscal_year',
                            tablesReferences: [],
                            sql: 'order_date_fiscal_year',
                            hidden: false,
                            fieldType: field_1.FieldType.DIMENSION,
                            type: field_1.DimensionType.STRING,
                            timeIntervalBaseDimensionName: 'order_date',
                            customTimeInterval: 'fiscal_year',
                        },
                        order_date_fiscal_quarter: {
                            name: 'order_date_fiscal_quarter',
                            label: 'Order Date Fiscal Quarter',
                            table: 'orders',
                            tableLabel: 'Orders',
                            compiledSql: 'order_date_fiscal_quarter',
                            tablesReferences: [],
                            sql: 'order_date_fiscal_quarter',
                            hidden: false,
                            fieldType: field_1.FieldType.DIMENSION,
                            type: field_1.DimensionType.STRING,
                            timeIntervalBaseDimensionName: 'order_date',
                            customTimeInterval: 'fiscal_quarter',
                        },
                    },
                },
            },
        };
        const filtersWithSiblingDerivedDimensionOnly = {
            dimensions: {
                id: 'mockGroupId',
                and: [
                    {
                        id: 'sibling-derived-filter',
                        target: { fieldId: 'orders_order_date_fiscal_quarter' },
                        operator: filter_1.FilterOperator.EQUALS,
                        values: ['FY2024-Q1'],
                    },
                ],
            },
        };
        const result = (0, filters_1.reduceRequiredDimensionFiltersToFilterRules)([(0, filters_mock_1.modelRequiredFilterRule)('order_date_fiscal_year')], filtersWithSiblingDerivedDimensionOnly.dimensions, exploreWithSiblingStringDerivedTimeDimensions);
        expect(result).toEqual([
            (0, filters_mock_1.expectedRequiredResult)('order_date_fiscal_year', 'orders'),
        ]);
    });
    test('should not add a required standard derived time filter when a sibling standard time filter is present', () => {
        const exploreWithStandardDerivedTimeDimensions = {
            ...filters_mock_1.mockExplore,
            tables: {
                ...filters_mock_1.mockExplore.tables,
                orders: {
                    ...filters_mock_1.mockExplore.tables.orders,
                    dimensions: {
                        ...filters_mock_1.mockExplore.tables.orders.dimensions,
                        order_date_week: {
                            ...filters_mock_1.mockExplore.tables.orders.dimensions
                                .order_date_week,
                            timeInterval: timeFrames_1.TimeFrames.WEEK,
                        },
                        order_date_month: {
                            ...filters_mock_1.mockExplore.tables.orders.dimensions
                                .order_date_month,
                            timeInterval: timeFrames_1.TimeFrames.MONTH,
                        },
                    },
                },
            },
        };
        const filtersWithSiblingStandardDimension = {
            dimensions: {
                id: 'mockGroupId',
                and: [
                    {
                        id: 'sibling-standard-filter',
                        target: { fieldId: 'orders_order_date_month' },
                        operator: filter_1.FilterOperator.EQUALS,
                        values: ['2024-09-01'],
                    },
                ],
            },
        };
        const result = (0, filters_1.reduceRequiredDimensionFiltersToFilterRules)([(0, filters_mock_1.modelRequiredFilterRule)('order_date_week')], filtersWithSiblingStandardDimension.dimensions, exploreWithStandardDerivedTimeDimensions);
        expect(result).toEqual([]);
    });
});
describe('resetRequiredFilterRules', () => {
    test('should correctly reset required filter rules', () => {
        const filterGroup = {
            id: 'uuidGroup',
            and: [
                (0, filters_mock_1.expectedRequiredResult)('mockFieldRef1', 'table'),
                (0, filters_mock_1.expectedRequiredResult)('mockFieldRef2', 'table'),
            ],
        };
        const newFilterRules = (0, filters_1.resetRequiredFilterRules)(filterGroup, [
            'table_mockFieldRef1',
            'someOther',
        ]);
        expect(newFilterRules).toEqual(filters_mock_1.expectedRequiredResetResult);
    });
});
describe('trackWhichTimeBasedMetricFiltersToOverride', () => {
    test('should track fields to change when dashboard filter targets base time dimension', () => {
        const metricQueryDimensionFilters = {
            id: 'dim-filter-group',
            and: [
                {
                    id: 'month-filter',
                    target: { fieldId: 'order_date_month' },
                    operator: filter_1.FilterOperator.EQUALS,
                    values: ['2024-03'],
                },
                {
                    id: 'week-filter',
                    target: { fieldId: 'order_date_week' },
                    operator: filter_1.FilterOperator.EQUALS,
                    values: ['2024-03-25'],
                },
            ],
        };
        const dashboardFilter = {
            id: 'year-filter',
            label: 'Year Filter',
            target: {
                fieldId: 'order_date_year',
                tableName: 'orders',
            },
            operator: filter_1.FilterOperator.EQUALS,
            values: ['2024'],
        };
        const result = (0, filters_1.trackWhichTimeBasedMetricFiltersToOverride)(metricQueryDimensionFilters, dashboardFilter, filters_mock_1.mockExplore);
        expect(result.overrideData?.fieldsToChange).toEqual(expect.arrayContaining(['order_date_month', 'order_date_week']));
    });
    test('should not track fields when dashboard filter targets non-base dimension', () => {
        const metricQueryDimensionFilters = {
            id: 'dim-filter-group',
            and: [
                {
                    id: 'status-filter',
                    target: { fieldId: 'status' },
                    operator: filter_1.FilterOperator.EQUALS,
                    values: ['completed'],
                },
            ],
        };
        const dashboardFilter = {
            id: 'status-filter',
            label: 'Status Filter',
            target: {
                fieldId: 'status',
                tableName: 'orders',
            },
            operator: filter_1.FilterOperator.EQUALS,
            values: ['shipped'],
        };
        const result = (0, filters_1.trackWhichTimeBasedMetricFiltersToOverride)(metricQueryDimensionFilters, dashboardFilter, filters_mock_1.mockExplore);
        expect(result.overrideData?.fieldsToChange).toBeUndefined();
    });
    test('should handle multiple time intervals in metric query', () => {
        const metricQueryDimensionFilters = {
            id: 'dim-filter-group',
            or: [
                {
                    id: 'month-filter',
                    target: { fieldId: 'order_date_month' },
                    operator: filter_1.FilterOperator.EQUALS,
                    values: ['2024-03'],
                },
                {
                    id: 'week-filter',
                    target: { fieldId: 'order_date_week' },
                    operator: filter_1.FilterOperator.EQUALS,
                    values: ['2024-03-25'],
                },
                {
                    id: 'year-filter',
                    target: { fieldId: 'order_date_year' },
                    operator: filter_1.FilterOperator.EQUALS,
                    values: ['2024'],
                },
            ],
        };
        const dashboardFilter = {
            id: 'base-filter',
            label: 'Base Filter',
            target: {
                fieldId: 'order_date_year',
                tableName: 'orders',
            },
            operator: filter_1.FilterOperator.EQUALS,
            values: ['2024'],
        };
        const result = (0, filters_1.trackWhichTimeBasedMetricFiltersToOverride)(metricQueryDimensionFilters, dashboardFilter, filters_mock_1.mockExplore);
        expect(result.overrideData?.fieldsToChange).toEqual(expect.arrayContaining([
            'order_date_month',
            'order_date_week',
            'order_date_year',
        ]));
    });
    test('should return original filter when no matching time intervals', () => {
        const metricQueryDimensionFilters = {
            id: 'dim-filter-group',
            and: [
                {
                    id: 'status-filter',
                    target: { fieldId: 'status' },
                    operator: filter_1.FilterOperator.EQUALS,
                    values: ['completed'],
                },
            ],
        };
        const dashboardFilter = {
            id: 'year-filter',
            label: 'Year Filter',
            target: {
                fieldId: 'order_date_year',
                tableName: 'orders',
            },
            operator: filter_1.FilterOperator.EQUALS,
            values: ['2024'],
        };
        const result = (0, filters_1.trackWhichTimeBasedMetricFiltersToOverride)(metricQueryDimensionFilters, dashboardFilter, filters_mock_1.mockExplore);
        expect(result.overrideData?.fieldsToChange).toBeUndefined();
    });
});
describe('getDashboardFilterRulesForTileAndReferences', () => {
    test('should return filter rules when there is a match (isSqlColumn is true and fieldId is in references)', () => {
        const mockTileUuid = 'tile-123';
        const mockReferences = ['field-1', 'field-2'];
        const mockDashboardFilterRules = [
            {
                id: 'filter-1',
                label: 'Filter 1',
                target: {
                    fieldId: 'field-1',
                    tableName: 'table-1',
                    isSqlColumn: true,
                },
                operator: filter_1.FilterOperator.EQUALS,
                values: ['value-1'],
                tileTargets: {
                    [mockTileUuid]: {
                        fieldId: 'field-1',
                        tableName: 'table-1',
                        isSqlColumn: true,
                    },
                },
            },
        ];
        const result = (0, filters_1.getDashboardFilterRulesForTileAndReferences)(mockTileUuid, mockReferences, mockDashboardFilterRules);
        expect(result).toHaveLength(1);
        expect(result[0].id).toBe('filter-1');
        expect(result[0].target.fieldId).toBe('field-1');
        expect(result[0].target.isSqlColumn).toBe(true);
    });
    test('should not return filter rules when isSqlColumn is false even though fieldId is a match', () => {
        const mockTileUuid = 'tile-123';
        const mockReferences = ['field-1', 'field-2'];
        const mockDashboardFilterRules = [
            {
                id: 'filter-2',
                label: 'Filter 2',
                target: {
                    fieldId: 'field-2',
                    tableName: 'table-1',
                    isSqlColumn: false,
                },
                operator: filter_1.FilterOperator.EQUALS,
                values: ['value-2'],
                tileTargets: {
                    [mockTileUuid]: {
                        fieldId: 'field-2',
                        tableName: 'table-1',
                        isSqlColumn: false,
                    },
                },
            },
        ];
        const result = (0, filters_1.getDashboardFilterRulesForTileAndReferences)(mockTileUuid, mockReferences, mockDashboardFilterRules);
        // Verify filter-2 is not included (isSqlColumn is false but fieldId is a match)
        expect(result).toHaveLength(0);
    });
    test('should not return filter rules when isSqlColumn is true but fieldId does not match', () => {
        const mockTileUuid = 'tile-123';
        const mockReferences = ['field-1', 'field-2'];
        const mockDashboardFilterRules = [
            {
                id: 'filter-3',
                label: 'Filter 3',
                target: {
                    fieldId: 'field-3',
                    tableName: 'table-1',
                    isSqlColumn: true,
                },
                operator: filter_1.FilterOperator.EQUALS,
                values: ['value-3'],
                tileTargets: {
                    [mockTileUuid]: {
                        fieldId: 'field-3',
                        tableName: 'table-1',
                        isSqlColumn: true,
                    },
                },
            },
        ];
        const result = (0, filters_1.getDashboardFilterRulesForTileAndReferences)(mockTileUuid, mockReferences, mockDashboardFilterRules);
        // Verify filter-3 is not included (isSqlColumn is true but fieldId doesn't match)
        expect(result).toHaveLength(0);
    });
});
describe('applyDashboardFiltersForTile', () => {
    const baseMetricQuery = {
        exploreName: 'test',
        dimensions: [],
        metrics: [],
        filters: {},
        sorts: [],
        limit: 500,
        tableCalculations: [],
    };
    const statusRule = {
        id: 'f-status',
        target: { fieldId: 'orders_status', tableName: 'orders' },
        operator: filter_1.FilterOperator.EQUALS,
        values: [true],
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
    };
    const offExploreRule = {
        id: 'f-off',
        target: { fieldId: 'other_browser', tableName: 'other' },
        operator: filter_1.FilterOperator.EQUALS,
        values: ['chrome'],
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
    };
    test('drops rules whose fieldId is not in the explore', () => {
        const { metricQuery, appliedDashboardFilters } = (0, filters_1.applyDashboardFiltersForTile)({
            tileUuid: 't-1',
            metricQuery: baseMetricQuery,
            dashboardFilters: {
                dimensions: [offExploreRule],
                metrics: [],
                tableCalculations: [],
            },
            explore: filters_mock_1.mockExplore,
        });
        expect(appliedDashboardFilters.dimensions).toEqual([]);
        expect(metricQuery.filters.dimensions
            ?.and ?? []).toEqual([]);
    });
    test('drops rules whose tileTargets disable them for this tile', () => {
        const disabledRule = {
            ...statusRule,
            tileTargets: { 't-1': false },
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
        };
        const { metricQuery, appliedDashboardFilters } = (0, filters_1.applyDashboardFiltersForTile)({
            tileUuid: 't-1',
            metricQuery: baseMetricQuery,
            dashboardFilters: {
                dimensions: [disabledRule],
                metrics: [],
                tableCalculations: [],
            },
            explore: filters_mock_1.mockExplore,
        });
        expect(appliedDashboardFilters.dimensions).toEqual([]);
        expect(metricQuery.filters.dimensions
            ?.and ?? []).toEqual([]);
    });
    test('merges applicable rules into the metric query', () => {
        const { metricQuery, appliedDashboardFilters } = (0, filters_1.applyDashboardFiltersForTile)({
            tileUuid: 't-1',
            metricQuery: baseMetricQuery,
            dashboardFilters: {
                dimensions: [statusRule, offExploreRule],
                metrics: [],
                tableCalculations: [],
            },
            explore: filters_mock_1.mockExplore,
        });
        expect(appliedDashboardFilters.dimensions).toHaveLength(1);
        expect(appliedDashboardFilters.dimensions[0].id).toBe('f-status');
        const merged = metricQuery.filters.dimensions.and;
        expect(merged).toHaveLength(1);
        expect(merged[0]).toMatchObject({
            target: { fieldId: 'orders_status' },
            values: [true],
        });
    });
});
describe('stripOverridesForLockedFiltersOnTab', () => {
    const TAB_A = 'tab-a';
    const TAB_B = 'tab-b';
    const makeRule = (id, fieldId, tableName, opts = {}) => ({
        id,
        operator: filter_1.FilterOperator.EQUALS,
        target: { fieldId, tableName },
        values: opts.values ?? ['x'],
        label: undefined,
        ...(opts.lockedTabUuids ? { lockedTabUuids: opts.lockedTabUuids } : {}),
    });
    test('drops override on a tab where the rule is locked', () => {
        const saved = {
            dimensions: [
                makeRule('s-1', 'orders_status', 'orders', {
                    lockedTabUuids: [TAB_A],
                }),
            ],
            metrics: [],
            tableCalculations: [],
        };
        const overrides = {
            dimensions: [
                makeRule('o-1', 'orders_status', 'orders', {
                    values: ['returned'],
                }),
            ],
            metrics: [],
            tableCalculations: [],
        };
        const result = (0, filters_1.stripOverridesForLockedFiltersOnTab)(saved, overrides, TAB_A, true);
        expect(result.filters.dimensions).toEqual([]);
        expect(result.droppedCount).toBe(1);
    });
    test('keeps override on a tab where the rule is NOT locked', () => {
        const saved = {
            dimensions: [
                makeRule('s-1', 'orders_status', 'orders', {
                    lockedTabUuids: [TAB_A],
                }),
            ],
            metrics: [],
            tableCalculations: [],
        };
        const overrides = {
            dimensions: [makeRule('o-1', 'orders_status', 'orders')],
            metrics: [],
            tableCalculations: [],
        };
        const result = (0, filters_1.stripOverridesForLockedFiltersOnTab)(saved, overrides, TAB_B, true);
        expect(result.filters.dimensions).toHaveLength(1);
        expect(result.droppedCount).toBe(0);
    });
    test('keeps override on a different field even if a sibling field is locked', () => {
        const saved = {
            dimensions: [
                makeRule('s-1', 'orders_status', 'orders', {
                    lockedTabUuids: [TAB_A],
                }),
            ],
            metrics: [],
            tableCalculations: [],
        };
        const overrides = {
            dimensions: [makeRule('o-1', 'orders_amount', 'orders')],
            metrics: [],
            tableCalculations: [],
        };
        const result = (0, filters_1.stripOverridesForLockedFiltersOnTab)(saved, overrides, TAB_A, true);
        expect(result.filters.dimensions).toHaveLength(1);
        expect(result.droppedCount).toBe(0);
    });
    test('does not cross filter groups (dim lock leaves metric overrides alone)', () => {
        const saved = {
            dimensions: [
                makeRule('s-1', 'orders_status', 'orders', {
                    lockedTabUuids: [TAB_A],
                }),
            ],
            metrics: [],
            tableCalculations: [],
        };
        const overrides = {
            dimensions: [],
            metrics: [makeRule('o-1', 'orders_status', 'orders')],
            tableCalculations: [],
        };
        const result = (0, filters_1.stripOverridesForLockedFiltersOnTab)(saved, overrides, TAB_A, true);
        expect(result.filters.metrics).toHaveLength(1);
        expect(result.droppedCount).toBe(0);
    });
    test('matches on both fieldId and tableName', () => {
        const saved = {
            dimensions: [
                makeRule('s-1', 'status', 'orders', {
                    lockedTabUuids: [TAB_A],
                }),
            ],
            metrics: [],
            tableCalculations: [],
        };
        const overrides = {
            dimensions: [makeRule('o-1', 'status', 'customers')],
            metrics: [],
            tableCalculations: [],
        };
        const result = (0, filters_1.stripOverridesForLockedFiltersOnTab)(saved, overrides, TAB_A, true);
        expect(result.filters.dimensions).toHaveLength(1);
        expect(result.droppedCount).toBe(0);
    });
    test('tabbed dashboard with undefined tabUuid strips nothing (transient pre-selection state)', () => {
        const saved = {
            dimensions: [
                makeRule('s-1', 'orders_status', 'orders', {
                    lockedTabUuids: [TAB_A],
                }),
            ],
            metrics: [],
            tableCalculations: [],
        };
        const overrides = {
            dimensions: [makeRule('o-1', 'orders_status', 'orders')],
            metrics: [],
            tableCalculations: [],
        };
        const result = (0, filters_1.stripOverridesForLockedFiltersOnTab)(saved, overrides, undefined, true);
        expect(result.filters.dimensions).toHaveLength(1);
        expect(result.droppedCount).toBe(0);
    });
    test('rule locked on multiple tabs is enforced on each', () => {
        const saved = {
            dimensions: [
                makeRule('s-1', 'orders_status', 'orders', {
                    lockedTabUuids: [TAB_A, TAB_B],
                }),
            ],
            metrics: [],
            tableCalculations: [],
        };
        const overrides = {
            dimensions: [makeRule('o-1', 'orders_status', 'orders')],
            metrics: [],
            tableCalculations: [],
        };
        const a = (0, filters_1.stripOverridesForLockedFiltersOnTab)(saved, overrides, TAB_A, true);
        const b = (0, filters_1.stripOverridesForLockedFiltersOnTab)(saved, overrides, TAB_B, true);
        expect(a.droppedCount).toBe(1);
        expect(b.droppedCount).toBe(1);
    });
    test('empty lockedTabUuids never strips', () => {
        const saved = {
            dimensions: [
                makeRule('s-1', 'orders_status', 'orders', {
                    lockedTabUuids: [],
                }),
            ],
            metrics: [],
            tableCalculations: [],
        };
        const overrides = {
            dimensions: [makeRule('o-1', 'orders_status', 'orders')],
            metrics: [],
            tableCalculations: [],
        };
        const result = (0, filters_1.stripOverridesForLockedFiltersOnTab)(saved, overrides, TAB_A, true);
        expect(result.filters.dimensions).toHaveLength(1);
        expect(result.droppedCount).toBe(0);
    });
    test('tab-less dashboard: any non-empty lockedTabUuids strips overrides', () => {
        const saved = {
            dimensions: [
                makeRule('s-1', 'orders_status', 'orders', {
                    lockedTabUuids: ['dashboard-uuid-as-sentinel'],
                }),
            ],
            metrics: [],
            tableCalculations: [],
        };
        const overrides = {
            dimensions: [
                makeRule('o-1', 'orders_status', 'orders', {
                    values: ['returned'],
                }),
            ],
            metrics: [],
            tableCalculations: [],
        };
        const result = (0, filters_1.stripOverridesForLockedFiltersOnTab)(saved, overrides, undefined, false);
        expect(result.filters.dimensions).toEqual([]);
        expect(result.droppedCount).toBe(1);
    });
    test('tab-less dashboard: empty lockedTabUuids still does not strip', () => {
        const saved = {
            dimensions: [
                makeRule('s-1', 'orders_status', 'orders', {
                    lockedTabUuids: [],
                }),
            ],
            metrics: [],
            tableCalculations: [],
        };
        const overrides = {
            dimensions: [makeRule('o-1', 'orders_status', 'orders')],
            metrics: [],
            tableCalculations: [],
        };
        const result = (0, filters_1.stripOverridesForLockedFiltersOnTab)(saved, overrides, undefined, false);
        expect(result.filters.dimensions).toHaveLength(1);
        expect(result.droppedCount).toBe(0);
    });
    test('tab-less dashboard: non-target field is not affected by lock', () => {
        const saved = {
            dimensions: [
                makeRule('s-1', 'orders_status', 'orders', {
                    lockedTabUuids: ['dashboard-uuid-as-sentinel'],
                }),
            ],
            metrics: [],
            tableCalculations: [],
        };
        const overrides = {
            dimensions: [makeRule('o-1', 'orders_amount', 'orders')],
            metrics: [],
            tableCalculations: [],
        };
        const result = (0, filters_1.stripOverridesForLockedFiltersOnTab)(saved, overrides, undefined, false);
        expect(result.filters.dimensions).toHaveLength(1);
        expect(result.droppedCount).toBe(0);
    });
});
describe('isMalformedEmptyDashboardFilter', () => {
    test('flags disabled:false + empty values + value-requiring operator', () => {
        expect((0, filters_1.isMalformedEmptyDashboardFilter)({
            operator: filter_1.FilterOperator.EQUALS,
            disabled: false,
            values: [],
        })).toBe(true);
    });
    test('flags missing values (treated as empty)', () => {
        expect((0, filters_1.isMalformedEmptyDashboardFilter)({
            operator: filter_1.FilterOperator.EQUALS,
            disabled: false,
        })).toBe(true);
    });
    test('flags omitted disabled (defaults to active)', () => {
        expect((0, filters_1.isMalformedEmptyDashboardFilter)({
            operator: filter_1.FilterOperator.EQUALS,
            values: [],
        })).toBe(true);
    });
    test('treats null values (YAML `values: ~`) as empty', () => {
        expect((0, filters_1.isMalformedEmptyDashboardFilter)({
            operator: filter_1.FilterOperator.EQUALS,
            disabled: false,
            values: null,
        })).toBe(true);
    });
    test('does NOT flag disabled filters', () => {
        expect((0, filters_1.isMalformedEmptyDashboardFilter)({
            operator: filter_1.FilterOperator.EQUALS,
            disabled: true,
            values: [],
        })).toBe(false);
    });
    test('does NOT flag operators that legitimately take no values', () => {
        expect((0, filters_1.isMalformedEmptyDashboardFilter)({
            operator: filter_1.FilterOperator.NULL,
            disabled: false,
            values: [],
        })).toBe(false);
        expect((0, filters_1.isMalformedEmptyDashboardFilter)({
            operator: filter_1.FilterOperator.NOT_NULL,
            disabled: false,
        })).toBe(false);
        expect((0, filters_1.isMalformedEmptyDashboardFilter)({
            operator: filter_1.FilterOperator.IN_PERIOD_TO_DATE,
            disabled: false,
        })).toBe(false);
    });
    test('does NOT flag filters with values', () => {
        expect((0, filters_1.isMalformedEmptyDashboardFilter)({
            operator: filter_1.FilterOperator.EQUALS,
            disabled: false,
            values: ['some-value'],
        })).toBe(false);
    });
});
//# sourceMappingURL=filters.test.js.map