import { warehouseClientMock } from '../../compiler/exploreCompiler.mock';
import { ParseError } from '../../types/errors';
import { CustomDimensionType, DimensionType, MetricType, } from '../../types/field';
import { SupportedDbtVersions } from '../../types/projects';
import DbtSchemaEditor from './DbtSchemaEditor';
import { CUSTOM_METRIC, CUSTOM_RANGE_BIN_DIMENSION, CUSTOM_SQL_DIMENSION, EXPECTED_SCHEMA_JSON_WITH_NEW_MODEL, EXPECTED_SCHEMA_YML_WITH_NEW_METRICS_AND_DIMENSIONS, EXPECTED_SCHEMA_YML_WITH_NEW_MODEL, FIXED_WIDTH_BIN_DIMENSION, INVALID_SCHEMA_YML, NEW_MODEL, SCHEMA_JSON, SCHEMA_YML, SIMPLE_SCHEMA, } from './DbtSchemaEditor.mock';
describe('DbtSchemaEditor', () => {
    it('should load the yaml schema and convert to JS and YML', () => {
        const editor = new DbtSchemaEditor(SCHEMA_YML);
        // can convert to JS
        expect(editor.toJS()).toEqual(SCHEMA_JSON);
        // can convert back to string
        expect(editor.toString()).toEqual(SCHEMA_YML);
    });
    it('should throw error with invalid yaml schema', () => {
        expect(() => new DbtSchemaEditor(INVALID_SCHEMA_YML)).toThrowError(ParseError);
    });
    it('should update a model with custom metrics and custom dimensions', () => {
        const editor = new DbtSchemaEditor(SCHEMA_YML);
        // confirms it has models
        expect(editor.hasModels()).toEqual(true);
        // adds custom metrics
        editor.addCustomMetrics([CUSTOM_METRIC]);
        editor.addCustomDimensions([
            CUSTOM_SQL_DIMENSION,
            FIXED_WIDTH_BIN_DIMENSION,
            CUSTOM_RANGE_BIN_DIMENSION,
        ], warehouseClientMock);
        expect(editor.toString()).toEqual(EXPECTED_SCHEMA_YML_WITH_NEW_METRICS_AND_DIMENSIONS);
    });
    it('should create a new file', () => {
        const editor = new DbtSchemaEditor('');
        // confirm it has no models
        expect(editor.hasModels()).toEqual(false);
        // add a new model
        editor.addModel(NEW_MODEL);
        expect(editor.hasModels()).toEqual(true);
        expect(editor.toJS()).toEqual(EXPECTED_SCHEMA_JSON_WITH_NEW_MODEL);
        expect(editor.toString()).toEqual(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(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('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(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(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(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(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(SIMPLE_SCHEMA, '', SupportedDbtVersions.V1_10);
        editor.addCustomMetrics([
            {
                name: 'test_metric',
                description: 'Test metric',
                sql: 'COUNT(*)',
                type: 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(SIMPLE_SCHEMA, '', SupportedDbtVersions.V1_9);
        editor.addCustomMetrics([
            {
                name: 'test_metric',
                description: 'Test metric',
                sql: 'COUNT(*)',
                type: 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(SIMPLE_SCHEMA, '', SupportedDbtVersions.V1_10);
        editor.addCustomDimensions([
            {
                id: 'custom_dim',
                name: 'Custom Dimension',
                table: 'test_table',
                type: CustomDimensionType.SQL,
                sql: '${test_table.test_column} || "_suffix"',
                dimensionType: DimensionType.STRING,
            },
        ], 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(SIMPLE_SCHEMA, '', SupportedDbtVersions.V1_9);
        editor.addCustomDimensions([
            {
                id: 'custom_dim',
                name: 'Custom Dimension',
                table: 'test_table',
                type: CustomDimensionType.SQL,
                sql: '${test_table.test_column} || "_suffix"',
                dimensionType: DimensionType.STRING,
            },
        ], 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('version: 2', '', SupportedDbtVersions.V1_9);
        expect(editorV19.isDbtVersion110OrHigher()).toBe(false);
        const editorV18 = new DbtSchemaEditor('version: 2', '', SupportedDbtVersions.V1_8);
        expect(editorV18.isDbtVersion110OrHigher()).toBe(false);
        // Test v1.10
        const editorV110 = new DbtSchemaEditor('version: 2', '', SupportedDbtVersions.V1_10);
        expect(editorV110.isDbtVersion110OrHigher()).toBe(true);
        // Test undefined version (defaults to false)
        const editorNoVersion = new DbtSchemaEditor('version: 2', '');
        expect(editorNoVersion.isDbtVersion110OrHigher()).toBe(false);
    });
});
//# sourceMappingURL=DbtSchemaEditor.test.js.map