UNPKG

typeorm

Version:

Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, WebSQL, MongoDB databases.

818 lines (817 loc) • 80.4 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [0, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; Object.defineProperty(exports, "__esModule", { value: true }); var TransactionAlreadyStartedError_1 = require("../../error/TransactionAlreadyStartedError"); var TransactionNotStartedError_1 = require("../../error/TransactionNotStartedError"); var TableColumn_1 = require("../../schema-builder/schema/TableColumn"); var Table_1 = require("../../schema-builder/schema/Table"); var TableForeignKey_1 = require("../../schema-builder/schema/TableForeignKey"); var TablePrimaryKey_1 = require("../../schema-builder/schema/TablePrimaryKey"); var TableIndex_1 = require("../../schema-builder/schema/TableIndex"); var QueryRunnerAlreadyReleasedError_1 = require("../../error/QueryRunnerAlreadyReleasedError"); var MssqlParameter_1 = require("./MssqlParameter"); var OrmUtils_1 = require("../../util/OrmUtils"); var QueryFailedError_1 = require("../../error/QueryFailedError"); var PromiseUtils_1 = require("../../util/PromiseUtils"); /** * Runs queries on a single mysql database connection. */ var SqlServerQueryRunner = /** @class */ (function () { // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- function SqlServerQueryRunner(driver, mode) { if (mode === void 0) { mode = "master"; } /** * Indicates if connection for this query runner is released. * Once its released, query runner cannot run queries anymore. */ this.isReleased = false; /** * Indicates if transaction is in progress. */ this.isTransactionActive = false; /** * Stores temporarily user data. * Useful for sharing data with subscribers. */ this.data = {}; /** * Last executed query in a transaction. * This is needed because in transaction mode mssql cannot execute parallel queries, * that's why we store last executed query promise to wait it when we execute next query. * * @see https://github.com/patriksimek/node-mssql/issues/491 */ this.queryResponsibilityChain = []; /** * Indicates if special query runner mode in which sql queries won't be executed is enabled. */ this.sqlMemoryMode = false; /** * Sql-s stored if "sql in memory" mode is enabled. */ this.sqlsInMemory = []; this.driver = driver; this.connection = driver.connection; this.mode = mode; } // ------------------------------------------------------------------------- // Public Methods // ------------------------------------------------------------------------- /** * Creates/uses database connection from the connection pool to perform further operations. * Returns obtained database connection. */ SqlServerQueryRunner.prototype.connect = function () { return Promise.resolve(); }; /** * Releases used database connection. * You cannot use query runner methods once its released. */ SqlServerQueryRunner.prototype.release = function () { this.isReleased = true; return Promise.resolve(); }; /** * Starts transaction. */ SqlServerQueryRunner.prototype.startTransaction = function () { return __awaiter(this, void 0, void 0, function () { var _this = this; return __generator(this, function (_a) { if (this.isReleased) throw new QueryRunnerAlreadyReleasedError_1.QueryRunnerAlreadyReleasedError(); if (this.isTransactionActive) throw new TransactionAlreadyStartedError_1.TransactionAlreadyStartedError(); return [2 /*return*/, new Promise(function (ok, fail) { return __awaiter(_this, void 0, void 0, function () { var _this = this; var pool; return __generator(this, function (_a) { switch (_a.label) { case 0: this.isTransactionActive = true; return [4 /*yield*/, (this.mode === "slave" ? this.driver.obtainSlaveConnection() : this.driver.obtainMasterConnection())]; case 1: pool = _a.sent(); this.databaseConnection = pool.transaction(); this.databaseConnection.begin(function (err) { if (err) { _this.isTransactionActive = false; return fail(err); } ok(); }); return [2 /*return*/]; } }); }); })]; }); }); }; /** * Commits transaction. * Error will be thrown if transaction was not started. */ SqlServerQueryRunner.prototype.commitTransaction = function () { return __awaiter(this, void 0, void 0, function () { var _this = this; return __generator(this, function (_a) { if (this.isReleased) throw new QueryRunnerAlreadyReleasedError_1.QueryRunnerAlreadyReleasedError(); if (!this.isTransactionActive) throw new TransactionNotStartedError_1.TransactionNotStartedError(); return [2 /*return*/, new Promise(function (ok, fail) { _this.databaseConnection.commit(function (err) { if (err) return fail(err); _this.isTransactionActive = false; _this.databaseConnection = null; ok(); }); })]; }); }); }; /** * Rollbacks transaction. * Error will be thrown if transaction was not started. */ SqlServerQueryRunner.prototype.rollbackTransaction = function () { return __awaiter(this, void 0, void 0, function () { var _this = this; return __generator(this, function (_a) { if (this.isReleased) throw new QueryRunnerAlreadyReleasedError_1.QueryRunnerAlreadyReleasedError(); if (!this.isTransactionActive) throw new TransactionNotStartedError_1.TransactionNotStartedError(); return [2 /*return*/, new Promise(function (ok, fail) { _this.databaseConnection.rollback(function (err) { if (err) return fail(err); _this.isTransactionActive = false; _this.databaseConnection = null; ok(); }); })]; }); }); }; SqlServerQueryRunner.prototype.mssqlParameterToNativeParameter = function (parameter) { switch (this.driver.normalizeType({ type: parameter.type })) { case "bit": return this.driver.mssql.Bit; case "bigint": return this.driver.mssql.BigInt; case "decimal": return (_a = this.driver.mssql).Decimal.apply(_a, parameter.params); case "float": return this.driver.mssql.Float; case "int": return this.driver.mssql.Int; case "money": return this.driver.mssql.Money; case "numeric": return (_b = this.driver.mssql).Numeric.apply(_b, parameter.params); case "smallint": return this.driver.mssql.SmallInt; case "smallmoney": return this.driver.mssql.SmallMoney; case "real": return this.driver.mssql.Real; case "tinyint": return this.driver.mssql.TinyInt; case "char": return (_c = this.driver.mssql).Char.apply(_c, parameter.params); case "nchar": return (_d = this.driver.mssql).NChar.apply(_d, parameter.params); case "text": return this.driver.mssql.Text; case "ntext": return this.driver.mssql.Ntext; case "varchar": return (_e = this.driver.mssql).VarChar.apply(_e, parameter.params); case "nvarchar": return (_f = this.driver.mssql).NVarChar.apply(_f, parameter.params); case "xml": return this.driver.mssql.Xml; case "time": return (_g = this.driver.mssql).Time.apply(_g, parameter.params); case "date": return this.driver.mssql.Date; case "datetime": return this.driver.mssql.DateTime; case "datetime2": return (_h = this.driver.mssql).DateTime2.apply(_h, parameter.params); case "datetimeoffset": return (_j = this.driver.mssql).DateTimeOffset.apply(_j, parameter.params); case "smalldatetime": return this.driver.mssql.SmallDateTime; case "uniqueidentifier": return this.driver.mssql.UniqueIdentifier; case "variant": return this.driver.mssql.Variant; case "binary": return this.driver.mssql.Binary; case "varbinary": return (_k = this.driver.mssql).VarBinary.apply(_k, parameter.params); case "image": return this.driver.mssql.Image; case "udt": return this.driver.mssql.UDT; case "geography": return this.driver.mssql.Geography; case "geometry": return this.driver.mssql.Geometry; } var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; }; /** * Executes a given SQL query. */ SqlServerQueryRunner.prototype.query = function (query, parameters) { return __awaiter(this, void 0, void 0, function () { var _this = this; var waitingOkay, waitingPromise, otherWaitingPromises, promise; return __generator(this, function (_a) { switch (_a.label) { case 0: if (this.isReleased) throw new QueryRunnerAlreadyReleasedError_1.QueryRunnerAlreadyReleasedError(); waitingPromise = new Promise(function (ok) { return waitingOkay = ok; }); if (!this.queryResponsibilityChain.length) return [3 /*break*/, 2]; otherWaitingPromises = this.queryResponsibilityChain.slice(); this.queryResponsibilityChain.push(waitingPromise); return [4 /*yield*/, Promise.all(otherWaitingPromises)]; case 1: _a.sent(); _a.label = 2; case 2: promise = new Promise(function (ok, fail) { return __awaiter(_this, void 0, void 0, function () { var _this = this; var pool, request_1, queryStartTime_1, err_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); this.driver.connection.logger.logQuery(query, parameters, this); return [4 /*yield*/, (this.mode === "slave" ? this.driver.obtainSlaveConnection() : this.driver.obtainMasterConnection())]; case 1: pool = _a.sent(); request_1 = new this.driver.mssql.Request(this.isTransactionActive ? this.databaseConnection : pool); if (parameters && parameters.length) { parameters.forEach(function (parameter, index) { if (parameter instanceof MssqlParameter_1.MssqlParameter) { var mssqlParameter = _this.mssqlParameterToNativeParameter(parameter); if (mssqlParameter) { request_1.input(index, mssqlParameter, parameter.value); } else { request_1.input(index, parameter.value); } } else { request_1.input(index, parameter); } }); } queryStartTime_1 = +new Date(); request_1.query(query, function (err, result) { // log slow queries if maxQueryExecution time is set var maxQueryExecutionTime = _this.driver.connection.options.maxQueryExecutionTime; var queryEndTime = +new Date(); var queryExecutionTime = queryEndTime - queryStartTime_1; if (maxQueryExecutionTime && queryExecutionTime > maxQueryExecutionTime) _this.driver.connection.logger.logQuerySlow(queryExecutionTime, query, parameters, _this); var resolveChain = function () { if (promiseIndex !== -1) _this.queryResponsibilityChain.splice(promiseIndex, 1); if (waitingPromiseIndex !== -1) _this.queryResponsibilityChain.splice(waitingPromiseIndex, 1); waitingOkay(); }; var promiseIndex = _this.queryResponsibilityChain.indexOf(promise); var waitingPromiseIndex = _this.queryResponsibilityChain.indexOf(waitingPromise); if (err) { _this.driver.connection.logger.logQueryError(err, query, parameters, _this); resolveChain(); return fail(new QueryFailedError_1.QueryFailedError(query, parameters, err)); } ok(result.recordset); resolveChain(); }); return [3 /*break*/, 3]; case 2: err_1 = _a.sent(); fail(err_1); return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); }); if (this.isTransactionActive) this.queryResponsibilityChain.push(promise); return [2 /*return*/, promise]; } }); }); }; /** * Returns raw data stream. */ SqlServerQueryRunner.prototype.stream = function (query, parameters, onEnd, onError) { return __awaiter(this, void 0, void 0, function () { var _this = this; var waitingOkay, waitingPromise, otherWaitingPromises, promise; return __generator(this, function (_a) { switch (_a.label) { case 0: if (this.isReleased) throw new QueryRunnerAlreadyReleasedError_1.QueryRunnerAlreadyReleasedError(); waitingPromise = new Promise(function (ok) { return waitingOkay = ok; }); if (!this.queryResponsibilityChain.length) return [3 /*break*/, 2]; otherWaitingPromises = this.queryResponsibilityChain.slice(); this.queryResponsibilityChain.push(waitingPromise); return [4 /*yield*/, Promise.all(otherWaitingPromises)]; case 1: _a.sent(); _a.label = 2; case 2: promise = new Promise(function (ok, fail) { return __awaiter(_this, void 0, void 0, function () { var _this = this; var pool, request; return __generator(this, function (_a) { switch (_a.label) { case 0: this.driver.connection.logger.logQuery(query, parameters, this); return [4 /*yield*/, (this.mode === "slave" ? this.driver.obtainSlaveConnection() : this.driver.obtainMasterConnection())]; case 1: pool = _a.sent(); request = new this.driver.mssql.Request(this.isTransactionActive ? this.databaseConnection : pool); request.stream = true; if (parameters && parameters.length) { parameters.forEach(function (parameter, index) { if (parameter instanceof MssqlParameter_1.MssqlParameter) { request.input(index, _this.mssqlParameterToNativeParameter(parameter), parameter.value); } else { request.input(index, parameter); } }); } request.query(query, function (err, result) { var resolveChain = function () { if (promiseIndex !== -1) _this.queryResponsibilityChain.splice(promiseIndex, 1); if (waitingPromiseIndex !== -1) _this.queryResponsibilityChain.splice(waitingPromiseIndex, 1); waitingOkay(); }; var promiseIndex = _this.queryResponsibilityChain.indexOf(promise); var waitingPromiseIndex = _this.queryResponsibilityChain.indexOf(waitingPromise); if (err) { _this.driver.connection.logger.logQueryError(err, query, parameters, _this); resolveChain(); return fail(err); } ok(result.recordset); resolveChain(); }); if (onEnd) request.on("done", onEnd); if (onError) request.on("error", onError); ok(request); return [2 /*return*/]; } }); }); }); if (this.isTransactionActive) this.queryResponsibilityChain.push(promise); return [2 /*return*/, promise]; } }); }); }; /** * Insert a new row with given values into the given table. * Returns value of the generated column if given and generate column exist in the table. */ SqlServerQueryRunner.prototype.insert = function (tablePath, keyValues) { return __awaiter(this, void 0, void 0, function () { var keys, columns, values, generatedColumns, generatedColumnNames, generatedColumnSql, sql, parameters, parametersArray, result, generatedMap; return __generator(this, function (_a) { switch (_a.label) { case 0: keys = Object.keys(keyValues); columns = keys.map(function (key) { return "\"" + key + "\""; }).join(", "); values = keys.map(function (key, index) { return "@" + index; }).join(","); generatedColumns = this.connection.hasMetadata(tablePath) ? this.connection.getMetadata(tablePath).generatedColumns : []; generatedColumnNames = generatedColumns.map(function (generatedColumn) { return "INSERTED.\"" + generatedColumn.databaseName + "\""; }).join(", "); generatedColumnSql = generatedColumns.length > 0 ? " OUTPUT " + generatedColumnNames : ""; sql = columns.length > 0 ? "INSERT INTO " + this.escapeTablePath(tablePath) + "(" + columns + ") " + generatedColumnSql + " VALUES (" + values + ")" : "INSERT INTO " + this.escapeTablePath(tablePath) + " " + generatedColumnSql + " DEFAULT VALUES "; parameters = this.driver.parametrizeMap(tablePath, keyValues); parametersArray = Object.keys(parameters).map(function (key) { return parameters[key]; }); return [4 /*yield*/, this.query(sql, parametersArray)]; case 1: result = _a.sent(); generatedMap = generatedColumns.reduce(function (map, column) { var valueMap = column.createValueMap(result[0][column.databaseName]); return OrmUtils_1.OrmUtils.mergeDeep(map, valueMap); }, {}); return [2 /*return*/, { result: result, generatedMap: Object.keys(generatedMap).length > 0 ? generatedMap : undefined }]; } }); }); }; /** * Updates rows that match given conditions in the given table. */ SqlServerQueryRunner.prototype.update = function (tablePath, valuesMap, conditions) { return __awaiter(this, void 0, void 0, function () { var conditionParams, updateParams, allParameters, updateValues, conditionString, sql; return __generator(this, function (_a) { switch (_a.label) { case 0: valuesMap = this.driver.parametrizeMap(tablePath, valuesMap); conditions = this.driver.parametrizeMap(tablePath, conditions); conditionParams = Object.keys(conditions).map(function (key) { return conditions[key]; }); updateParams = Object.keys(valuesMap).map(function (key) { return valuesMap[key]; }); allParameters = updateParams.concat(conditionParams); updateValues = this.parametrize(valuesMap).join(", "); conditionString = this.parametrize(conditions, updateParams.length).join(" AND "); sql = "UPDATE " + this.escapeTablePath(tablePath) + " SET " + updateValues + " " + (conditionString ? (" WHERE " + conditionString) : ""); return [4 /*yield*/, this.query(sql, allParameters)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; /** * Deletes from the given table by a given conditions. */ SqlServerQueryRunner.prototype.delete = function (tablePath, conditions, maybeParameters) { return __awaiter(this, void 0, void 0, function () { var conditionString, parameters, sql; return __generator(this, function (_a) { switch (_a.label) { case 0: conditions = typeof conditions === "object" ? this.driver.parametrizeMap(tablePath, conditions) : conditions; conditionString = typeof conditions === "string" ? conditions : this.parametrize(conditions).join(" AND "); parameters = conditions instanceof Object ? Object.keys(conditions).map(function (key) { return conditions[key]; }) : maybeParameters; sql = "DELETE FROM " + this.escapeTablePath(tablePath) + " WHERE " + conditionString; return [4 /*yield*/, this.query(sql, parameters)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; /** * Inserts rows into the closure table. */ SqlServerQueryRunner.prototype.insertIntoClosureTable = function (tablePath, newEntityId, parentId, hasLevel) { return __awaiter(this, void 0, void 0, function () { var sql, results; return __generator(this, function (_a) { switch (_a.label) { case 0: sql = ""; if (hasLevel) { sql = "INSERT INTO " + this.escapeTablePath(tablePath) + "(\"ancestor\", \"descendant\", \"level\") " + ("SELECT \"ancestor\", " + newEntityId + ", \"level\" + 1 FROM " + this.escapeTablePath(tablePath) + " WHERE \"descendant\" = " + parentId + " ") + ("UNION ALL SELECT " + newEntityId + ", " + newEntityId + ", 1"); } else { sql = "INSERT INTO " + this.escapeTablePath(tablePath) + "(\"ancestor\", \"descendant\") " + ("SELECT \"ancestor\", " + newEntityId + " FROM " + this.escapeTablePath(tablePath) + " WHERE \"descendant\" = " + parentId + " ") + ("UNION ALL SELECT " + newEntityId + ", " + newEntityId); } return [4 /*yield*/, this.query(sql)]; case 1: _a.sent(); if (!hasLevel) return [3 /*break*/, 3]; return [4 /*yield*/, this.query("SELECT MAX(level) as level FROM " + this.escapeTablePath(tablePath) + " WHERE descendant = " + parentId)]; case 2: results = _a.sent(); return [2 /*return*/, results && results[0] && results[0]["level"] ? parseInt(results[0]["level"]) + 1 : 1]; case 3: return [2 /*return*/, -1]; } }); }); }; /** * Loads given table's data from the database. */ SqlServerQueryRunner.prototype.getTable = function (tablePath) { return __awaiter(this, void 0, void 0, function () { var tables; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.getTables([tablePath])]; case 1: tables = _a.sent(); return [2 /*return*/, tables.length > 0 ? tables[0] : undefined]; } }); }); }; /** * Loads all tables (with given names) from the database and creates a Table from them. */ SqlServerQueryRunner.prototype.getTables = function (tablePaths) { return __awaiter(this, void 0, void 0, function () { var _this = this; var tableNames, schemaNames, dbNames, schemaNamesString, tableNamesString, tablesSql, columnsSql, constraintsSql, identityColumnsSql, indicesSql, _a, dbTables, dbColumns, dbConstraints, dbIdentityColumns, dbIndices; return __generator(this, function (_b) { switch (_b.label) { case 0: // if no tables given then no need to proceed if (!tablePaths || !tablePaths.length) return [2 /*return*/, []]; tableNames = tablePaths.map(function (tablePath) { if (tablePath.split(".").length === 3) { return tablePath.split(".")[2]; } else if (tablePath.split(".").length === 2) { return tablePath.split(".")[1]; } else { return tablePath; } }); schemaNames = []; tablePaths.filter(function (tablePath) { return tablePath.indexOf(".") !== -1; }) .forEach(function (tablePath) { if (tablePath.split(".").length === 3) { if (tablePath.split(".")[1] !== "") schemaNames.push(tablePath.split(".")[1]); } else { schemaNames.push(tablePath.split(".")[0]); } }); schemaNames.push(this.driver.options.schema || "SCHEMA_NAME()"); dbNames = tablePaths .filter(function (tablePath) { return tablePath.split(".").length === 3; }) .map(function (tablePath) { return tablePath.split(".")[0]; }); if (this.driver.database && !dbNames.find(function (dbName) { return dbName === _this.driver.database; })) dbNames.push(this.driver.database); schemaNamesString = schemaNames.map(function (name) { return name === "SCHEMA_NAME()" ? name : "'" + name + "'"; }).join(", "); tableNamesString = tableNames.map(function (name) { return "'" + name + "'"; }).join(", "); tablesSql = dbNames.map(function (dbName) { return "SELECT * FROM " + dbName + ".INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME IN (" + tableNamesString + ") AND TABLE_SCHEMA IN (" + schemaNamesString + ")"; }).join(" UNION ALL "); columnsSql = dbNames.map(function (dbName) { return "SELECT * FROM " + dbName + ".INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA IN (" + schemaNamesString + ")"; }).join(" UNION ALL "); constraintsSql = dbNames.map(function (dbName) { return "SELECT columnUsages.*, tableConstraints.CONSTRAINT_TYPE FROM " + dbName + ".INFORMATION_SCHEMA.KEY_COLUMN_USAGE columnUsages " + ("LEFT JOIN " + dbName + ".INFORMATION_SCHEMA.TABLE_CONSTRAINTS tableConstraints ON tableConstraints.CONSTRAINT_NAME = columnUsages.CONSTRAINT_NAME ") + ("WHERE columnUsages.TABLE_SCHEMA IN (" + schemaNamesString + ") AND tableConstraints.TABLE_SCHEMA IN (" + schemaNamesString + ")"); }).join(" UNION ALL "); identityColumnsSql = dbNames.map(function (dbName) { return "SELECT COLUMN_NAME, TABLE_NAME FROM " + dbName + ".INFORMATION_SCHEMA.COLUMNS WHERE COLUMNPROPERTY(object_id(TABLE_SCHEMA + '.' + TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1 AND TABLE_SCHEMA IN (" + schemaNamesString + ")"; }).join(" UNION ALL "); indicesSql = dbNames.map(function (dbName) { return "SELECT TABLE_NAME = t.name, INDEX_NAME = ind.name, IndexId = ind.index_id, ColumnId = ic.index_column_id, \n COLUMN_NAME = col.name, IS_UNIQUE = ind.is_unique, ind.*, ic.*, col.* \n FROM " + dbName + ".sys.indexes ind \n INNER JOIN " + dbName + ".sys.index_columns ic ON ind.object_id = ic.object_id and ind.index_id = ic.index_id\n INNER JOIN " + dbName + ".sys.columns col ON ic.object_id = col.object_id and ic.column_id = col.column_id \n INNER JOIN " + dbName + ".sys.tables t ON ind.object_id = t.object_id WHERE ind.is_primary_key = 0 \n AND ind.is_unique_constraint = 0 AND t.is_ms_shipped = 0"; }).join(" UNION ALL "); return [4 /*yield*/, Promise.all([ this.query(tablesSql), this.query(columnsSql), this.query(constraintsSql), this.query(identityColumnsSql), this.query(indicesSql), ])]; case 1: _a = _b.sent(), dbTables = _a[0], dbColumns = _a[1], dbConstraints = _a[2], dbIdentityColumns = _a[3], dbIndices = _a[4]; // if tables were not found in the db, no need to proceed if (!dbTables.length) return [2 /*return*/, []]; // create table schemas for loaded tables return [2 /*return*/, Promise.all(dbTables.map(function (dbTable) { return __awaiter(_this, void 0, void 0, function () { var table; return __generator(this, function (_a) { table = new Table_1.Table(dbTable["TABLE_NAME"]); table.database = dbTable["TABLE_CATALOG"]; table.schema = dbTable["TABLE_SCHEMA"]; // create columns from the loaded columns table.columns = dbColumns .filter(function (dbColumn) { return dbColumn["TABLE_NAME"] === table.name; }) .map(function (dbColumn) { var isPrimary = !!dbConstraints.find(function (dbConstraint) { return dbConstraint["TABLE_NAME"] === table.name && dbConstraint["COLUMN_NAME"] === dbColumn["COLUMN_NAME"] && dbConstraint["CONSTRAINT_TYPE"] === "PRIMARY KEY"; }); var isGenerated = !!dbIdentityColumns.find(function (column) { return column["TABLE_NAME"] === table.name && column["COLUMN_NAME"] === dbColumn["COLUMN_NAME"]; }); var isUnique = !!dbConstraints.find(function (dbConstraint) { return dbConstraint["TABLE_NAME"] === table.name && dbConstraint["COLUMN_NAME"] === dbColumn["COLUMN_NAME"] && dbConstraint["CONSTRAINT_TYPE"] === "UNIQUE"; }); var tableColumn = new TableColumn_1.TableColumn(); tableColumn.name = dbColumn["COLUMN_NAME"]; tableColumn.type = dbColumn["DATA_TYPE"].toLowerCase(); tableColumn.length = dbColumn["CHARACTER_MAXIMUM_LENGTH"] ? dbColumn["CHARACTER_MAXIMUM_LENGTH"].toString() : ""; if (tableColumn.length === "-1") tableColumn.length = "MAX"; tableColumn.precision = dbColumn["NUMERIC_PRECISION"]; tableColumn.scale = dbColumn["NUMERIC_SCALE"]; tableColumn.default = dbColumn["COLUMN_DEFAULT"] !== null && dbColumn["COLUMN_DEFAULT"] !== undefined ? dbColumn["COLUMN_DEFAULT"] : undefined; tableColumn.isNullable = dbColumn["IS_NULLABLE"] === "YES"; tableColumn.isPrimary = isPrimary; tableColumn.isGenerated = isGenerated; if (tableColumn.default === "(newsequentialid())") { tableColumn.isGenerated = true; tableColumn.default = undefined; } tableColumn.isUnique = isUnique; tableColumn.charset = dbColumn["CHARACTER_SET_NAME"]; tableColumn.collation = dbColumn["COLLATION_NAME"]; tableColumn.comment = ""; // todo: less priority, implement this later if (tableColumn.type === "datetime2" || tableColumn.type === "time" || tableColumn.type === "datetimeoffset") { tableColumn.precision = dbColumn["DATETIME_PRECISION"]; } return tableColumn; }); // create primary key schema table.primaryKeys = dbConstraints .filter(function (dbConstraint) { return dbConstraint["TABLE_NAME"] === table.name && dbConstraint["CONSTRAINT_TYPE"] === "PRIMARY KEY"; }) .map(function (keyColumnUsage) { return new TablePrimaryKey_1.TablePrimaryKey(keyColumnUsage["CONSTRAINT_NAME"], keyColumnUsage["COLUMN_NAME"]); }); // create foreign key schemas from the loaded indices table.foreignKeys = dbConstraints .filter(function (dbConstraint) { return dbConstraint["TABLE_NAME"] === table.name && dbConstraint["CONSTRAINT_TYPE"] === "FOREIGN KEY"; }) .map(function (dbConstraint) { return new TableForeignKey_1.TableForeignKey(dbConstraint["CONSTRAINT_NAME"], [], [], "", ""); }); // todo: fix missing params // create index schemas from the loaded indices table.indices = dbIndices .filter(function (dbIndex) { return dbIndex["TABLE_NAME"] === table.name && (!table.foreignKeys.find(function (foreignKey) { return foreignKey.name === dbIndex["INDEX_NAME"]; })) && (!table.primaryKeys.find(function (primaryKey) { return primaryKey.name === dbIndex["INDEX_NAME"]; })); }) .map(function (dbIndex) { return dbIndex["INDEX_NAME"]; }) .filter(function (value, index, self) { return self.indexOf(value) === index; }) // unqiue .map(function (dbIndexName) { var columnNames = dbIndices .filter(function (dbIndex) { return dbIndex["TABLE_NAME"] === table.name && dbIndex["INDEX_NAME"] === dbIndexName; }) .map(function (dbIndex) { return dbIndex["COLUMN_NAME"]; }); var isUnique = !!dbIndices.find(function (dbIndex) { return dbIndex["TABLE_NAME"] === table.name && dbIndex["INDEX_NAME"] === dbIndexName && dbIndex["IS_UNIQUE"] === true; }); return new TableIndex_1.TableIndex(dbTable["TABLE_NAME"], dbIndexName, columnNames, isUnique); }); return [2 /*return*/, table]; }); }); }))]; } }); }); }; /** * Checks if database with the given name exist. */ SqlServerQueryRunner.prototype.hasDatabase = function (database) { return __awaiter(this, void 0, void 0, function () { var result, dbId; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.query("SELECT DB_ID('" + database + "') as db_id")]; case 1: result = _a.sent(); dbId = result[0]["db_id"]; return [2 /*return*/, !!dbId]; } }); }); }; /** * Checks if table with the given name exist in the database. */ SqlServerQueryRunner.prototype.hasTable = function (tablePath) { return __awaiter(this, void 0, void 0, function () { var parsedTablePath, sql, result; return __generator(this, function (_a) { switch (_a.label) { case 0: parsedTablePath = this.parseTablePath(tablePath); sql = "SELECT * FROM " + parsedTablePath.database + ".INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '" + parsedTablePath.tableName + "' AND TABLE_SCHEMA = " + (parsedTablePath.schema === "SCHEMA_NAME()" ? parsedTablePath.schema : "'" + parsedTablePath.schema + "'"); return [4 /*yield*/, this.query(sql)]; case 1: result = _a.sent(); return [2 /*return*/, result.length ? true : false]; } }); }); }; /** * Creates a database if it's not created. */ SqlServerQueryRunner.prototype.createDatabase = function (database) { return this.query("IF DB_ID('" + database + "') IS NULL CREATE DATABASE " + database); }; /** * Creates a schema if it's not created. */ SqlServerQueryRunner.prototype.createSchema = function (schemaPaths) { var _this = this; if (this.driver.options.schema) schemaPaths.push(this.driver.options.schema); return PromiseUtils_1.PromiseUtils.runInSequence(schemaPaths, function (path) { return __awaiter(_this, void 0, void 0, function () { var query, dbName, schema, currentDBQuery, currentDB, query; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!(path.indexOf(".") === -1)) return [3 /*break*/, 1]; query = "IF SCHEMA_ID('" + path + "') IS NULL BEGIN EXEC sp_executesql N'CREATE SCHEMA " + path + "' END"; return [2 /*return*/, this.query(query)]; case 1: dbName = path.split(".")[0]; schema = path.split(".")[1]; return [4 /*yield*/, this.query("SELECT DB_NAME() AS db_name")]; case 2: currentDBQuery = _a.sent(); currentDB = currentDBQuery[0]["db_name"]; return [4 /*yield*/, this.query("USE " + dbName)]; case 3: _a.sent(); query = "IF SCHEMA_ID('" + schema + "') IS NULL BEGIN EXEC sp_executesql N'CREATE SCHEMA " + schema + "' END"; return [4 /*yield*/, this.query(query)]; case 4: _a.sent(); return [2 /*return*/, this.query("USE " + currentDB)]; } }); }); }); }; /** * Creates a new table from the given table metadata and column metadatas. */ SqlServerQueryRunner.prototype.createTable = function (table) { return __awaiter(this, void 0, void 0, function () { var _this = this; var columnDefinitions, sql, primaryKeyColumns; return __generator(this, function (_a) { switch (_a.label) { case 0: columnDefinitions = table.columns.map(function (column) { return _this.buildCreateColumnSql(table.name, column, false, true); }).join(", "); sql = "CREATE TABLE " + this.escapeTablePath(table) + " (" + columnDefinitions; sql += table.columns .filter(function (column) { return column.isUnique; }) .map(function (column) { var constraintName = table.name + "_" + column.name; var schema = table.schema || _this.driver.options.schema;