mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
added extra methods to query runner and implemented them in mysql driver
This commit is contained in:
parent
45a4cff5c8
commit
c55094810d
@ -14,6 +14,7 @@ import {PrimaryKeySchema} from "../../schema-builder/schema/PrimaryKeySchema";
|
||||
import {IndexSchema} from "../../schema-builder/schema/IndexSchema";
|
||||
import {QueryRunnerAlreadyReleasedError} from "../../query-runner/error/QueryRunnerAlreadyReleasedError";
|
||||
import {NamingStrategyInterface} from "../../naming-strategy/NamingStrategyInterface";
|
||||
import {toASCII} from "punycode";
|
||||
|
||||
/**
|
||||
* Runs queries on a single mysql database connection.
|
||||
@ -59,6 +60,8 @@ export class MysqlQueryRunner implements QueryRunner {
|
||||
|
||||
/**
|
||||
* Removes all tables from the currently connected database.
|
||||
* Be careful with using this method and avoid using it in production or migrations
|
||||
* (because it can clear all your database).
|
||||
*/
|
||||
async clearDatabase(): Promise<void> {
|
||||
if (this.isReleased)
|
||||
@ -234,10 +237,18 @@ export class MysqlQueryRunner implements QueryRunner {
|
||||
return results && results[0] && results[0]["level"] ? parseInt(results[0]["level"]) + 1 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads given table's data from the database.
|
||||
*/
|
||||
async loadTableSchema(tableName: string, namingStrategy: NamingStrategyInterface): Promise<TableSchema|undefined> {
|
||||
const tableSchemas = await this.loadTableSchemas([tableName], namingStrategy);
|
||||
return tableSchemas.length > 0 ? tableSchemas[0] : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all tables (with given names) from the database and creates a TableSchema from them.
|
||||
*/
|
||||
async loadSchemaTables(tableNames: string[], namingStrategy: NamingStrategyInterface): Promise<TableSchema[]> {
|
||||
async loadTableSchemas(tableNames: string[], namingStrategy: NamingStrategyInterface): Promise<TableSchema[]> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
@ -323,7 +334,16 @@ export class MysqlQueryRunner implements QueryRunner {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new table from the given table metadata and column metadatas.
|
||||
* Checks if table with the given name exist in the database.
|
||||
*/
|
||||
async hasTable(table: TableSchema): Promise<boolean> {
|
||||
const sql = `SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '${this.dbName}' AND TABLE_NAME = '${table.name}'`;
|
||||
const result = await this.query(sql);
|
||||
return result.length ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new table from the given table schema and column schemas inside it.
|
||||
*/
|
||||
async createTable(table: TableSchema): Promise<void> {
|
||||
if (this.isReleased)
|
||||
@ -340,19 +360,49 @@ export class MysqlQueryRunner implements QueryRunner {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new column from the column metadata in the table.
|
||||
* Checks if column with the given name exist in the given table.
|
||||
*/
|
||||
async createColumns(tableSchema: TableSchema, columns: ColumnSchema[]): Promise<void> {
|
||||
async hasColumn(table: TableSchema, columnName: string): Promise<boolean> {
|
||||
const sql = `SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '${this.dbName}' AND TABLE_NAME = '${table.name}' AND COLUMN_NAME = '${columnName}'`;
|
||||
const result = await this.query(sql);
|
||||
return result.length ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new column from the column schema in the table.
|
||||
*/
|
||||
async addColumn(tableSchema: TableSchema, column: ColumnSchema): Promise<void> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
const queries = columns.map(column => {
|
||||
const sql = `ALTER TABLE \`${tableSchema.name}\` ADD ${this.buildCreateColumnSql(column, false)}`;
|
||||
return this.query(sql);
|
||||
});
|
||||
const sql = `ALTER TABLE \`${tableSchema.name}\` ADD ${this.buildCreateColumnSql(column, false)}`;
|
||||
return this.query(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new columns from the column schema in the table.
|
||||
*/
|
||||
async addColumns(tableSchema: TableSchema, columns: ColumnSchema[]): Promise<void> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
const queries = columns.map(column => this.addColumn(tableSchema, column));
|
||||
await Promise.all(queries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes a column in the table.
|
||||
*/
|
||||
async changeColumn(tableSchema: TableSchema, newColumn: ColumnSchema, oldColumn: ColumnSchema): Promise<void> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
if (newColumn.isUnique === false && oldColumn.isUnique === true)
|
||||
await this.query(`ALTER TABLE \`${tableSchema.name}\` DROP INDEX \`${oldColumn.name}\``);
|
||||
|
||||
return this.query(`ALTER TABLE \`${tableSchema.name}\` CHANGE \`${oldColumn.name}\` ${this.buildCreateColumnSql(newColumn, oldColumn.isPrimary)}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes a column in the table.
|
||||
*/
|
||||
@ -361,17 +411,19 @@ export class MysqlQueryRunner implements QueryRunner {
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
const updatePromises = changedColumns.map(async changedColumn => {
|
||||
const sql = `ALTER TABLE \`${tableSchema.name}\` CHANGE \`${changedColumn.oldColumn.name}\` ${this.buildCreateColumnSql(changedColumn.newColumn, changedColumn.oldColumn.isPrimary)}`; // todo: CHANGE OR MODIFY COLUMN ????
|
||||
|
||||
if (changedColumn.newColumn.isUnique === false && changedColumn.oldColumn.isUnique === true)
|
||||
await this.query(`ALTER TABLE \`${tableSchema.name}\` DROP INDEX \`${changedColumn.oldColumn.name}\``);
|
||||
|
||||
return this.query(sql);
|
||||
return this.changeColumn(tableSchema, changedColumn.newColumn, changedColumn.oldColumn);
|
||||
});
|
||||
|
||||
await Promise.all(updatePromises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops column in the table.
|
||||
*/
|
||||
async dropColumn(dbTable: TableSchema, column: ColumnSchema): Promise<void> {
|
||||
return this.query(`ALTER TABLE \`${dbTable.name}\` DROP \`${column.name}\``);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops the columns in the table.
|
||||
*/
|
||||
@ -379,10 +431,7 @@ export class MysqlQueryRunner implements QueryRunner {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
const dropPromises = columns.map(column => {
|
||||
return this.query(`ALTER TABLE \`${dbTable.name}\` DROP \`${column.name}\``);
|
||||
});
|
||||
|
||||
const dropPromises = columns.map(column => this.dropColumn(dbTable, column));
|
||||
await Promise.all(dropPromises);
|
||||
}
|
||||
|
||||
@ -401,6 +450,22 @@ export class MysqlQueryRunner implements QueryRunner {
|
||||
await this.query(`ALTER TABLE ${tableSchema.name} ADD PRIMARY KEY (${primaryColumnNames.join(", ")})`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new foreign key.
|
||||
*/
|
||||
async createForeignKey(dbTable: TableSchema, foreignKey: ForeignKeySchema): Promise<void> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
const columnNames = foreignKey.columnNames.map(column => "`" + column + "`").join(", ");
|
||||
const referencedColumnNames = foreignKey.referencedColumnNames.map(column => "`" + column + "`").join(",");
|
||||
let sql = `ALTER TABLE ${dbTable.name} ADD CONSTRAINT \`${foreignKey.name}\` ` +
|
||||
`FOREIGN KEY (${columnNames}) ` +
|
||||
`REFERENCES \`${foreignKey.referencedTableName}\`(${referencedColumnNames})`;
|
||||
if (foreignKey.onDelete) sql += " ON DELETE " + foreignKey.onDelete;
|
||||
return this.query(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new foreign keys.
|
||||
*/
|
||||
@ -408,19 +473,20 @@ export class MysqlQueryRunner implements QueryRunner {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
const promises = foreignKeys.map(foreignKey => {
|
||||
const columnNames = foreignKey.columnNames.map(column => "`" + column + "`").join(", ");
|
||||
const referencedColumnNames = foreignKey.referencedColumnNames.map(column => "`" + column + "`").join(",");
|
||||
let sql = `ALTER TABLE ${dbTable.name} ADD CONSTRAINT \`${foreignKey.name}\` ` +
|
||||
`FOREIGN KEY (${columnNames}) ` +
|
||||
`REFERENCES \`${foreignKey.referencedTableName}\`(${referencedColumnNames})`;
|
||||
if (foreignKey.onDelete) sql += " ON DELETE " + foreignKey.onDelete;
|
||||
return this.query(sql);
|
||||
});
|
||||
|
||||
const promises = foreignKeys.map(foreignKey => this.createForeignKey(dbTable, foreignKey));
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops a foreign key from the table.
|
||||
*/
|
||||
async dropForeignKey(tableSchema: TableSchema, foreignKey: ForeignKeySchema): Promise<void> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
return this.query(`ALTER TABLE \`${tableSchema.name}\` DROP FOREIGN KEY \`${foreignKey.name}\``);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops a foreign keys from the table.
|
||||
*/
|
||||
@ -428,11 +494,7 @@ export class MysqlQueryRunner implements QueryRunner {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
const promises = foreignKeys.map(foreignKey => {
|
||||
const sql = `ALTER TABLE \`${tableSchema.name}\` DROP FOREIGN KEY \`${foreignKey.name}\``;
|
||||
return this.query(sql);
|
||||
});
|
||||
|
||||
const promises = foreignKeys.map(foreignKey => this.dropForeignKey(tableSchema, foreignKey));
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,8 @@ import {PlatformTools} from "../../platform/PlatformTools";
|
||||
|
||||
/**
|
||||
* Organizes communication with Oracle DBMS.
|
||||
*
|
||||
* todo: this driver is not 100% finished yet, need to fix all issues that are left
|
||||
*/
|
||||
export class OracleDriver implements Driver {
|
||||
|
||||
|
||||
@ -17,6 +17,8 @@ import {NamingStrategyInterface} from "../../naming-strategy/NamingStrategyInter
|
||||
|
||||
/**
|
||||
* Runs queries on a single mysql database connection.
|
||||
*
|
||||
* todo: this driver is not 100% finished yet, need to fix all issues that are left
|
||||
*/
|
||||
export class OracleQueryRunner implements QueryRunner {
|
||||
|
||||
@ -253,7 +255,7 @@ export class OracleQueryRunner implements QueryRunner {
|
||||
/**
|
||||
* Loads all tables (with given names) from the database and creates a TableSchema from them.
|
||||
*/
|
||||
async loadSchemaTables(tableNames: string[], namingStrategy: NamingStrategyInterface): Promise<TableSchema[]> {
|
||||
async loadTableSchemas(tableNames: string[], namingStrategy: NamingStrategyInterface): Promise<TableSchema[]> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
@ -373,7 +375,7 @@ AND cons.constraint_name = cols.constraint_name AND cons.owner = cols.owner ORDE
|
||||
/**
|
||||
* Creates a new column from the column metadata in the table.
|
||||
*/
|
||||
async createColumns(tableSchema: TableSchema, columns: ColumnSchema[]): Promise<void> {
|
||||
async addColumns(tableSchema: TableSchema, columns: ColumnSchema[]): Promise<void> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
|
||||
@ -235,7 +235,7 @@ export class PostgresQueryRunner implements QueryRunner {
|
||||
/**
|
||||
* Loads all tables (with given names) from the database and creates a TableSchema from them.
|
||||
*/
|
||||
async loadSchemaTables(tableNames: string[], namingStrategy: NamingStrategyInterface): Promise<TableSchema[]> {
|
||||
async loadTableSchemas(tableNames: string[], namingStrategy: NamingStrategyInterface): Promise<TableSchema[]> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
@ -354,7 +354,7 @@ where constraint_type = 'PRIMARY KEY' and tc.table_catalog = '${this.dbName}'`;
|
||||
/**
|
||||
* Creates a new column from the column metadata in the table.
|
||||
*/
|
||||
async createColumns(tableSchema: TableSchema, columns: ColumnSchema[]): Promise<void> {
|
||||
async addColumns(tableSchema: TableSchema, columns: ColumnSchema[]): Promise<void> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
|
||||
@ -247,7 +247,7 @@ export class SqliteQueryRunner implements QueryRunner {
|
||||
/**
|
||||
* Loads all tables (with given names) from the database and creates a TableSchema from them.
|
||||
*/
|
||||
async loadSchemaTables(tableNames: string[], namingStrategy: NamingStrategyInterface): Promise<TableSchema[]> {
|
||||
async loadTableSchemas(tableNames: string[], namingStrategy: NamingStrategyInterface): Promise<TableSchema[]> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
@ -383,7 +383,7 @@ export class SqliteQueryRunner implements QueryRunner {
|
||||
/**
|
||||
* Creates a new column from the column metadata in the table.
|
||||
*/
|
||||
async createColumns(tableSchema: TableSchema, columns: ColumnSchema[]): Promise<void> { // todo: remove column metadata returning
|
||||
async addColumns(tableSchema: TableSchema, columns: ColumnSchema[]): Promise<void> { // todo: remove column metadata returning
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
|
||||
@ -300,7 +300,7 @@ export class SqlServerQueryRunner implements QueryRunner {
|
||||
/**
|
||||
* Loads all tables (with given names) from the database and creates a TableSchema from them.
|
||||
*/
|
||||
async loadSchemaTables(tableNames: string[], namingStrategy: NamingStrategyInterface): Promise<TableSchema[]> {
|
||||
async loadTableSchemas(tableNames: string[], namingStrategy: NamingStrategyInterface): Promise<TableSchema[]> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
@ -429,7 +429,7 @@ export class SqlServerQueryRunner implements QueryRunner {
|
||||
/**
|
||||
* Creates a new column from the column metadata in the table.
|
||||
*/
|
||||
async createColumns(tableSchema: TableSchema, columns: ColumnSchema[]): Promise<void> {
|
||||
async addColumns(tableSchema: TableSchema, columns: ColumnSchema[]): Promise<void> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
|
||||
@ -258,7 +258,7 @@ export class WebsqlQueryRunner implements QueryRunner {
|
||||
/**
|
||||
* Loads all tables (with given names) from the database and creates a TableSchema from them.
|
||||
*/
|
||||
async loadSchemaTables(tableNames: string[], namingStrategy: NamingStrategyInterface): Promise<TableSchema[]> {
|
||||
async loadTableSchemas(tableNames: string[], namingStrategy: NamingStrategyInterface): Promise<TableSchema[]> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
@ -394,7 +394,7 @@ export class WebsqlQueryRunner implements QueryRunner {
|
||||
/**
|
||||
* Creates a new column from the column metadata in the table.
|
||||
*/
|
||||
async createColumns(tableSchema: TableSchema, columns: ColumnSchema[]): Promise<void> { // todo: remove column metadata returning
|
||||
async addColumns(tableSchema: TableSchema, columns: ColumnSchema[]): Promise<void> { // todo: remove column metadata returning
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
|
||||
@ -19,6 +19,8 @@ export interface QueryRunner {
|
||||
|
||||
/**
|
||||
* Removes all tables from the currently connected database.
|
||||
* Be careful with using this method and avoid using it in production or migrations
|
||||
* (because it can clear all your database).
|
||||
*/
|
||||
clearDatabase(): Promise<void>;
|
||||
|
||||
@ -80,23 +82,55 @@ export interface QueryRunner {
|
||||
/**
|
||||
* Loads all tables (with given names) from the database and creates a TableSchema from them.
|
||||
*/
|
||||
loadSchemaTables(tableNames: string[], namingStrategy: NamingStrategyInterface): Promise<TableSchema[]>;
|
||||
loadTableSchema(tableName: string, namingStrategy: NamingStrategyInterface): Promise<TableSchema|undefined>;
|
||||
|
||||
/**
|
||||
* Loads all tables (with given names) from the database and creates a TableSchema from them.
|
||||
*/
|
||||
loadTableSchemas(tableNames: string[], namingStrategy: NamingStrategyInterface): Promise<TableSchema[]>;
|
||||
|
||||
/**
|
||||
* Checks if table with the given name exist in the database.
|
||||
*/
|
||||
hasTable(table: TableSchema): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Creates a new table from the given table metadata and column metadatas.
|
||||
*/
|
||||
createTable(table: TableSchema): Promise<void>;
|
||||
|
||||
/**
|
||||
* Checks if column with the given name exist in the given table.
|
||||
*/
|
||||
hasColumn(table: TableSchema, columnName: string): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Creates a new column in the table.
|
||||
*/
|
||||
addColumn(tableSchema: TableSchema, column: ColumnSchema): Promise<void>;
|
||||
|
||||
/**
|
||||
* Creates new columns in the table.
|
||||
*/
|
||||
createColumns(tableSchema: TableSchema, columns: ColumnSchema[]): Promise<void>;
|
||||
addColumns(tableSchema: TableSchema, columns: ColumnSchema[]): Promise<void>;
|
||||
|
||||
// todo: renameColumn ?
|
||||
|
||||
/**
|
||||
* Changes a column in the table.
|
||||
*/
|
||||
changeColumn(tableSchema: TableSchema, newColumn: ColumnSchema, oldColumn: ColumnSchema): Promise<void>;
|
||||
|
||||
/**
|
||||
* Changes a columns in the table.
|
||||
*/
|
||||
changeColumns(tableSchema: TableSchema, changedColumns: { newColumn: ColumnSchema, oldColumn: ColumnSchema }[]): Promise<void>;
|
||||
|
||||
/**
|
||||
* Drops the column in the table.
|
||||
*/
|
||||
dropColumn(dbTable: TableSchema, column: ColumnSchema): Promise<void>;
|
||||
|
||||
/**
|
||||
* Drops the columns in the table.
|
||||
*/
|
||||
@ -107,11 +141,21 @@ export interface QueryRunner {
|
||||
*/
|
||||
updatePrimaryKeys(dbTable: TableSchema): Promise<void>;
|
||||
|
||||
/**
|
||||
* Creates a new foreign key.
|
||||
*/
|
||||
createForeignKey(dbTable: TableSchema, foreignKey: ForeignKeySchema): Promise<void>;
|
||||
|
||||
/**
|
||||
* Creates a new foreign keys.
|
||||
*/
|
||||
createForeignKeys(dbTable: TableSchema, foreignKeys: ForeignKeySchema[]): Promise<void>;
|
||||
|
||||
/**
|
||||
* Drops a foreign keys from the table.
|
||||
*/
|
||||
dropForeignKey(tableSchema: TableSchema, foreignKey: ForeignKeySchema): Promise<void>;
|
||||
|
||||
/**
|
||||
* Drops a foreign keys from the table.
|
||||
*/
|
||||
|
||||
@ -104,7 +104,7 @@ export class SchemaBuilder {
|
||||
*/
|
||||
protected loadTableSchemas(): Promise<TableSchema[]> {
|
||||
const tableNames = this.entityToSyncMetadatas.map(metadata => metadata.table.name);
|
||||
return this.queryRunner.loadSchemaTables(tableNames, this.namingStrategy);
|
||||
return this.queryRunner.loadTableSchemas(tableNames, this.namingStrategy);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -214,7 +214,7 @@ export class SchemaBuilder {
|
||||
// create columns in the database
|
||||
const newColumnSchemas = this.metadataColumnsToColumnSchemas(newColumnMetadatas);
|
||||
tableSchema.addColumns(newColumnSchemas);
|
||||
await this.queryRunner.createColumns(tableSchema, newColumnSchemas);
|
||||
await this.queryRunner.addColumns(tableSchema, newColumnSchemas);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@ -354,7 +354,7 @@ describe("Connection", () => {
|
||||
it("database should be empty after schema sync", () => Promise.all(connections.map(async connection => {
|
||||
await connection.syncSchema(true);
|
||||
const queryRunner = await connection.driver.createQueryRunner();
|
||||
let schema = await queryRunner.loadSchemaTables(["view"], new DefaultNamingStrategy());
|
||||
let schema = await queryRunner.loadTableSchemas(["view"], new DefaultNamingStrategy());
|
||||
expect(schema.some(table => table.name === "view")).to.be.false;
|
||||
})));
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user