UNPKG

typeorm

Version:

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

899 lines • 59.2 kB
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 }; } }; import { TransactionAlreadyStartedError } from "../../error/TransactionAlreadyStartedError"; import { TransactionNotStartedError } from "../../error/TransactionNotStartedError"; import { TableColumn } from "../../schema-builder/schema/TableColumn"; import { Table } from "../../schema-builder/schema/Table"; import { TableForeignKey } from "../../schema-builder/schema/TableForeignKey"; import { TablePrimaryKey } from "../../schema-builder/schema/TablePrimaryKey"; import { TableIndex } from "../../schema-builder/schema/TableIndex"; import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"; import { OrmUtils } from "../../util/OrmUtils"; import { QueryFailedError } from "../../error/QueryFailedError"; /** * Runs queries on a single mysql database connection. */ var MysqlQueryRunner = /** @class */ (function () { // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- function MysqlQueryRunner(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 = {}; /** * 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. */ MysqlQueryRunner.prototype.connect = function () { var _this = this; if (this.databaseConnection) return Promise.resolve(this.databaseConnection); if (this.databaseConnectionPromise) return this.databaseConnectionPromise; if (this.mode === "slave" && this.driver.isReplicated) { this.databaseConnectionPromise = this.driver.obtainSlaveConnection().then(function (connection) { _this.databaseConnection = connection; return _this.databaseConnection; }); } else { this.databaseConnectionPromise = this.driver.obtainMasterConnection().then(function (connection) { _this.databaseConnection = connection; return _this.databaseConnection; }); } return this.databaseConnectionPromise; }; /** * Releases used database connection. * You cannot use query runner methods once its released. */ MysqlQueryRunner.prototype.release = function () { this.isReleased = true; if (this.databaseConnection) this.databaseConnection.release(); return Promise.resolve(); }; /** * Starts transaction on the current connection. */ MysqlQueryRunner.prototype.startTransaction = function () { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: if (this.isTransactionActive) throw new TransactionAlreadyStartedError(); this.isTransactionActive = true; return [4 /*yield*/, this.query("START TRANSACTION")]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; /** * Commits transaction. * Error will be thrown if transaction was not started. */ MysqlQueryRunner.prototype.commitTransaction = function () { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: if (!this.isTransactionActive) throw new TransactionNotStartedError(); return [4 /*yield*/, this.query("COMMIT")]; case 1: _a.sent(); this.isTransactionActive = false; return [2 /*return*/]; } }); }); }; /** * Rollbacks transaction. * Error will be thrown if transaction was not started. */ MysqlQueryRunner.prototype.rollbackTransaction = function () { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: if (!this.isTransactionActive) throw new TransactionNotStartedError(); return [4 /*yield*/, this.query("ROLLBACK")]; case 1: _a.sent(); this.isTransactionActive = false; return [2 /*return*/]; } }); }); }; /** * Executes a raw SQL query. */ MysqlQueryRunner.prototype.query = function (query, parameters) { var _this = this; if (this.isReleased) throw new QueryRunnerAlreadyReleasedError(); return new Promise(function (ok, fail) { return __awaiter(_this, void 0, void 0, function () { var _this = this; var databaseConnection, queryStartTime_1, err_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, this.connect()]; case 1: databaseConnection = _a.sent(); this.driver.connection.logger.logQuery(query, parameters, this); queryStartTime_1 = +new Date(); databaseConnection.query(query, parameters, 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); if (err) { _this.driver.connection.logger.logQueryError(err, query, parameters, _this); return fail(new QueryFailedError(query, parameters, err)); } ok(result); }); return [3 /*break*/, 3]; case 2: err_1 = _a.sent(); fail(err_1); return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); }); }; /** * Returns raw data stream. */ MysqlQueryRunner.prototype.stream = function (query, parameters, onEnd, onError) { var _this = this; if (this.isReleased) throw new QueryRunnerAlreadyReleasedError(); return new Promise(function (ok, fail) { return __awaiter(_this, void 0, void 0, function () { var databaseConnection, stream, err_2; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, this.connect()]; case 1: databaseConnection = _a.sent(); this.driver.connection.logger.logQuery(query, parameters, this); stream = databaseConnection.query(query, parameters); if (onEnd) stream.on("end", onEnd); if (onError) stream.on("error", onError); ok(stream); return [3 /*break*/, 3]; case 2: err_2 = _a.sent(); fail(err_2); return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); }); }; /** * 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. */ MysqlQueryRunner.prototype.insert = function (tablePath, keyValues) { return __awaiter(this, void 0, void 0, function () { var keys, columns, values, parameters, generatedColumns, sql, 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) { return "?"; }).join(","); parameters = keys.map(function (key) { return keyValues[key]; }); generatedColumns = this.connection.hasMetadata(tablePath) ? this.connection.getMetadata(tablePath).generatedColumns : []; sql = "INSERT INTO `" + this.escapeTablePath(tablePath) + "`(" + columns + ") VALUES (" + values + ")"; return [4 /*yield*/, this.query(sql, parameters)]; case 1: result = _a.sent(); generatedMap = generatedColumns.reduce(function (map, generatedColumn) { var value = generatedColumn.isPrimary && result.insertId ? result.insertId : keyValues[generatedColumn.databaseName]; if (!value) return map; return OrmUtils.mergeDeep(map, generatedColumn.createValueMap(value)); }, {}); return [2 /*return*/, { result: result, generatedMap: Object.keys(generatedMap).length > 0 ? generatedMap : undefined }]; } }); }); }; /** * Updates rows that match given conditions in the given table. */ MysqlQueryRunner.prototype.update = function (tablePath, valuesMap, conditions) { return __awaiter(this, void 0, void 0, function () { var updateValues, conditionString, sql, conditionParams, updateParams, allParameters; return __generator(this, function (_a) { switch (_a.label) { case 0: updateValues = this.parametrize(valuesMap).join(", "); conditionString = this.parametrize(conditions).join(" AND "); sql = "UPDATE `" + this.escapeTablePath(tablePath) + "` SET " + updateValues + " " + (conditionString ? (" WHERE " + conditionString) : ""); conditionParams = Object.keys(conditions).map(function (key) { return conditions[key]; }); updateParams = Object.keys(valuesMap).map(function (key) { return valuesMap[key]; }); allParameters = updateParams.concat(conditionParams); return [4 /*yield*/, this.query(sql, allParameters)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; /** * Deletes from the given table by a given conditions. */ MysqlQueryRunner.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: 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. */ MysqlQueryRunner.prototype.insertIntoClosureTable = function (tablePath, newEntityId, parentId, hasLevel) { return __awaiter(this, void 0, void 0, function () { var results; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!hasLevel) return [3 /*break*/, 2]; return [4 /*yield*/, this.query("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"))]; case 1: _a.sent(); return [3 /*break*/, 4]; case 2: return [4 /*yield*/, this.query("INSERT INTO `" + this.escapeTablePath(tablePath) + "`(`ancestor`, `descendant`) " + ("SELECT `ancestor`, " + newEntityId + " FROM `" + this.escapeTablePath(tablePath) + "` WHERE `descendant` = " + parentId + " ") + ("UNION ALL SELECT " + newEntityId + ", " + newEntityId))]; case 3: _a.sent(); _a.label = 4; case 4: if (!hasLevel) return [3 /*break*/, 6]; return [4 /*yield*/, this.query("SELECT MAX(`level`) as `level` FROM `" + this.escapeTablePath(tablePath) + "` WHERE `descendant` = " + parentId)]; case 5: results = _a.sent(); return [2 /*return*/, results && results[0] && results[0]["level"] ? parseInt(results[0]["level"]) + 1 : 1]; case 6: return [2 /*return*/, -1]; } }); }); }; /** * Loads given table's data from the database. */ MysqlQueryRunner.prototype.getTable = function (tableName) { 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([tableName])]; 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. */ MysqlQueryRunner.prototype.getTables = function (tablePaths) { return __awaiter(this, void 0, void 0, function () { var _this = this; var tableNames, dbNames, databaseNamesString, tableNamesString, tablesSql, columnsSql, indicesSql, foreignKeysSql, _a, dbTables, dbColumns, dbIndices, dbForeignKeys, isMariaDb; return __generator(this, function (_b) { switch (_b.label) { case 0: if (this.sqlMemoryMode) throw new Error("Loading table is not supported in sql memory mode"); // if no tables given then no need to proceed if (!tablePaths || !tablePaths.length) return [2 /*return*/, []]; tableNames = tablePaths.map(function (tablePath) { return tablePath.indexOf(".") === -1 ? tablePath : tablePath.split(".")[1]; }); dbNames = tablePaths .filter(function (tablePath) { return tablePath.indexOf(".") !== -1; }) .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); databaseNamesString = dbNames.map(function (dbName) { return "'" + dbName + "'"; }).join(", "); tableNamesString = tableNames.map(function (tableName) { return "'" + tableName + "'"; }).join(", "); tablesSql = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA IN (" + databaseNamesString + ") AND TABLE_NAME IN (" + tableNamesString + ")"; columnsSql = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA IN (" + databaseNamesString + ")"; indicesSql = "SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA IN (" + databaseNamesString + ") AND INDEX_NAME != 'PRIMARY' ORDER BY SEQ_IN_INDEX"; foreignKeysSql = "SELECT * FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA IN (" + databaseNamesString + ") AND REFERENCED_COLUMN_NAME IS NOT NULL"; return [4 /*yield*/, Promise.all([ this.query(tablesSql), this.query(columnsSql), this.query(indicesSql), this.query(foreignKeysSql) ])]; case 1: _a = _b.sent(), dbTables = _a[0], dbColumns = _a[1], dbIndices = _a[2], dbForeignKeys = _a[3]; // if tables were not found in the db, no need to proceed if (!dbTables.length) return [2 /*return*/, []]; isMariaDb = this.driver.options.type === "mariadb"; // create tables for loaded tables return [2 /*return*/, Promise.all(dbTables.map(function (dbTable) { return __awaiter(_this, void 0, void 0, function () { var table, primaryKeys; return __generator(this, function (_a) { switch (_a.label) { case 0: table = new Table(dbTable["TABLE_NAME"]); table.database = dbTable["TABLE_SCHEMA"]; return [4 /*yield*/, this.query("SHOW INDEX FROM `" + dbTable["TABLE_SCHEMA"] + "`.`" + dbTable["TABLE_NAME"] + "` WHERE Key_name = 'PRIMARY'")]; case 1: primaryKeys = _a.sent(); // create columns from the loaded columns table.columns = dbColumns .filter(function (dbColumn) { return dbColumn["TABLE_NAME"] === table.name; }) .map(function (dbColumn) { var tableColumn = new TableColumn(); tableColumn.name = dbColumn["COLUMN_NAME"]; var columnType = dbColumn["COLUMN_TYPE"].toLowerCase(); var endIndex = columnType.indexOf("("); tableColumn.type = endIndex !== -1 ? columnType.substring(0, endIndex) : columnType; if (dbColumn["COLUMN_DEFAULT"] === null || dbColumn["COLUMN_DEFAULT"] === undefined || (isMariaDb && dbColumn["COLUMN_DEFAULT"] === "NULL")) { tableColumn.default = undefined; } else { tableColumn.default = dbColumn["COLUMN_DEFAULT"]; } tableColumn.isNullable = dbColumn["IS_NULLABLE"] === "YES"; tableColumn.isPrimary = dbColumn["COLUMN_KEY"].indexOf("PRI") !== -1; tableColumn.isUnique = dbColumn["COLUMN_KEY"].indexOf("UNI") !== -1; tableColumn.isGenerated = dbColumn["EXTRA"].indexOf("auto_increment") !== -1; tableColumn.comment = dbColumn["COLUMN_COMMENT"]; tableColumn.precision = dbColumn["NUMERIC_PRECISION"]; tableColumn.scale = dbColumn["NUMERIC_SCALE"]; tableColumn.charset = dbColumn["CHARACTER_SET_NAME"]; tableColumn.collation = dbColumn["COLLATION_NAME"]; if (tableColumn.type === "int" || tableColumn.type === "tinyint" || tableColumn.type === "smallint" || tableColumn.type === "mediumint" || tableColumn.type === "bigint" || tableColumn.type === "year") { var length_1 = columnType.substring(columnType.indexOf("(") + 1, columnType.indexOf(")")); tableColumn.length = length_1 ? length_1.toString() : ""; } else { tableColumn.length = dbColumn["CHARACTER_MAXIMUM_LENGTH"] ? dbColumn["CHARACTER_MAXIMUM_LENGTH"].toString() : ""; } if (tableColumn.type === "enum") { var colType = dbColumn["COLUMN_TYPE"]; var items = colType.substring(colType.indexOf("(") + 1, colType.indexOf(")")).split(","); tableColumn.enum = items.map(function (item) { return item.substring(1, item.length - 1); }); } if (tableColumn.type === "datetime" || tableColumn.type === "time" || tableColumn.type === "timestamp") { tableColumn.precision = dbColumn["DATETIME_PRECISION"]; } return tableColumn; }); // create primary keys table.primaryKeys = primaryKeys.map(function (primaryKey) { return new TablePrimaryKey(primaryKey["Key_name"], primaryKey["Column_name"]); }); // create foreign key schemas from the loaded indices table.foreignKeys = dbForeignKeys .filter(function (dbForeignKey) { return dbForeignKey["TABLE_NAME"] === table.name; }) .map(function (dbForeignKey) { return new TableForeignKey(dbForeignKey["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 currentDbIndices = dbIndices.filter(function (dbIndex) { return dbIndex["TABLE_NAME"] === table.name && dbIndex["INDEX_NAME"] === dbIndexName; }); var columnNames = currentDbIndices.map(function (dbIndex) { return dbIndex["COLUMN_NAME"]; }); // find a special index - unique index and if (currentDbIndices.length === 1 && currentDbIndices[0]["NON_UNIQUE"] === 0) { var column = table.columns.find(function (column) { return column.name === currentDbIndices[0]["INDEX_NAME"] && column.name === currentDbIndices[0]["COLUMN_NAME"]; }); if (column) { column.isUnique = true; return; } } return new TableIndex(dbTable["TABLE_NAME"], dbIndexName, columnNames, currentDbIndices[0]["NON_UNIQUE"] === 0); }) .filter(function (index) { return !!index; }); // remove empty returns return [2 /*return*/, table]; } }); }); }))]; } }); }); }; /** * Checks if database with the given name exist. */ MysqlQueryRunner.prototype.hasDatabase = function (database) { return __awaiter(this, void 0, void 0, function () { var result; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.query("SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '" + database + "'")]; case 1: result = _a.sent(); return [2 /*return*/, result.length ? true : false]; } }); }); }; /** * Checks if table with the given name exist in the database. */ MysqlQueryRunner.prototype.hasTable = function (tableOrPath) { 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(tableOrPath); sql = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '" + parsedTablePath.database + "' AND TABLE_NAME = '" + parsedTablePath.tableName + "'"; return [4 /*yield*/, this.query(sql)]; case 1: result = _a.sent(); return [2 /*return*/, result.length ? true : false]; } }); }); }; /** * Checks if column with the given name exist in the given table. */ MysqlQueryRunner.prototype.hasColumn = function (tableOrPath, column) { return __awaiter(this, void 0, void 0, function () { var parsedTablePath, columnName, sql, result; return __generator(this, function (_a) { switch (_a.label) { case 0: parsedTablePath = this.parseTablePath(tableOrPath); columnName = column instanceof TableColumn ? column.name : column; sql = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '" + parsedTablePath.database + "' AND TABLE_NAME = '" + parsedTablePath.tableName + "' AND COLUMN_NAME = '" + columnName + "'"; 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. */ MysqlQueryRunner.prototype.createDatabase = function (database) { return this.query("CREATE DATABASE IF NOT EXISTS " + database); // todo(dima): IT SHOULD NOT EXECUTE "IF NOT EXIST" if user already has a database (privileges issue) }; /** * Creates a schema if it's not created. */ MysqlQueryRunner.prototype.createSchema = function (schemas) { return Promise.resolve([]); }; /** * Creates a new table from the given table and column inside it. */ MysqlQueryRunner.prototype.createTable = function (table) { return __awaiter(this, void 0, void 0, function () { var _this = this; var columnDefinitions, sql, primaryKeyColumns, revertSql; return __generator(this, function (_a) { columnDefinitions = table.columns.map(function (column) { return _this.buildCreateColumnSql(column, false); }).join(", "); sql = "CREATE TABLE `" + this.escapeTablePath(table) + "` (" + columnDefinitions; primaryKeyColumns = table.columns.filter(function (column) { return column.isPrimary && !column.isGenerated; }); if (primaryKeyColumns.length > 0) sql += ", PRIMARY KEY(" + primaryKeyColumns.map(function (column) { return "`" + column.name + "`"; }).join(", ") + ")"; sql += ") ENGINE=" + (table.engine || "InnoDB"); revertSql = "DROP TABLE `" + this.escapeTablePath(table) + "`"; return [2 /*return*/, this.schemaQuery(sql, revertSql)]; }); }); }; /** * Drop the table. */ MysqlQueryRunner.prototype.dropTable = function (tableOrPath) { return __awaiter(this, void 0, void 0, function () { var sql; return __generator(this, function (_a) { sql = "DROP TABLE `" + this.escapeTablePath(tableOrPath) + "`"; return [2 /*return*/, this.query(sql)]; }); }); }; /** * Creates a new column from the column in the table. */ MysqlQueryRunner.prototype.addColumn = function (tableOrPath, column) { return __awaiter(this, void 0, void 0, function () { var sql, revertSql; return __generator(this, function (_a) { sql = "ALTER TABLE `" + this.escapeTablePath(tableOrPath) + "` ADD " + this.buildCreateColumnSql(column, false); revertSql = "ALTER TABLE `" + this.escapeTablePath(tableOrPath) + "` DROP `" + column.name + "`"; return [2 /*return*/, this.schemaQuery(sql, revertSql)]; }); }); }; /** * Creates a new columns from the column in the table. */ MysqlQueryRunner.prototype.addColumns = function (tableOrName, columns) { return __awaiter(this, void 0, void 0, function () { var _this = this; var queries; return __generator(this, function (_a) { switch (_a.label) { case 0: queries = columns.map(function (column) { return _this.addColumn(tableOrName, column); }); return [4 /*yield*/, Promise.all(queries)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; /** * Renames column in the given table. */ MysqlQueryRunner.prototype.renameColumn = function (tableOrName, oldTableColumnOrName, newTableColumnOrName) { return __awaiter(this, void 0, void 0, function () { var table, oldColumn, newColumn; return __generator(this, function (_a) { switch (_a.label) { case 0: table = undefined; if (!(tableOrName instanceof Table)) return [3 /*break*/, 1]; table = tableOrName; return [3 /*break*/, 3]; case 1: return [4 /*yield*/, this.getTable(tableOrName)]; case 2: table = _a.sent(); // todo: throw exception, this wont work because of sql memory enabled. remove support by table name if (!table) throw new Error("Table " + tableOrName + " was not found."); _a.label = 3; case 3: oldColumn = undefined; if (oldTableColumnOrName instanceof TableColumn) { oldColumn = oldTableColumnOrName; } else { oldColumn = table.columns.find(function (column) { return column.name === oldTableColumnOrName; }); } if (!oldColumn) throw new Error("Column \"" + oldTableColumnOrName + "\" was not found in the \"" + tableOrName + "\" table."); newColumn = undefined; if (newTableColumnOrName instanceof TableColumn) { newColumn = newTableColumnOrName; } else { newColumn = oldColumn.clone(); newColumn.name = newTableColumnOrName; } return [2 /*return*/, this.changeColumn(table, oldColumn, newColumn)]; } }); }); }; /** * Changes a column in the table. */ MysqlQueryRunner.prototype.changeColumn = function (tableOrName, oldTableColumnOrName, newColumn) { return __awaiter(this, void 0, void 0, function () { var table, oldColumn, sql, revertSql; return __generator(this, function (_a) { switch (_a.label) { case 0: table = undefined; if (!(tableOrName instanceof Table)) return [3 /*break*/, 1]; table = tableOrName; return [3 /*break*/, 3]; case 1: return [4 /*yield*/, this.getTable(tableOrName)]; case 2: table = _a.sent(); _a.label = 3; case 3: if (!table) throw new Error("Table " + tableOrName + " was not found."); oldColumn = undefined; if (oldTableColumnOrName instanceof TableColumn) { oldColumn = oldTableColumnOrName; } else { oldColumn = table.columns.find(function (column) { return column.name === oldTableColumnOrName; }); } if (!oldColumn) throw new Error("Column \"" + oldTableColumnOrName + "\" was not found in the \"" + tableOrName + "\" table."); if (!(newColumn.isUnique === false && oldColumn.isUnique === true)) return [3 /*break*/, 5]; return [4 /*yield*/, this.query("ALTER TABLE `" + this.escapeTablePath(table) + "` DROP INDEX `" + oldColumn.name + "`")]; case 4: _a.sent(); // todo: add revert code _a.label = 5; case 5: sql = "ALTER TABLE `" + this.escapeTablePath(table) + "` CHANGE `" + oldColumn.name + "` " + this.buildCreateColumnSql(newColumn, oldColumn.isPrimary); revertSql = "ALTER TABLE `" + this.escapeTablePath(table) + "` CHANGE `" + oldColumn.name + "` " + this.buildCreateColumnSql(oldColumn, oldColumn.isPrimary); return [2 /*return*/, this.schemaQuery(sql, revertSql)]; } }); }); }; /** * Changes a column in the table. */ MysqlQueryRunner.prototype.changeColumns = function (table, changedColumns) { return __awaiter(this, void 0, void 0, function () { var _this = this; var updatePromises; return __generator(this, function (_a) { switch (_a.label) { case 0: updatePromises = changedColumns.map(function (changedColumn) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, this.changeColumn(table, changedColumn.oldColumn, changedColumn.newColumn)]; }); }); }); return [4 /*yield*/, Promise.all(updatePromises)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; /** * Drops column in the table. */ MysqlQueryRunner.prototype.dropColumn = function (table, column) { return __awaiter(this, void 0, void 0, function () { var sql, revertSql; return __generator(this, function (_a) { sql = "ALTER TABLE `" + this.escapeTablePath(table) + "` DROP `" + column.name + "`"; revertSql = "ALTER TABLE `" + this.escapeTablePath(table) + "` ADD " + this.buildCreateColumnSql(column, false); return [2 /*return*/, this.schemaQuery(sql, revertSql)]; }); }); }; /** * Drops the columns in the table. */ MysqlQueryRunner.prototype.dropColumns = function (table, columns) { return __awaiter(this, void 0, void 0, function () { var _this = this; var dropPromises; return __generator(this, function (_a) { switch (_a.label) { case 0: dropPromises = columns.map(function (column) { return _this.dropColumn(table, column); }); return [4 /*yield*/, Promise.all(dropPromises)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; /** * Updates table's primary keys. */ MysqlQueryRunner.prototype.updatePrimaryKeys = function (table) { return __awaiter(this, void 0, void 0, function () { var primaryColumnNames, sql, revertSql; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!!table.hasGeneratedColumn) return [3 /*break*/, 2]; return [4 /*yield*/, this.query("ALTER TABLE `" + this.escapeTablePath(table) + "` DROP PRIMARY KEY")]; case 1: _a.sent(); _a.label = 2; case 2: primaryColumnNames = table.columns .filter(function (column) { return column.isPrimary && !column.isGenerated; }) .map(function (column) { return "`" + column.name + "`"; }); if (primaryColumnNames.length > 0) { sql = "ALTER TABLE `" + this.escapeTablePath(table) + "` ADD PRIMARY KEY (" + primaryColumnNames.join(", ") + ")"; revertSql = "ALTER TABLE `" + this.escapeTablePath(table) + "` DROP PRIMARY KEY"; return [2 /*return*/, this.schemaQuery(sql, revertSql)]; } return [2 /*return*/]; } }); }); }; /** * Creates a new foreign key. */ MysqlQueryRunner.prototype.createForeignKey = function (tableOrPath, foreignKey) { return __awaiter(this, void 0, void 0, function () { var columnNames, referencedColumnNames, sql, revertSql; return __generator(this, function (_a) { columnNames = foreignKey.columnNames.map(function (column) { return "`" + column + "`"; }).join(", "); referencedColumnNames = foreignKey.referencedColumnNames.map(function (column) { return "`" + column + "`"; }).join(","); sql = "ALTER TABLE `" + this.escapeTablePath(tableOrPath) + "` ADD CONSTRAINT `" + foreignKey.name + "` " + ("FOREIGN KEY (" + columnNames + ") ") + ("REFERENCES `" + foreignKey.referencedTableName + "`(" + referencedColumnNames + ")"); if (foreignKey.onDelete) sql += " ON DELETE " + foreignKey.onDelete; revertSql = "ALTER TABLE `" + this.escapeTablePath(tableOrPath) + "` DROP FOREIGN KEY `" + foreignKey.name + "`"; return [2 /*return*/, this.schemaQuery(sql, revertSql)]; }); }); }; /** * Creates a new foreign keys. */ MysqlQueryRunner.prototype.createForeignKeys = function (tableOrName, foreignKeys) { return __awaiter(this, void 0, void 0, function () { var _this = this; var promises; return __generator(this, function (_a) { switch (_a.label) { case 0: promises = foreignKeys.map(function (foreignKey) { return _this.createForeignKey(tableOrName, foreignKey); }); return [4 /*yield*/, Promise.all(promises)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; /** * Drops a foreign key from the table. */ MysqlQueryRunner.prototype.dropForeignKey = function (tableOrPath, foreignKey) { return __awaiter(this, void 0, void 0, function () { var sql, columnNames, referencedColumnNames, revertSql; return __generator(this, function (_a) { sql = "ALTER TABLE `" + this.escapeTablePath(tableOrPath) + "` DROP FOREIGN KEY `" + foreignKey.name + "`"; columnNames = foreignKey.columnNames.map(function (column) { return "`" + column + "`"; }).join(", "); referencedColumnNames = foreignKey.referencedColumnNames.map(function (column) { return "`" + column + "`"; }).join(","); revertSql = "ALTER TABLE `" + this.escapeTablePath(tableOrPath) + "` ADD CONSTRAINT `" + foreignKey.name + "` " + ("FOREIGN KEY (" + columnNames + ") ") + ("REFERENCES `" + foreignKey.referencedTableName + "`(" + referencedColumnNames + ")"); if (foreignKey.onDelete) revertSql += " ON DELETE " + foreignKey.onDelete; return [2 /*return*/, this.schemaQuery(sql, revertSql)]; }); }); }; /** * Drops a foreign keys from the table. */ MysqlQueryRunner.prototype.dropForeignKeys = function (tableOrName, foreignKeys) { return __awaiter(this, void 0, void 0, function () { var _this = this; var promises; return __generator(this, function (_a) { switch (_a.label) { case 0: promises = foreignKeys.map(function (foreignKey) { return _this.dropForeignKey(tableOrName, foreignKey); }); return [4 /*yield*/, Promise.all(promises)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; /** * Creates a new index. */ MysqlQueryRunner.prototype.createIndex = function (table, index) { return __awaiter(this, void 0, void 0, function () { var columns, sql, revertSql; return __generator(this, function (_a) { switch (_a.label) { case 0: columns = index.columnNames.map(function (columnName) { return "`" + columnName + "`"; }).join(", "); sql = "CREATE " + (index.isUnique ? "UNIQUE " : "") + "INDEX `" + index.name + "` ON `" + this.escapeTablePath(table) + "`(" + columns + ")"; revertSql = "ALTER TABLE `" + this.escapeTablePath(table) + "` DROP INDEX `" + index.name + "`"; return [4 /*yield*/, this.sc