"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;
        });
        /*
        * PrimaryKey, charge the pkObjectIds.length,if
        * >1, do primaryKeyMulti
        * =1, do primaryKey
        * =0,output =''
        * */
        var pkObjectIds = primaryKeys.filter(function (x) { return x.object_id === item.object_id; });
        if (pkObjectIds.length > 1) {
            output += '    ' + this.primaryKey(pkObjectIds);
            output += os_1.EOL;
        }
        else if (pkObjectIds.length === 1) {
            output += '    ' + this.primaryKey(pkObjectIds);
            output += os_1.EOL;
        }
        output += ')';
        foreignKeys = foreignKeys.filter(function (x) { return x.object_id === item.object_id; });
        if (foreignKeys.length || indexes.length) {
            output += os_1.EOL;
            output += os_1.EOL;
        }
        var fkIndex = [];
        foreignKeys.forEach(function (v, index, arr) {
            var flag = 0;
            fkIndex.forEach(function (vx, i, arrx) {
                if (fkIndex[i].name === v.name) {
                    flag = 1;
                }
            });
            if (flag === 0) {
                fkIndex.push({ name: v.name, flag: 0 });
            }
        });
        fkIndex.forEach(function (vx, i, arrx) {
            foreignKeys.filter(function (x) { return x.name === fkIndex[i].name; })
                .forEach(function (v, index, arr) {
                if (vx.flag === 0) {
                    output += _this.foreignKey(arr);
                    output += os_1.EOL;
                    vx.flag = 1;
                }
            });
        });
        output += os_1.EOL;
        indexes = indexes.filter(function (x) { return x.object_id === item.object_id; });
        if (foreignKeys.length && indexes.length) {
            output += os_1.EOL;
        }
        var indexsx = [];
        indexes.forEach(function (v, index, arr) {
            var flag = 0;
            indexsx.forEach(function (vx, i, arrx) {
                if (indexsx[i].name === v.name) {
                    flag = 1;
                }
            });
            if (flag === 0) {
                indexsx.push({ name: v.name, flag: 0 });
            }
        });
        indexsx.forEach(function (vx, i, arrx) {
            indexes.filter(function (x) { return x.name === indexsx[i].name; })
                .forEach(function (v, index, arr) {
                if (vx.flag === 0) {
                    output += _this.index(arr);
                    output += os_1.EOL;
                    vx.flag = 1;
                }
            });
        });
        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(/'/ig, "''");
            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 Row from query.
     */
    MSSQLGenerator.prototype.primaryKey = function (arr) {
        var output = '';
        if (arr.length > 1) {
            arr.forEach(function (v, i, a) {
                var direction = a[i].is_descending_key ? 'DESC' : 'ASC';
                if (i === 0) {
                    output += "CONSTRAINT [" + a[i].name + "] PRIMARY KEY ([" + a[i].column + "] " + direction + ",";
                }
                else {
                    if (i === (a.length - 1)) {
                        output += "[" + a[i].column + "] " + direction + ")";
                    }
                    else {
                        output += "[" + a[i].column + "] " + direction + ",";
                    }
                }
            });
        }
        else if (arr.length === 1) {
            var direction = arr[0].is_descending_key ? 'DESC' : 'ASC';
            output += "CONSTRAINT [" + arr[0].name + "] PRIMARY KEY ([" + arr[0].column + "] " + direction + ")";
        }
        return output;
    };
    /**
     * Get script for table's foreign key.
     *
     * @param item Row from foreignKeys query.
     */
    MSSQLGenerator.prototype.foreignKey = function (arr) {
        var item = arr[0];
        var objectId = "[" + arr[0].schema + "].[" + arr[0].table + "]";
        var parentObjectId = "[" + arr[0].parent_schema + "].[" + arr[0].parent_table + "]";
        var output = '';
        var output1 = '';
        if (arr.length > 1) {
            arr.forEach(function (v, i, a) {
                if (i === 0) {
                    output += "ALTER TABLE " + objectId + " WITH " + (a[i].is_not_trusted ? 'NOCHECK' : 'CHECK');
                    output += " ADD CONSTRAINT [" + a[i].name + "] FOREIGN KEY ([" + a[i].column + "],";
                    output1 += " REFERENCES " + parentObjectId + " ([" + a[i].reference + "],";
                }
                else {
                    if (i === (a.length - 1)) {
                        output += "[" + a[i].column + "])";
                        output1 += " [" + a[i].reference + "])";
                    }
                    else {
                        output += "[" + a[i].column + "],";
                        output1 += "[" + a[i].reference + "],";
                    }
                }
            });
            output += output1;
        }
        else if (arr.length === 1) {
            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 + "]";
        output += os_1.EOL;
        return output;
    };
    /**
     * Get script for table's indexes.
     *
     * @param arr Row from query.
     */
    MSSQLGenerator.prototype.index = function (arr) {
        var output = '';
        if (arr.length > 1) {
            arr.forEach(function (v, i, a) {
                var direction = a[i].is_descending_key ? 'DESC' : 'ASC';
                if (i === 0) {
                    var objectId = "[" + a[i].schema + "].[" + a[i].table + "]";
                    output += "IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE object_id = OBJECT_ID('" + objectId + "') AND name = '" + a[i].name + "')";
                    output += os_1.EOL;
                    output += 'CREATE';
                    if (a[i].is_unique) {
                        output += ' UNIQUE';
                    }
                    output += " NONCLUSTERED INDEX [" + a[i].name + "] ON " + objectId;
                    output += "([" + a[i].column + "] " + (a[i].is_descending_key ? 'DESC' : 'ASC') + ",";
                }
                else {
                    if (i === (a.length - 1)) {
                        output += "[" + a[i].column + "] " + (a[i].is_descending_key ? 'DESC' : 'ASC') + ")";
                    }
                    else {
                        output += "[" + a[i].column + "] " + (a[i].is_descending_key ? 'DESC' : 'ASC') + ",";
                    }
                }
            });
        }
        else if (arr.length === 1) {
            var objectId = "[" + arr[0].schema + "].[" + arr[0].table + "]";
            output += "IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE object_id = OBJECT_ID('" + objectId + "') AND name = '" + arr[0].name + "')";
            output += os_1.EOL;
            output += 'CREATE';
            if (arr[0].is_unique) {
                output += ' UNIQUE';
            }
            output += " NONCLUSTERED INDEX [" + arr[0].name + "] ON " + objectId;
            output += "([" + arr[0].column + "] " + (arr[0].is_descending_key ? 'DESC' : 'ASC') + ")";
        }
        // todo (jbl): includes
        output += os_1.EOL;
        return output;
    };
    return MSSQLGenerator;
}());
exports.default = MSSQLGenerator;
//# sourceMappingURL=mssql.js.map