"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/* tslint:disable:max-line-length */
var os_1 = require("os");
var ts_util_is_1 = require("ts-util-is");
/**
 * MSSQL generator.
 */
var MSSQLGenerator = /** @class */ (function () {
    function MSSQLGenerator(config) {
        this.config = config;
    }
    /**
     * Get data file content.
     *
     * @param item Row from query.
     */
    MSSQLGenerator.prototype.data = function (item) {
        var _this = this;
        var output = '';
        switch (this.config.idempotency.data) {
            case 'delete':
                output += "DELETE FROM " + item.name + os_1.EOL;
                output += os_1.EOL;
                break;
            case 'delete-and-reseed':
                output += "DELETE FROM " + item.name;
                output += os_1.EOL;
                output += "DBCC CHECKIDENT ('" + item.name + "', RESEED, 0)";
                output += os_1.EOL;
                break;
            case 'truncate':
                output += "TRUNCATE TABLE " + item.name;
                output += os_1.EOL;
                break;
        }
        output += os_1.EOL;
        output += "SET IDENTITY_INSERT " + item.name + " ON";
        output += os_1.EOL;
        output += os_1.EOL;
        item.result.recordset.forEach(function (row) {
            var keys = Object.keys(row);
            var columns = keys.join(', ');
            var values = keys.map(function (key) { return _this.safeValue(row[key]); }).join(', ');
            output += "INSERT INTO " + item.name + " (" + columns + ") VALUES (" + values + ")";
            output += os_1.EOL;
        });
        output += os_1.EOL;
        output += "SET IDENTITY_INSERT " + item.name + " OFF";
        return output;
    };
    /**
     * Get function file content.
     *
     * @param item Row from query.
     */
    MSSQLGenerator.prototype.function = function (item) {
        var objectId = "[" + item.schema + "].[" + item.name + "]";
        var type = item.type.trim();
        var output = '';
        switch (this.config.idempotency.functions) {
            case 'if-exists-drop':
                output += "IF EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID('" + objectId + "') AND type = '" + type + "')";
                output += os_1.EOL;
                output += "DROP FUNCTION " + objectId;
                output += os_1.EOL;
                output += 'GO';
                output += os_1.EOL;
                break;
            case 'if-not-exists':
                output += "IF NOT EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID('" + objectId + "') AND type = '" + type + "')";
                output += os_1.EOL;
                break;
        }
        output += item.text;
        return output;
    };
    /**
     * Get stored procedure file content.
     *
     * @param item Row from query.
     */
    MSSQLGenerator.prototype.storedProcedure = function (item) {
        var objectId = "[" + item.schema + "].[" + item.name + "]";
        var type = item.type.trim();
        var output = '';
        switch (this.config.idempotency.procs) {
            case 'if-exists-drop':
                output += "IF EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID('" + objectId + "') AND type = '" + type + "')";
                output += os_1.EOL;
                output += "DROP PROCEDURE " + objectId;
                output += os_1.EOL;
                output += 'GO';
                output += os_1.EOL;
                break;
            case 'if-not-exists':
                output += "IF NOT EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID('" + objectId + "') AND type = '" + type + "')";
                output += os_1.EOL;
                break;
        }
        output += item.text;
        return output;
    };
    /**
     * Get schema file content.
     *
     * @param item Row from query.
     */
    MSSQLGenerator.prototype.schema = function (item) {
        var output = '';
        output += "IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = '" + item.name + "')";
        output += os_1.EOL;
        output += "EXEC('CREATE SCHEMA " + item.name + "')";
        return output;
    };
    /**
     * Get table file content.
     *
     * @param item Row from query.
     * @param columns Columns from query.
     * @param primaryKeys Primary key from query.
     * @param foreignKeys Foreign keys from query.
     * @param indexes Indexes from query.
     */
    MSSQLGenerator.prototype.table = function (item, columns, primaryKeys, foreignKeys, indexes) {
        var _this = this;
        var objectId = "[" + item.schema + "].[" + item.name + "]";
        var type = item.type.trim();
        var output = '';
        switch (this.config.idempotency.tables) {
            case 'if-exists-drop':
                output += "IF EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID('" + objectId + "') AND type = '" + type + "')";
                output += os_1.EOL;
                output += "DROP TABLE " + objectId;
                output += os_1.EOL;
                output += 'GO';
                output += os_1.EOL;
                break;
            case 'if-not-exists':
                output += "IF NOT EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID('" + objectId + "') AND type = '" + type + "')";
                output += os_1.EOL;
                break;
        }
        output += "CREATE TABLE " + objectId;
        output += os_1.EOL;
        output += '(';
        output += os_1.EOL;
        columns
            .filter(function (x) { return x.object_id === item.object_id; })
            .forEach(function (col) {
            output += '    ' + _this.column(col) + ',';
            output += os_1.EOL;
        });
        primaryKeys
            .filter(function (x) { return x.object_id === item.object_id; })
            .forEach(function (pk) {
            output += '    ' + _this.primaryKey(pk);
            output += os_1.EOL;
        });
        output += ')';
        foreignKeys = foreignKeys.filter(function (x) { return x.object_id === item.object_id; });
        indexes = indexes.filter(function (x) { return x.object_id === item.object_id; });
        if (foreignKeys.length || indexes.length) {
            output += os_1.EOL;
            output += os_1.EOL;
        }
        foreignKeys.forEach(function (fk) {
            output += _this.foreignKey(fk);
            output += os_1.EOL;
        });
        if (foreignKeys.length && indexes.length) {
            output += os_1.EOL;
        }
        indexes.forEach(function (index) {
            output += _this.index(index);
            output += os_1.EOL;
        });
        return output;
    };
    /**
     * Get trigger file content.
     *
     * @param item Row from query.
     */
    MSSQLGenerator.prototype.trigger = function (item) {
        var objectId = "[" + item.schema + "].[" + item.name + "]";
        var type = item.type.trim();
        var output = '';
        switch (this.config.idempotency.triggers) {
            case 'if-exists-drop':
                output += "IF EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID('" + objectId + "') AND type = '" + type + "')";
                output += os_1.EOL;
                output += "DROP TRIGGER " + objectId;
                output += os_1.EOL;
                output += 'GO';
                output += os_1.EOL;
                break;
            case 'if-not-exists':
                output += "IF NOT EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID('" + objectId + "') AND type = '" + type + "')";
                output += os_1.EOL;
                break;
        }
        output += item.text;
        return output;
    };
    /**
     * Get type file content.
     *
     * @param item Row from query.
     * @param columns Columns from query.
     */
    MSSQLGenerator.prototype.type = function (item, columns) {
        var _this = this;
        var objectId = "[" + item.schema + "].[" + item.name + "]";
        var type = item.type.trim();
        var output = '';
        switch (this.config.idempotency.types) {
            case 'if-exists-drop':
                output += 'IF EXISTS (';
                output += os_1.EOL;
                output += '    SELECT 1 FROM sys.table_types AS t';
                output += os_1.EOL;
                output += '    JOIN sys.schemas s ON t.schema_id = s.schema_id';
                output += os_1.EOL;
                output += "    WHERE t.name = '" + item.name + "' AND s.name = '" + item.schema + "'";
                output += os_1.EOL;
                output += ')';
                output += os_1.EOL;
                output += "DROP TYPE " + objectId;
                output += os_1.EOL;
                output += 'GO';
                output += os_1.EOL;
                break;
            case 'if-not-exists':
                output += "IF NOT EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID('" + objectId + "') AND type = '" + type + "')";
                output += os_1.EOL;
                break;
        }
        output += "CREATE TYPE " + objectId + " AS TABLE";
        output += os_1.EOL;
        output += '(';
        output += os_1.EOL;
        columns
            .filter(function (x) { return x.object_id === item.object_id; })
            .forEach(function (col, idx, array) {
            output += '    ' + _this.column(col);
            if (idx !== array.length - 1) {
                // not the last column
                output += ',';
            }
            output += os_1.EOL;
        });
        output += ')';
        return output;
    };
    /**
     * Get view file content.
     *
     * @param item Row from query.
     */
    MSSQLGenerator.prototype.view = function (item) {
        var objectId = "[" + item.schema + "].[" + item.name + "]";
        var type = item.type.trim();
        var output = '';
        switch (this.config.idempotency.views) {
            case 'if-exists-drop':
                output += "IF EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID('" + objectId + "') AND type = '" + type + "')";
                output += os_1.EOL;
                output += "DROP VIEW " + objectId;
                output += os_1.EOL;
                output += 'GO';
                output += os_1.EOL;
                break;
            case 'if-not-exists':
                output += "IF NOT EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID('" + objectId + "') AND type = '" + type + "')";
                output += os_1.EOL;
                break;
        }
        output += item.text;
        return output;
    };
    /**
     * Safely transform SQL value for scripting.
     *
     * @param value SQL data value.
     */
    MSSQLGenerator.prototype.safeValue = function (value) {
        if (ts_util_is_1.isNull(value)) {
            return 'NULL';
        }
        if (ts_util_is_1.isString(value)) {
            value = value.replace("'", "''");
            return "'" + value + "'";
        }
        if (ts_util_is_1.isDate(value)) {
            value = value.toISOString();
            return "'" + value + "'";
        }
        if (ts_util_is_1.isBoolean(value)) {
            return value ? 1 : 0;
        }
        return value;
    };
    /**
     * Get script for table's column.
     *
     * @param item Row from query.
     */
    MSSQLGenerator.prototype.column = function (item) {
        var output = "[" + item.name + "]";
        var size;
        if (item.is_computed) {
            output += " AS " + item.formula;
            return output;
        }
        output += " " + item.datatype;
        switch (item.datatype) {
            case 'varchar':
            case 'char':
            case 'varbinary':
            case 'binary':
            case 'text':
                size = (item.max_length === -1 ? 'max' : item.max_length);
                output += "(" + size + ")";
                break;
            case 'nvarchar':
            case 'nchar':
            case 'ntext':
                size = (item.max_length === -1 ? 'max' : item.max_length / 2);
                output += "(" + size + ")";
                break;
            case 'datetime2':
            case 'time2':
            case 'datetimeoffset':
                output += "(" + item.scale + ")";
                break;
            case 'decimal':
                output += "(" + item.precision + ", " + item.scale + ")";
                break;
        }
        if (item.collation_name) {
            output += " COLLATE " + item.collation_name;
        }
        output += item.is_nullable ? ' NULL' : ' NOT NULL';
        if (item.definition) {
            output += " DEFAULT" + item.definition;
        }
        if (item.is_identity) {
            output += " IDENTITY(" + (item.seed_value || 0) + ", " + (item.increment_value || 1) + ")";
        }
        return output;
    };
    /**
     * Get script for table's primary key.
     *
     * @param item Row from query.
     */
    MSSQLGenerator.prototype.primaryKey = function (item) {
        var direction = item.is_descending_key ? 'DESC' : 'ASC';
        return "CONSTRAINT [" + item.name + "] PRIMARY KEY ([" + item.column + "] " + direction + ")";
    };
    /**
     * Get script for table's foreign key.
     *
     * @param item Row from foreignKeys query.
     */
    MSSQLGenerator.prototype.foreignKey = function (item) {
        var objectId = "[" + item.schema + "].[" + item.table + "]";
        var parentObjectId = "[" + item.parent_schema + "].[" + item.parent_table + "]";
        var output = '';
        output += "ALTER TABLE " + objectId + " WITH " + (item.is_not_trusted ? 'NOCHECK' : 'CHECK');
        output += " ADD CONSTRAINT [" + item.name + "] FOREIGN KEY ([" + item.column + "])";
        output += " REFERENCES " + parentObjectId + " ([" + item.reference + "])";
        switch (item.delete_referential_action) {
            case 1:
                output += ' ON DELETE CASCADE';
                break;
            case 2:
                output += ' ON DELETE SET NULL';
                break;
            case 3:
                output += ' ON DELETE SET DEFAULT';
                break;
        }
        switch (item.update_referential_action) {
            case 1:
                output += ' ON UPDATE CASCADE';
                break;
            case 2:
                output += ' ON UPDATE SET NULL';
                break;
            case 3:
                output += ' ON UPDATE SET DEFAULT';
                break;
        }
        output += os_1.EOL;
        output += "ALTER TABLE " + objectId + " CHECK CONSTRAINT [" + item.name + "]";
        return output;
    };
    /**
     * Get script for table's indexes.
     *
     * @param item Row from query.
     */
    MSSQLGenerator.prototype.index = function (item) {
        var objectId = "[" + item.schema + "].[" + item.table + "]";
        var output = '';
        output += "IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE object_id = OBJECT_ID('" + objectId + "') AND name = '" + item.name + "')";
        output += os_1.EOL;
        output += 'CREATE';
        if (item.is_unique) {
            output += ' UNIQUE';
        }
        output += " NONCLUSTERED INDEX [" + item.name + "] ON " + objectId;
        output += "([" + item.column + "] " + (item.is_descending_key ? 'DESC' : 'ASC') + ")";
        // todo (jbl): includes
        output += os_1.EOL;
        return output;
    };
    return MSSQLGenerator;
}());
exports.default = MSSQLGenerator;
//# sourceMappingURL=mssql.js.map