"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
class MySQL {
    constructor(knex) {
        this.knex = knex;
    }
    // Tables
    // ===============================================================================================
    /**
     * List all existing tables in the current schema/database
     */
    tables() {
        return __awaiter(this, void 0, void 0, function* () {
            const records = yield this.knex
                .select('table_namename')
                .from('information_schema.tables')
                .where({
                table_type: 'BASE TABLE',
                table_schema: this.knex.client.database(),
            });
            return records.map(({ table_name }) => table_name);
        });
    }
    tableInfo(table) {
        return __awaiter(this, void 0, void 0, function* () {
            const query = this.knex
                .select('TABLE_NAME', 'ENGINE', 'TABLE_SCHEMA', 'TABLE_COLLATION', 'TABLE_COMMENT')
                .from('information_schema.tables')
                .where({
                table_schema: this.knex.client.database(),
                table_type: 'BASE TABLE',
            });
            if (table) {
                const rawTable = yield query
                    .andWhere({ table_name: table })
                    .first();
                return {
                    name: rawTable.TABLE_NAME,
                    schema: rawTable.TABLE_SCHEMA,
                    comment: rawTable.TABLE_COMMENT,
                    collation: rawTable.TABLE_COLLATION,
                    engine: rawTable.ENGINE,
                };
            }
            const records = yield query;
            return records.map((rawTable) => {
                return {
                    name: rawTable.TABLE_NAME,
                    schema: rawTable.TABLE_SCHEMA,
                    comment: rawTable.TABLE_COMMENT,
                    collation: rawTable.TABLE_COLLATION,
                    engine: rawTable.ENGINE,
                };
            });
        });
    }
    /**
     * Check if a table exists in the current schema/database
     */
    hasTable(table) {
        return __awaiter(this, void 0, void 0, function* () {
            const { count } = this.knex
                .count({ count: '*' })
                .from('information_schema.tables')
                .where({ table_schema: this.knex.client.database(), table_name: table })
                .first();
            return !!count;
        });
    }
    // Columns
    // ===============================================================================================
    /**
     * Get all the available columns in the current schema/database. Can be filtered to a specific table
     */
    columns(table) {
        return __awaiter(this, void 0, void 0, function* () {
            const query = this.knex
                .select('table_name', 'column_name')
                .from('information_schema.columns')
                .where({ table_schema: this.knex.client.database() });
            if (table) {
                query.andWhere({ table_name: table });
            }
            const records = yield query;
            return records.map(({ table_name, column_name }) => ({
                table: table_name,
                column: column_name,
            }));
        });
    }
    columnInfo(table, column) {
        return __awaiter(this, void 0, void 0, function* () {
            const query = this.knex
                .select('c.TABLE_NAME', 'c.COLUMN_NAME', 'c.COLUMN_DEFAULT', 'c.DATA_TYPE', 'c.CHARACTER_MAXIMUM_LENGTH', 'c.IS_NULLABLE', 'c.COLUMN_KEY', 'c.EXTRA', 'c.COLLATION_NAME', 'c.COLUMN_COMMENT', 'fk.REFERENCED_TABLE_NAME', 'fk.REFERENCED_COLUMN_NAME', 'fk.CONSTRAINT_NAME', 'rc.UPDATE_RULE', 'rc.DELETE_RULE', 'rc.MATCH_OPTION')
                .from('information_schema.columns c')
                .leftJoin('INFORMATION_SCHEMA.KEY_COLUMN_USAGE fk', function () {
                this.on('fk.TABLE_NAME', '=', 'fk.TABLE_NAME')
                    .andOn('fk.COLUMN_NAME', '=', 'c.COLUMN_NAME')
                    .andOn('fk.CONSTRAINT_SCHEMA', '=', 'c.TABLE_SCHEMA');
            })
                .leftJoin('INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc', function () {
                this.on('rc.TABLE_NAME', '=', 'fk.TABLE_NAME')
                    .andOn('rc.CONSTRAINT_NAME', '=', 'fk.CONSTRAINT_NAME')
                    .andOn('rc.CONSTRAINT_SCHEMA', '=', 'fk.CONSTRAINT_SCHEMA');
            })
                .where({
                'c.TABLE_SCHEMA': this.knex.client.database(),
            });
            if (table) {
                query.andWhere({ TABLE_NAME: table });
            }
            if (column) {
                const rawColumn = yield query
                    .andWhere({ 'c.column_name': column })
                    .first();
                return {
                    name: rawColumn.COLUMN_NAME,
                    table: rawColumn.TABLE_NAME,
                    type: rawColumn.DATA_TYPE,
                    default_value: rawColumn.COLUMN_DEFAULT,
                    max_length: rawColumn.CHARACTER_MAXIMUM_LENGTH,
                    is_nullable: rawColumn.IS_NULLABLE,
                    is_primary_key: rawColumn.CONSTRAINT_NAME === 'PRIMARY',
                    has_auto_increment: rawColumn.EXTRA === 'auto_increment',
                    foreign_key_column: rawColumn.REFERENCED_COLUMN_NAME,
                    foreign_key_table: rawColumn.REFERENCED_TABLE_NAME,
                    comment: rawColumn.COLUMN_COMMENT,
                };
            }
            const records = yield query;
            return records.map((rawColumn) => {
                return {
                    name: rawColumn.COLUMN_NAME,
                    table: rawColumn.TABLE_NAME,
                    type: rawColumn.DATA_TYPE,
                    default_value: rawColumn.COLUMN_DEFAULT,
                    max_length: rawColumn.CHARACTER_MAXIMUM_LENGTH,
                    is_nullable: rawColumn.IS_NULLABLE,
                    is_primary_key: rawColumn.CONSTRAINT_NAME === 'PRIMARY',
                    has_auto_increment: rawColumn.EXTRA === 'auto_increment',
                    foreign_key_column: rawColumn.REFERENCED_COLUMN_NAME,
                    foreign_key_table: rawColumn.REFERENCED_TABLE_NAME,
                    comment: rawColumn.COLUMN_COMMENT,
                };
            });
        });
    }
    /**
     * Check if a table exists in the current schema/database
     */
    hasColumn(table, column) {
        return __awaiter(this, void 0, void 0, function* () {
            const { count } = this.knex
                .count({ count: '*' })
                .from('information_schema.tables')
                .where({
                table_schema: this.knex.client.database(),
                table_name: table,
                column_name: column,
            })
                .first();
            return !!count;
        });
    }
    /**
     * Get the primary key column for the given table
     */
    primary(table) {
        return __awaiter(this, void 0, void 0, function* () {
            const { rows } = yield this.knex.raw(`SHOW KEYS FROM ? WHERE Key_name = 'PRIMARY'`, table);
            return rows[0]['Column_name'];
        });
    }
}
exports.default = MySQL;
