"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const parameters_1 = require("../../compiler/parameters");
const field_1 = require("../../types/field");
const item_1 = require("../../utils/item");
const dimensionEligibility_1 = require("./dimensionEligibility");
const makeDimension = (overrides) => ({
    ...overrides,
    fieldType: field_1.FieldType.DIMENSION,
    type: field_1.DimensionType.STRING,
    name: overrides.name,
    label: overrides.label ?? overrides.name,
    table: overrides.table ?? 'orders',
    tableLabel: overrides.tableLabel ?? 'Orders',
    sql: overrides.sql ?? '${TABLE}.id',
    compiledSql: overrides.compiledSql ?? overrides.sql ?? '"orders".id',
    parameterReferences: overrides.parameterReferences ??
        (0, parameters_1.getParameterReferencesFromSqlAndFormat)(overrides.sql ?? '${TABLE}.id'),
    tablesReferences: overrides.tablesReferences ?? ['orders'],
    hidden: overrides.hidden ?? false,
});
const makeTables = (dimensions) => dimensions.reduce((acc, dimension) => {
    acc[dimension.table] = acc[dimension.table] ?? {
        name: dimension.table,
        originalName: dimension.table === 'cstmr' ? 'customers' : undefined,
        dimensions: {},
        metrics: {},
    };
    acc[dimension.table].dimensions[dimension.name] = dimension;
    return acc;
}, {});
describe('analyzePreAggregateDerivedDimensionEligibility', () => {
    it('classifies a plain base dimension as eligible', () => {
        const orderId = makeDimension({
            name: 'order_id',
            sql: '${TABLE}.id',
            compiledSql: '"orders".id',
        });
        expect((0, dimensionEligibility_1.analyzePreAggregateDerivedDimensionEligibility)({
            dimension: orderId,
            tables: makeTables([orderId]),
        })).toEqual({
            isEligible: true,
            referencedDimensionFieldIds: [(0, item_1.getItemId)(orderId)],
        });
    });
    it('classifies a derived dimension without runtime context as eligible', () => {
        const status = makeDimension({
            name: 'status',
            sql: '${TABLE}.status',
            compiledSql: '"orders".status',
        });
        const normalizedStatus = makeDimension({
            name: 'normalized_status',
            sql: 'upper(${status})',
        });
        const statusLabel = makeDimension({
            name: 'status_label',
            sql: "concat(${normalized_status}, '-ok')",
        });
        expect((0, dimensionEligibility_1.analyzePreAggregateDerivedDimensionEligibility)({
            dimension: statusLabel,
            tables: makeTables([status, normalizedStatus, statusLabel]),
        })).toEqual({
            isEligible: true,
            referencedDimensionFieldIds: [
                (0, item_1.getItemId)(statusLabel),
                (0, item_1.getItemId)(normalizedStatus),
                (0, item_1.getItemId)(status),
            ],
        });
    });
    it('resolves references through a joined table original name', () => {
        const customerFirstName = makeDimension({
            name: 'first_name',
            table: 'cstmr',
            sql: '${TABLE}.first_name',
            compiledSql: '"customers".first_name',
        });
        const customerGreeting = makeDimension({
            name: 'customer_greeting',
            sql: "concat(${customers.first_name}, ' hi')",
        });
        expect((0, dimensionEligibility_1.analyzePreAggregateDerivedDimensionEligibility)({
            dimension: customerGreeting,
            tables: makeTables([customerFirstName, customerGreeting]),
        })).toEqual({
            isEligible: true,
            referencedDimensionFieldIds: [
                (0, item_1.getItemId)(customerGreeting),
                (0, item_1.getItemId)(customerFirstName),
            ],
        });
    });
    it('rejects when a dimension sql references a parameter directly', () => {
        const status = makeDimension({
            name: 'status',
            sql: `
                CASE
                    WHEN \${lightdash.parameters.orders.region} = 'EMEA' THEN \${TABLE}.status
                    ELSE NULL
                END
            `,
        });
        expect((0, dimensionEligibility_1.analyzePreAggregateDerivedDimensionEligibility)({
            dimension: status,
            tables: makeTables([status]),
        })).toEqual({
            isEligible: false,
            reason: dimensionEligibility_1.PreAggregateDerivedDimensionIneligibilityReason.PARAMETER_REFERENCES,
            ineligibleDimensionFieldId: (0, item_1.getItemId)(status),
            referencedDimensionFieldIds: [(0, item_1.getItemId)(status)],
        });
    });
    it('rejects when a recursive dependency has parameter references', () => {
        const status = makeDimension({
            name: 'status',
            sql: `
                CASE
                    WHEN \${lightdash.parameters.orders.region} = 'EMEA' THEN \${TABLE}.status
                    ELSE NULL
                END
            `,
        });
        const filteredStatus = makeDimension({
            name: 'filtered_status',
            sql: '${status}',
        });
        expect((0, dimensionEligibility_1.analyzePreAggregateDerivedDimensionEligibility)({
            dimension: filteredStatus,
            tables: makeTables([status, filteredStatus]),
        })).toEqual({
            isEligible: false,
            reason: dimensionEligibility_1.PreAggregateDerivedDimensionIneligibilityReason.PARAMETER_REFERENCES,
            ineligibleDimensionFieldId: (0, item_1.getItemId)(status),
            referencedDimensionFieldIds: [
                (0, item_1.getItemId)(filteredStatus),
                (0, item_1.getItemId)(status),
            ],
        });
    });
    it('rejects when the dimension sql contains a direct user attribute reference', () => {
        const regionAwareStatus = makeDimension({
            name: 'region_aware_status',
            sql: "case when ${ld.attr.region} = 'EMEA' then ${TABLE}.status end",
        });
        expect((0, dimensionEligibility_1.analyzePreAggregateDerivedDimensionEligibility)({
            dimension: regionAwareStatus,
            tables: makeTables([regionAwareStatus]),
        })).toEqual({
            isEligible: false,
            reason: dimensionEligibility_1.PreAggregateDerivedDimensionIneligibilityReason.USER_ATTRIBUTES,
            ineligibleDimensionFieldId: (0, item_1.getItemId)(regionAwareStatus),
            referencedDimensionFieldIds: [(0, item_1.getItemId)(regionAwareStatus)],
        });
    });
    it('rejects when the dimension sql contains a direct intrinsic user reference', () => {
        const emailAwareStatus = makeDimension({
            name: 'email_aware_status',
            sql: "case when ${lightdash.user.email} = 'demo@lightdash.com' then ${TABLE}.status end",
        });
        expect((0, dimensionEligibility_1.analyzePreAggregateDerivedDimensionEligibility)({
            dimension: emailAwareStatus,
            tables: makeTables([emailAwareStatus]),
        })).toEqual({
            isEligible: false,
            reason: dimensionEligibility_1.PreAggregateDerivedDimensionIneligibilityReason.USER_ATTRIBUTES,
            ineligibleDimensionFieldId: (0, item_1.getItemId)(emailAwareStatus),
            referencedDimensionFieldIds: [(0, item_1.getItemId)(emailAwareStatus)],
        });
    });
    it('rejects when a nested dependency has a compilation error', () => {
        const status = makeDimension({
            name: 'status',
            sql: '${TABLE}.status',
            compilationError: {
                message: 'Cannot compile',
            },
        });
        const prettyStatus = makeDimension({
            name: 'pretty_status',
            sql: "concat(${orders.status}, '!')",
        });
        const statusWrapper = makeDimension({
            name: 'status_wrapper',
            sql: '${pretty_status}',
        });
        expect((0, dimensionEligibility_1.analyzePreAggregateDerivedDimensionEligibility)({
            dimension: statusWrapper,
            tables: makeTables([status, prettyStatus, statusWrapper]),
        })).toEqual({
            isEligible: false,
            reason: dimensionEligibility_1.PreAggregateDerivedDimensionIneligibilityReason.COMPILATION_ERROR,
            ineligibleDimensionFieldId: (0, item_1.getItemId)(status),
            referencedDimensionFieldIds: [
                (0, item_1.getItemId)(statusWrapper),
                (0, item_1.getItemId)(prettyStatus),
                (0, item_1.getItemId)(status),
            ],
        });
    });
    it('rejects circular dependencies without recursing indefinitely', () => {
        const loop = makeDimension({
            name: 'loop',
            sql: '${loop}',
        });
        expect((0, dimensionEligibility_1.analyzePreAggregateDerivedDimensionEligibility)({
            dimension: loop,
            tables: makeTables([loop]),
        })).toEqual({
            isEligible: false,
            reason: dimensionEligibility_1.PreAggregateDerivedDimensionIneligibilityReason.CIRCULAR_DEPENDENCY,
            ineligibleDimensionFieldId: (0, item_1.getItemId)(loop),
            referencedDimensionFieldIds: [(0, item_1.getItemId)(loop)],
        });
    });
});
//# sourceMappingURL=dimensionEligibility.test.js.map