"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const exploreCompiler_mock_1 = require("../../compiler/exploreCompiler.mock");
const errors_1 = require("../../types/errors");
const field_1 = require("../../types/field");
const projects_1 = require("../../types/projects");
const DbtSchemaEditor_1 = tslib_1.__importDefault(require("./DbtSchemaEditor"));
const DbtSchemaEditor_mock_1 = require("./DbtSchemaEditor.mock");
describe('DbtSchemaEditor', () => {
    it('should load the yaml schema and convert to JS and YML', () => {
        const editor = new DbtSchemaEditor_1.default(DbtSchemaEditor_mock_1.SCHEMA_YML);
        // can convert to JS
        expect(editor.toJS()).toEqual(DbtSchemaEditor_mock_1.SCHEMA_JSON);
        // can convert back to string
        expect(editor.toString()).toEqual(DbtSchemaEditor_mock_1.SCHEMA_YML);
    });
    it('should throw error with invalid yaml schema', () => {
        expect(() => new DbtSchemaEditor_1.default(DbtSchemaEditor_mock_1.INVALID_SCHEMA_YML)).toThrowError(errors_1.ParseError);
    });
    it('should update a model with custom metrics and custom dimensions', () => {
        const editor = new DbtSchemaEditor_1.default(DbtSchemaEditor_mock_1.SCHEMA_YML);
        // confirms it has models
        expect(editor.hasModels()).toEqual(true);
        // adds custom metrics
        editor.addCustomMetrics([DbtSchemaEditor_mock_1.CUSTOM_METRIC]);
        editor.addCustomDimensions([
            DbtSchemaEditor_mock_1.CUSTOM_SQL_DIMENSION,
            DbtSchemaEditor_mock_1.FIXED_WIDTH_BIN_DIMENSION,
            DbtSchemaEditor_mock_1.CUSTOM_RANGE_BIN_DIMENSION,
        ], exploreCompiler_mock_1.warehouseClientMock);
        expect(editor.toString()).toEqual(DbtSchemaEditor_mock_1.EXPECTED_SCHEMA_YML_WITH_NEW_METRICS_AND_DIMENSIONS);
    });
    it('should create a new file', () => {
        const editor = new DbtSchemaEditor_1.default('');
        // confirm it has no models
        expect(editor.hasModels()).toEqual(false);
        // add a new model
        editor.addModel(DbtSchemaEditor_mock_1.NEW_MODEL);
        expect(editor.hasModels()).toEqual(true);
        expect(editor.toJS()).toEqual(DbtSchemaEditor_mock_1.EXPECTED_SCHEMA_JSON_WITH_NEW_MODEL);
        expect(editor.toString()).toEqual(DbtSchemaEditor_mock_1.EXPECTED_SCHEMA_YML_WITH_NEW_MODEL);
    });
    it('should preserve long single-line descriptions when mutating the schema', () => {
        const schema = `version: 2
models:
  - name: my_model
    columns:
      - name: id
        description: "This is a very long description that should remain on a single line after the schema editor serializes the document back to YAML."`;
        const editor = new DbtSchemaEditor_1.default(schema);
        editor.addColumn('my_model', {
            name: 'new_column',
            description: '',
        });
        expect(editor.toString()).toContain('description: "This is a very long description that should remain on a single line after the schema editor serializes the document back to YAML."');
    });
});
describe('AI hint schema validation', () => {
    it.each([
        {
            name: 'model',
            metadata: `    ai_hint:
      - Formula: clicks + keys`,
        },
        {
            name: 'field group',
            metadata: `    group_details:
      finance:
        label: Finance
        ai_hint:
          - Formula: clicks + keys`,
        },
        {
            name: 'model metric',
            metadata: `    metrics:
      revenue:
        type: sum
        sql: '\${TABLE}.revenue'
        ai_hint:
          - Formula: clicks + keys`,
        },
    ])('rejects malformed $name hints', ({ metadata }) => {
        const schema = `version: 2
models:
  - name: orders
    meta:
${metadata}`;
        expect(() => new DbtSchemaEditor_1.default(schema)).toThrowError(errors_1.ParseError);
    });
    it.each([
        {
            name: 'column metric',
            metadata: `        metrics:
          revenue:
            type: sum
            ai_hint:
              - Formula: clicks + keys`,
        },
        {
            name: 'dimension',
            metadata: `        dimension:
          ai_hint:
            - Formula: clicks + keys`,
        },
        {
            name: 'additional dimension',
            metadata: `        additional_dimensions:
          normalized_name:
            type: string
            sql: '\${TABLE}.name'
            ai_hint:
              - Formula: clicks + keys`,
        },
    ])('rejects malformed $name hints', ({ metadata }) => {
        const schema = `version: 2
models:
  - name: orders
    columns:
      - name: status
        meta:
${metadata}`;
        expect(() => new DbtSchemaEditor_1.default(schema)).toThrowError(errors_1.ParseError);
    });
});
describe('case-insensitive column matching', () => {
    const MIXED_CASE_SCHEMA = `version: 2
models:
  - name: my_model
    columns:
      - name: appclassid
        description: My existing description
        tests:
          - not_null
      - name: userid
        description: User ID column`;
    it('should find columns with case-insensitive name matching', () => {
        const editor = new DbtSchemaEditor_1.default(MIXED_CASE_SCHEMA);
        // Exact case
        expect(editor.findColumnByName('my_model', 'appclassid')).toBeDefined();
        // Different case
        expect(editor.findColumnByName('my_model', 'appClassId')).toBeDefined();
        expect(editor.findColumnByName('my_model', 'APPCLASSID')).toBeDefined();
        // Non-existent
        expect(editor.findColumnByName('my_model', 'nonexistent')).toBeUndefined();
    });
    it('should update columns found by case-insensitive matching', () => {
        const editor = new DbtSchemaEditor_1.default(MIXED_CASE_SCHEMA);
        // Update using different case than what's in YAML
        editor.updateColumn({
            modelName: 'my_model',
            columnName: 'AppClassId',
            properties: {
                description: 'Updated description',
            },
        });
        const columns = editor.getModelColumns('my_model');
        const col = columns?.find((c) => c.name.toLowerCase() === 'appclassid');
        expect(col?.description).toBe('Updated description');
        // Original name should be preserved in YAML
        expect(col?.name).toBe('appclassid');
    });
    it('should prevent adding duplicate columns with different case', () => {
        const editor = new DbtSchemaEditor_1.default(MIXED_CASE_SCHEMA);
        expect(() => editor.addColumn('my_model', {
            name: 'AppClassId',
            description: '',
        })).toThrow('already exists');
    });
    it('should remove columns with case-insensitive matching', () => {
        const editor = new DbtSchemaEditor_1.default(MIXED_CASE_SCHEMA);
        editor.removeColumns('my_model', ['AppClassId']);
        const columns = editor.getModelColumns('my_model');
        expect(columns?.length).toBe(1);
        expect(columns?.[0].name).toBe('userid');
    });
});
describe('dbt v1.10+ compatibility', () => {
    it('should add custom metrics under config.meta for dbt v1.10', () => {
        const editor = new DbtSchemaEditor_1.default(DbtSchemaEditor_mock_1.SIMPLE_SCHEMA, '', projects_1.SupportedDbtVersions.V1_10);
        editor.addCustomMetrics([
            {
                name: 'test_metric',
                description: 'Test metric',
                sql: 'COUNT(*)',
                type: field_1.MetricType.COUNT,
                table: 'test_table',
                baseDimensionName: 'test_column',
            },
        ]);
        const result = editor.toString().replace(/\s+/g, '');
        // Check that the structure is config->meta->metrics (no spaces)
        expect(result).toContain('config:meta:metrics:');
        // Ensure meta is not directly at column level
        expect(result).not.toContain('description:Atestcolumnmeta:');
    });
    it('should add custom metrics directly under meta for dbt v1.9', () => {
        const editor = new DbtSchemaEditor_1.default(DbtSchemaEditor_mock_1.SIMPLE_SCHEMA, '', projects_1.SupportedDbtVersions.V1_9);
        editor.addCustomMetrics([
            {
                name: 'test_metric',
                description: 'Test metric',
                sql: 'COUNT(*)',
                type: field_1.MetricType.COUNT,
                table: 'test_table',
                baseDimensionName: 'test_column',
            },
        ]);
        const result = editor.toString().replace(/\s+/g, '');
        // Check that meta is NOT inside config
        expect(result).not.toContain('config:meta:metrics:');
        // Check that meta is directly at column level
        expect(result).toContain('description:Atestcolumnmeta:metrics:');
    });
    it('should add custom dimensions under config.meta for dbt v1.10', () => {
        const editor = new DbtSchemaEditor_1.default(DbtSchemaEditor_mock_1.SIMPLE_SCHEMA, '', projects_1.SupportedDbtVersions.V1_10);
        editor.addCustomDimensions([
            {
                id: 'custom_dim',
                name: 'Custom Dimension',
                table: 'test_table',
                type: field_1.CustomDimensionType.SQL,
                sql: '${test_table.test_column} || "_suffix"',
                dimensionType: field_1.DimensionType.STRING,
            },
        ], exploreCompiler_mock_1.warehouseClientMock);
        const result = editor.toString().replace(/\s+/g, '');
        // Check that the structure is config->meta->additional_dimensions (no spaces)
        expect(result).toContain('config:meta:additional_dimensions:');
        // Ensure meta is not directly at column level
        expect(result).not.toContain('description:Atestcolumnmeta:');
    });
    it('should add custom dimensions directly under meta for dbt v1.9', () => {
        const editor = new DbtSchemaEditor_1.default(DbtSchemaEditor_mock_1.SIMPLE_SCHEMA, '', projects_1.SupportedDbtVersions.V1_9);
        editor.addCustomDimensions([
            {
                id: 'custom_dim',
                name: 'Custom Dimension',
                table: 'test_table',
                type: field_1.CustomDimensionType.SQL,
                sql: '${test_table.test_column} || "_suffix"',
                dimensionType: field_1.DimensionType.STRING,
            },
        ], exploreCompiler_mock_1.warehouseClientMock);
        const result = editor.toString().replace(/\s+/g, '');
        // Check that meta is NOT inside config
        expect(result).not.toContain('config:meta:additional_dimensions:');
        // Check that meta is directly at column level
        expect(result).toContain('description:Atestcolumnmeta:additional_dimensions:');
    });
    it('should handle dbt versions correctly in isDbtVersion110OrHigher', () => {
        // Test v1.9 and below
        const editorV19 = new DbtSchemaEditor_1.default('version: 2', '', projects_1.SupportedDbtVersions.V1_9);
        expect(editorV19.isDbtVersion110OrHigher()).toBe(false);
        const editorV18 = new DbtSchemaEditor_1.default('version: 2', '', projects_1.SupportedDbtVersions.V1_8);
        expect(editorV18.isDbtVersion110OrHigher()).toBe(false);
        // Test v1.10
        const editorV110 = new DbtSchemaEditor_1.default('version: 2', '', projects_1.SupportedDbtVersions.V1_10);
        expect(editorV110.isDbtVersion110OrHigher()).toBe(true);
        // Test undefined version (defaults to false)
        const editorNoVersion = new DbtSchemaEditor_1.default('version: 2', '');
        expect(editorNoVersion.isDbtVersion110OrHigher()).toBe(false);
    });
});
//# sourceMappingURL=DbtSchemaEditor.test.js.map