fixed issue when sqllite database does not take in count foreign keys + fixed all tests for sqlite + moved logic of creation transaction during database drop to its method because its driver-specific (issue when sqlite needs to execute queries of disabling foreign key checks before transaction start)

This commit is contained in:
Umed Khudoiberdiev 2016-12-02 17:18:26 +05:00
parent ae511bbe9c
commit 92d37d39de
11 changed files with 108 additions and 51 deletions

View File

@ -201,17 +201,7 @@ export class Connection {
*/
async dropDatabase(): Promise<void> {
const queryRunner = await this.driver.createQueryRunner();
await queryRunner.beginTransaction();
try {
await queryRunner.clearDatabase();
await queryRunner.commitTransaction();
await queryRunner.release();
} catch (error) {
await queryRunner.rollbackTransaction();
await queryRunner.release();
throw error;
}
await queryRunner.clearDatabase();
}
/**

View File

@ -64,14 +64,26 @@ export class MysqlQueryRunner implements QueryRunner {
if (this.isReleased)
throw new QueryRunnerAlreadyReleasedError();
const disableForeignKeysCheckQuery = `SET FOREIGN_KEY_CHECKS = 0;`;
const dropTablesQuery = `SELECT concat('DROP TABLE IF EXISTS ', table_name, ';') AS query FROM information_schema.tables WHERE table_schema = '${this.dbName}'`;
const enableForeignKeysCheckQuery = `SET FOREIGN_KEY_CHECKS = 1;`;
await this.beginTransaction();
try {
const disableForeignKeysCheckQuery = `SET FOREIGN_KEY_CHECKS = 0;`;
const dropTablesQuery = `SELECT concat('DROP TABLE IF EXISTS ', table_name, ';') AS query FROM information_schema.tables WHERE table_schema = '${this.dbName}'`;
const enableForeignKeysCheckQuery = `SET FOREIGN_KEY_CHECKS = 1;`;
await this.query(disableForeignKeysCheckQuery);
const dropQueries: ObjectLiteral[] = await this.query(dropTablesQuery);
await Promise.all(dropQueries.map(query => this.query(query["query"])));
await this.query(enableForeignKeysCheckQuery);
await this.query(disableForeignKeysCheckQuery);
const dropQueries: ObjectLiteral[] = await this.query(dropTablesQuery);
await Promise.all(dropQueries.map(query => this.query(query["query"])));
await this.query(enableForeignKeysCheckQuery);
await this.commitTransaction();
} catch (error) {
await this.rollbackTransaction();
throw error;
} finally {
await this.release();
}
}
/**

View File

@ -64,14 +64,27 @@ export class OracleQueryRunner implements QueryRunner {
if (this.isReleased)
throw new QueryRunnerAlreadyReleasedError();
const disableForeignKeysCheckQuery = `SET FOREIGN_KEY_CHECKS = 0;`;
const dropTablesQuery = `SELECT concat('DROP TABLE IF EXISTS ', table_name, ';') AS query FROM information_schema.tables WHERE table_schema = '${this.dbName}'`;
const enableForeignKeysCheckQuery = `SET FOREIGN_KEY_CHECKS = 1;`;
await this.beginTransaction();
try {
const disableForeignKeysCheckQuery = `SET FOREIGN_KEY_CHECKS = 0;`;
const dropTablesQuery = `SELECT concat('DROP TABLE IF EXISTS ', table_name, ';') AS query FROM information_schema.tables WHERE table_schema = '${this.dbName}'`;
const enableForeignKeysCheckQuery = `SET FOREIGN_KEY_CHECKS = 1;`;
await this.query(disableForeignKeysCheckQuery);
const dropQueries: ObjectLiteral[] = await this.query(dropTablesQuery);
await Promise.all(dropQueries.map(query => this.query(query["query"])));
await this.query(enableForeignKeysCheckQuery);
await this.commitTransaction();
} catch (error) {
await this.rollbackTransaction();
throw error;
} finally {
await this.release();
}
await this.query(disableForeignKeysCheckQuery);
const dropQueries: ObjectLiteral[] = await this.query(dropTablesQuery);
await Promise.all(dropQueries.map(query => this.query(query["query"])));
await this.query(enableForeignKeysCheckQuery);
}
/**

View File

@ -63,9 +63,21 @@ export class PostgresQueryRunner implements QueryRunner {
if (this.isReleased)
throw new QueryRunnerAlreadyReleasedError();
const selectDropsQuery = `SELECT 'DROP TABLE IF EXISTS "' || tablename || '" CASCADE;' as query FROM pg_tables WHERE schemaname = 'public'`;
const dropQueries: ObjectLiteral[] = await this.query(selectDropsQuery);
await Promise.all(dropQueries.map(q => this.query(q["query"])));
await this.beginTransaction();
try {
const selectDropsQuery = `SELECT 'DROP TABLE IF EXISTS "' || tablename || '" CASCADE;' as query FROM pg_tables WHERE schemaname = 'public'`;
const dropQueries: ObjectLiteral[] = await this.query(selectDropsQuery);
await Promise.all(dropQueries.map(q => this.query(q["query"])));
await this.commitTransaction();
} catch (error) {
await this.rollbackTransaction();
throw error;
} finally {
await this.release();
}
}
/**

View File

@ -86,8 +86,9 @@ export class SqliteDriver implements Driver {
// we need to enable foreign keys in sqlite to make sure all foreign key related features
// working properly. this also makes onDelete to work with sqlite.
connection.run(`PRAGMA foreign_keys = ON`);
ok();
connection.run(`PRAGMA foreign_keys = ON;`, (err: any, result: any) => {
ok();
});
});
});
}

View File

@ -66,9 +66,22 @@ export class SqliteQueryRunner implements QueryRunner {
if (this.isReleased)
throw new QueryRunnerAlreadyReleasedError();
const selectDropsQuery = `select 'drop table ' || name || ';' as query from sqlite_master where type = 'table' and name != 'sqlite_sequence'`;
const dropQueries: ObjectLiteral[] = await this.query(selectDropsQuery);
await Promise.all(dropQueries.map(q => this.query(q["query"])));
await this.query(`PRAGMA foreign_keys = OFF;`);
await this.beginTransaction();
try {
const selectDropsQuery = `select 'drop table ' || name || ';' as query from sqlite_master where type = 'table' and name != 'sqlite_sequence'`;
const dropQueries: ObjectLiteral[] = await this.query(selectDropsQuery);
await Promise.all(dropQueries.map(q => this.query(q["query"])));
await this.commitTransaction();
} catch (error) {
await this.rollbackTransaction();
throw error;
} finally {
await this.release();
await this.query(`PRAGMA foreign_keys = ON;`);
}
}
/**

View File

@ -64,20 +64,32 @@ export class SqlServerQueryRunner implements QueryRunner {
if (this.isReleased)
throw new QueryRunnerAlreadyReleasedError();
const allTablesSql = `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'`;
const allTablesResults: ObjectLiteral[] = await this.query(allTablesSql);
const tableNames = allTablesResults.map(result => result["TABLE_NAME"]);
await Promise.all(tableNames.map(async tableName => {
const dropForeignKeySql = `SELECT 'ALTER TABLE ' + OBJECT_SCHEMA_NAME(parent_object_id) + '.[' + OBJECT_NAME(parent_object_id) + '] DROP CONSTRAINT ' + name as query FROM sys.foreign_keys WHERE referenced_object_id = object_id('${tableName}')`;
const dropFkQueries: ObjectLiteral[] = await this.query(dropForeignKeySql);
return Promise.all(dropFkQueries.map(result => result["query"]).map(dropQuery => {
return this.query(dropQuery);
await this.beginTransaction();
try {
const allTablesSql = `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'`;
const allTablesResults: ObjectLiteral[] = await this.query(allTablesSql);
const tableNames = allTablesResults.map(result => result["TABLE_NAME"]);
await Promise.all(tableNames.map(async tableName => {
const dropForeignKeySql = `SELECT 'ALTER TABLE ' + OBJECT_SCHEMA_NAME(parent_object_id) + '.[' + OBJECT_NAME(parent_object_id) + '] DROP CONSTRAINT ' + name as query FROM sys.foreign_keys WHERE referenced_object_id = object_id('${tableName}')`;
const dropFkQueries: ObjectLiteral[] = await this.query(dropForeignKeySql);
return Promise.all(dropFkQueries.map(result => result["query"]).map(dropQuery => {
return this.query(dropQuery);
}));
}));
}));
await Promise.all(tableNames.map(tableName => {
const dropTableSql = `DROP TABLE "${tableName}"`;
return this.query(dropTableSql);
}));
await Promise.all(tableNames.map(tableName => {
const dropTableSql = `DROP TABLE "${tableName}"`;
return this.query(dropTableSql);
}));
await this.commitTransaction();
} catch (error) {
await this.rollbackTransaction();
throw error;
} finally {
await this.release();
}
// const selectDropsQuery = `SELECT 'DROP TABLE "' + TABLE_NAME + '"' as query FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE';`;
// const dropQueries: ObjectLiteral[] = await this.query(selectDropsQuery);

View File

@ -10,7 +10,11 @@ describe("QueryBuilder > relation-count", () => {
// const resourceDir = __dirname + "/../../../../../../test/functional/query-builder/join-relation-ids/";
let connections: Connection[];
before(() => setupTestingConnections({ entities: [Post, Category, Tag], schemaCreate: true }).then(all => connections = all));
before(() => setupTestingConnections({
entities: [Post, Category, Tag],
schemaCreate: true,
dropSchemaOnConnection: true
}).then(all => connections = all));
beforeEach(() => reloadDatabases(connections));
after(() => closeConnections(connections));

View File

@ -16,7 +16,7 @@ describe("QueryBuilder > relation-id", () => {
// todo: also make sure all new qb features to work with FindOptions
let connections: Connection[];
before(() => setupTestingConnections({ entities: [Post, Category, Tag], schemaCreate: true }).then(all => connections = all));
before(() => setupTestingConnections({ entities: [Post, Category, Tag], schemaCreate: true, dropSchemaOnConnection: true }).then(all => connections = all));
beforeEach(() => reloadDatabases(connections));
after(() => closeConnections(connections));

View File

@ -34,8 +34,8 @@ describe("insertion", function() {
savedPost.should.be.equal(newPost);
expect(savedPost.id).not.to.be.empty;
const insertedPost = (await postRepository.findOneById(savedPost.id))!;
insertedPost.should.be.eql({
const insertedPost = await postRepository.findOneById(savedPost.id);
insertedPost!.should.be.eql({
id: savedPost.id,
text: "Hello post",
title: "this is post title",

View File

@ -219,7 +219,7 @@ export async function setupTestingConnections(options?: TestingConnectionOptions
const mysql = true; // !options || !options.skipMysql;
const mariadb = false; // !options || !options.skipMariadb;
const postgres = false; // !options || !options.skipPostgres;
const sqlite = false; // !options || !options.skipSqlite;
const sqlite = true; // !options || !options.skipSqlite;
const mssql = false; // !options || !options.skipSqlserver;
const allParameters: ConnectionOptions[] = [];