mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
fixed mssql driver, updated to 4 version of mssql
This commit is contained in:
parent
d59458b513
commit
d02f74ae8b
@ -48,6 +48,7 @@ More env variable names you can find in `ConnectionOptionsEnvReader` class.
|
||||
* `setLimit` and `setOffset` in `QueryBuilder` were renamed into `limit` and `offset`
|
||||
* `nativeInterface` has been removed from a driver interface and implementations.
|
||||
Now
|
||||
* now typeorm works with the latest version of mssql (version 4)
|
||||
|
||||
### DEPRECATIONS
|
||||
|
||||
@ -69,6 +70,7 @@ Now
|
||||
* moved `query`, `transaction` and `createQueryBuilder` to the `Connection`.
|
||||
`EntityManager` now simply use them from the connection.
|
||||
* refactored how query runner works, removed query runner provider
|
||||
* fixed some issues with sqlite, sqlite now strongly works on a single connection
|
||||
|
||||
### BUG FIXES
|
||||
|
||||
|
||||
@ -60,7 +60,7 @@
|
||||
"gulpclass": "^0.1.2",
|
||||
"mocha": "^2.5.3",
|
||||
"mongodb": "^2.2.26",
|
||||
"mssql": "^3.3.0",
|
||||
"mssql": "^4.0.4",
|
||||
"mysql": "^2.12.0",
|
||||
"mysql2": "^1.2.0",
|
||||
"pg": "^6.1.5",
|
||||
|
||||
@ -208,6 +208,7 @@ export class Connection {
|
||||
async dropDatabase(): Promise<void> {
|
||||
const queryRunner = await this.driver.createQueryRunner();
|
||||
await queryRunner.clearDatabase();
|
||||
await queryRunner.release();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -113,9 +113,6 @@ export class MysqlQueryRunner implements QueryRunner {
|
||||
} catch (error) {
|
||||
await this.rollbackTransaction();
|
||||
throw error;
|
||||
|
||||
} finally {
|
||||
await this.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -121,9 +121,6 @@ export class OracleQueryRunner implements QueryRunner {
|
||||
} catch (error) {
|
||||
await this.rollbackTransaction();
|
||||
throw error;
|
||||
|
||||
} finally {
|
||||
await this.release();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -127,9 +127,6 @@ export class PostgresQueryRunner implements QueryRunner {
|
||||
} catch (error) {
|
||||
await this.rollbackTransaction();
|
||||
throw error;
|
||||
|
||||
} finally {
|
||||
await this.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ import {RdbmsSchemaBuilder} from "../../schema-builder/RdbmsSchemaBuilder";
|
||||
import {SqliteConnectionOptions} from "./SqliteConnectionOptions";
|
||||
import {MappedColumnTypes} from "../types/MappedColumnTypes";
|
||||
import {ColumnType} from "../types/ColumnTypes";
|
||||
import {QueryRunner} from "../../query-runner/QueryRunner";
|
||||
|
||||
/**
|
||||
* Organizes communication with sqlite DBMS.
|
||||
@ -36,6 +37,16 @@ export class SqliteDriver implements Driver {
|
||||
*/
|
||||
sqlite: any;
|
||||
|
||||
/**
|
||||
* Sqlite has a single QueryRunner because it works on a single database connection.
|
||||
*/
|
||||
queryRunner?: QueryRunner;
|
||||
|
||||
/**
|
||||
* Real database connection with sqlite database.
|
||||
*/
|
||||
databaseConnection: any;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public Implemented Properties
|
||||
// -------------------------------------------------------------------------
|
||||
@ -114,22 +125,18 @@ export class SqliteDriver implements Driver {
|
||||
/**
|
||||
* Performs connection to the database.
|
||||
*/
|
||||
connect(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
async connect(): Promise<void> {
|
||||
this.databaseConnection = await this.createDatabaseConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes connection with database.
|
||||
*/
|
||||
disconnect(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
// todo: what to do with this function?
|
||||
// return new Promise<void>((ok, fail) => {
|
||||
// const handler = (err: any) => err ? fail(err) : ok();
|
||||
// if (!this.databaseConnection)
|
||||
// return fail(new ConnectionIsNotSetError("sqlite"));
|
||||
// this.databaseConnection.connection.close(handler);
|
||||
// });
|
||||
async disconnect(): Promise<void> {
|
||||
return new Promise<void>((ok, fail) => {
|
||||
this.queryRunner = undefined;
|
||||
this.databaseConnection.close((err: any) => err ? fail(err) : ok());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -143,7 +150,10 @@ export class SqliteDriver implements Driver {
|
||||
* Creates a query runner used to execute database queries.
|
||||
*/
|
||||
createQueryRunner() {
|
||||
return new SqliteQueryRunner(this);
|
||||
if (!this.queryRunner)
|
||||
this.queryRunner = new SqliteQueryRunner(this);
|
||||
|
||||
return this.queryRunner;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -300,6 +310,24 @@ export class SqliteDriver implements Driver {
|
||||
// Protected Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Creates connection with the database.
|
||||
*/
|
||||
protected createDatabaseConnection() {
|
||||
return new Promise<void>((ok, fail) => {
|
||||
const databaseConnection = new this.sqlite.Database(this.options.database, (err: any) => {
|
||||
if (err) return fail(err);
|
||||
|
||||
// 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.
|
||||
databaseConnection.run(`PRAGMA foreign_keys = ON;`, (err: any, result: any) => {
|
||||
if (err) return fail(err);
|
||||
ok(databaseConnection);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* If driver dependency is not given explicitly, then try to load it via "require".
|
||||
*/
|
||||
@ -307,7 +335,7 @@ export class SqliteDriver implements Driver {
|
||||
try {
|
||||
this.sqlite = PlatformTools.load("sqlite3").verbose();
|
||||
|
||||
} catch (e) { // todo: better error for browser env
|
||||
} catch (e) {
|
||||
throw new DriverPackageNotInstalledError("SQLite", "sqlite3");
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,44 +65,15 @@ export class SqliteQueryRunner implements QueryRunner {
|
||||
* Returns obtained database connection.
|
||||
*/
|
||||
connect(): Promise<any> {
|
||||
if (this.databaseConnection)
|
||||
return Promise.resolve(this.databaseConnection);
|
||||
|
||||
if (this.databaseConnectionPromise)
|
||||
return this.databaseConnectionPromise;
|
||||
|
||||
this.databaseConnectionPromise = new Promise<void>((ok, fail) => {
|
||||
this.databaseConnection = new this.driver.sqlite.Database(this.driver.options.database, (err: any) => {
|
||||
if (err) {
|
||||
this.databaseConnection = null;
|
||||
return fail(err);
|
||||
}
|
||||
|
||||
// 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.
|
||||
this.databaseConnection.run(`PRAGMA foreign_keys = ON;`, (err: any, result: any) => {
|
||||
if (err)
|
||||
return fail(err);
|
||||
|
||||
ok(this.databaseConnection);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return this.databaseConnectionPromise;
|
||||
return Promise.resolve(this.driver.databaseConnection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases used database connection.
|
||||
* You cannot use query runner methods once its released.
|
||||
* We don't do anything here because sqlite do not support multiple connections thus query runners.
|
||||
*/
|
||||
release(): Promise<void> {
|
||||
return new Promise<void>((ok, fail) => {
|
||||
const handler = (err: any) => err ? fail(err) : ok();
|
||||
if (this.databaseConnection)
|
||||
this.databaseConnection.close(handler);
|
||||
this.isReleased = true;
|
||||
});
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -126,7 +97,6 @@ export class SqliteQueryRunner implements QueryRunner {
|
||||
|
||||
} finally {
|
||||
await this.query(`PRAGMA foreign_keys = ON;`);
|
||||
await this.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -149,7 +149,7 @@ export class SqlServerDriver implements Driver {
|
||||
// pooling is enabled either when its set explicitly to true,
|
||||
// either when its not defined at all (e.g. enabled by default)
|
||||
return new Promise<void>((ok, fail) => {
|
||||
const connection = new this.mssql.Connection(options).connect((err: any) => {
|
||||
const connection = new this.mssql.ConnectionPool(options).connect((err: any) => {
|
||||
if (err) return fail(err);
|
||||
this.connectionPool = connection;
|
||||
ok();
|
||||
|
||||
@ -41,14 +41,13 @@ export class SqlServerQueryRunner implements QueryRunner {
|
||||
protected databaseConnection: any;
|
||||
|
||||
/**
|
||||
* Transaction instance opened for this query executor.
|
||||
* 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
|
||||
*/
|
||||
protected transaction: any;
|
||||
|
||||
/**
|
||||
* Special callback provided by a driver used to release a created connection.
|
||||
*/
|
||||
protected databaseConnectionPromise: Promise<any>;
|
||||
protected queryResponsibilityChain: Promise<any>[] = [];
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Constructor
|
||||
@ -66,19 +65,7 @@ export class SqlServerQueryRunner implements QueryRunner {
|
||||
* Returns obtained database connection.
|
||||
*/
|
||||
connect(): Promise<any> {
|
||||
if (this.databaseConnection)
|
||||
return Promise.resolve(this.databaseConnection);
|
||||
|
||||
if (this.databaseConnectionPromise)
|
||||
return this.databaseConnectionPromise;
|
||||
|
||||
this.databaseConnectionPromise = new Promise((ok, fail) => {
|
||||
const driver = this.driver as SqlServerDriver;
|
||||
this.databaseConnection = driver.connectionPool; // todo: fix it
|
||||
ok(this.databaseConnection);
|
||||
});
|
||||
|
||||
return this.databaseConnectionPromise;
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -87,7 +74,6 @@ export class SqlServerQueryRunner implements QueryRunner {
|
||||
*/
|
||||
release(): Promise<void> {
|
||||
this.isReleased = true;
|
||||
// todo
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
@ -120,36 +106,7 @@ export class SqlServerQueryRunner implements QueryRunner {
|
||||
} 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);
|
||||
// const allQueries = [`EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"`]
|
||||
// .concat(dropQueries.map(q => this.query(q["query"])).join("; "));
|
||||
//
|
||||
// return new Promise<void>((ok, fail) => {
|
||||
//
|
||||
// const request = new this.driver.mssql.Request(this.isTransactionActive() ? this.databaseConnection.transaction : this.databaseConnection.connection);
|
||||
// request.multiple = true;
|
||||
// request.query(allQueries, (err: any, result: any) => {
|
||||
// if (err) {
|
||||
// this.connection.logger.logFailedQuery(allQueries);
|
||||
// this.connection.logger.logQueryError(err);
|
||||
// return fail(err);
|
||||
// }
|
||||
//
|
||||
// ok();
|
||||
// });
|
||||
// });
|
||||
|
||||
// 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);
|
||||
// await this.query(`EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"`);
|
||||
// await Promise.all(dropQueries.map(q => this.query(q["query"])));
|
||||
// await this.query(`EXEC sp_msforeachtable 'drop table [?]'`);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -164,9 +121,8 @@ export class SqlServerQueryRunner implements QueryRunner {
|
||||
|
||||
return new Promise<void>(async (ok, fail) => {
|
||||
this.isTransactionActive = true;
|
||||
const dbConnection = await this.connect();
|
||||
this.transaction = dbConnection.transaction();
|
||||
this.transaction.begin((err: any) => {
|
||||
this.databaseConnection = this.driver.connectionPool.transaction();
|
||||
this.databaseConnection.begin((err: any) => {
|
||||
if (err) {
|
||||
this.isTransactionActive = false;
|
||||
return fail(err);
|
||||
@ -188,9 +144,10 @@ export class SqlServerQueryRunner implements QueryRunner {
|
||||
throw new TransactionNotStartedError();
|
||||
|
||||
return new Promise<void>((ok, fail) => {
|
||||
this.transaction.commit((err: any) => {
|
||||
this.databaseConnection.commit((err: any) => {
|
||||
if (err) return fail(err);
|
||||
this.isTransactionActive = false;
|
||||
this.databaseConnection = null;
|
||||
ok();
|
||||
});
|
||||
});
|
||||
@ -208,9 +165,10 @@ export class SqlServerQueryRunner implements QueryRunner {
|
||||
throw new TransactionNotStartedError();
|
||||
|
||||
return new Promise<void>((ok, fail) => {
|
||||
this.transaction.rollback((err: any) => {
|
||||
this.databaseConnection.rollback((err: any) => {
|
||||
if (err) return fail(err);
|
||||
this.isTransactionActive = false;
|
||||
this.databaseConnection = null;
|
||||
ok();
|
||||
});
|
||||
});
|
||||
@ -219,31 +177,54 @@ export class SqlServerQueryRunner implements QueryRunner {
|
||||
/**
|
||||
* Executes a given SQL query.
|
||||
*/
|
||||
query(query: string, parameters?: any[]): Promise<any> {
|
||||
async query(query: string, parameters?: any[]): Promise<any> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
return new Promise(async (ok, fail) => {
|
||||
let waitingOkay: Function;
|
||||
const waitingPromise = new Promise((ok) => waitingOkay = ok);
|
||||
if (this.queryResponsibilityChain.length) {
|
||||
const otherWaitingPromises = [...this.queryResponsibilityChain];
|
||||
this.queryResponsibilityChain.push(waitingPromise);
|
||||
await Promise.all(otherWaitingPromises);
|
||||
}
|
||||
|
||||
const promise = new Promise(async (ok, fail) => {
|
||||
|
||||
this.driver.connection.logger.logQuery(query, parameters);
|
||||
const mssql = this.driver.mssql;
|
||||
const dbConnection = await this.connect();
|
||||
const request = new mssql.Request(this.isTransactionActive ? this.transaction : dbConnection);
|
||||
const request = new this.driver.mssql.Request(this.isTransactionActive ? this.databaseConnection : this.driver.connectionPool);
|
||||
if (parameters && parameters.length) {
|
||||
parameters.forEach((parameter, index) => {
|
||||
request.input(index, parameters![index]);
|
||||
});
|
||||
}
|
||||
request.query(query, (err: any, result: any) => {
|
||||
|
||||
const resolveChain = () => {
|
||||
if (promiseIndex !== -1)
|
||||
this.queryResponsibilityChain.splice(promiseIndex, 1);
|
||||
if (waitingPromiseIndex !== -1)
|
||||
this.queryResponsibilityChain.splice(waitingPromiseIndex, 1);
|
||||
waitingOkay();
|
||||
};
|
||||
|
||||
let promiseIndex = this.queryResponsibilityChain.indexOf(promise);
|
||||
let waitingPromiseIndex = this.queryResponsibilityChain.indexOf(waitingPromise);
|
||||
if (err) {
|
||||
this.driver.connection.logger.logFailedQuery(query, parameters);
|
||||
this.driver.connection.logger.logQueryError(err);
|
||||
resolveChain();
|
||||
return fail(err);
|
||||
}
|
||||
|
||||
ok(result);
|
||||
ok(result.recordset);
|
||||
resolveChain();
|
||||
});
|
||||
});
|
||||
if (this.isTransactionActive)
|
||||
this.queryResponsibilityChain.push(promise);
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -117,8 +117,6 @@ export class WebsqlQueryRunner implements QueryRunner {
|
||||
await this.rollbackTransaction();
|
||||
throw error;
|
||||
|
||||
} finally {
|
||||
await this.release();
|
||||
// await this.query(`PRAGMA foreign_keys = ON;`);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user