fix: beforeQuery promises not awaited before query execution (#11086)

* fix: beforeQuery promises not awaited before query execution

Closes: #11085

* fix: run format

Closes: #11085

* fix: apply same beforeQuery & afterQuery logic to all drivers

* fix: use a different broadcaster for BeforeQuery / AfterQuery

* fix: BeforeQuery / AfterQuery event types

* fix: move broadCasterResult.wait in finally block

* fix: remove duplicated broadcasterResult.wait in ReactNativeQueryRunner

* fix: fix prettier issue

* fix: implemented requested changes

* fix: broken sqlite tests

* Revert "fix: broken sqlite tests"

This reverts commit 4bacd5f4b55bb09297e9086decefe62f08ceead0.

* Revert "fix: implemented requested changes"

This reverts commit 1d2f59bf2bf8ec276f84bcd8b840ca5420c4088f.

* review: undefined type at the end

* fix: move database connection logic outside of the promise bloc

---------

Co-authored-by: Lucian Mocanu <alumni@users.noreply.github.com>
This commit is contained in:
TanguyPoly 2025-04-30 23:16:32 +02:00 committed by GitHub
parent 9464e6522a
commit b9842e3be9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 332 additions and 281 deletions

View File

@ -1,32 +1,32 @@
import { ObjectLiteral } from "../../common/ObjectLiteral"
import { TypeORMError } from "../../error"
import { QueryFailedError } from "../../error/QueryFailedError"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { TransactionNotStartedError } from "../../error/TransactionNotStartedError"
import { ReadStream } from "../../platform/PlatformTools"
import { BaseQueryRunner } from "../../query-runner/BaseQueryRunner"
import { QueryResult } from "../../query-runner/QueryResult"
import { QueryRunner } from "../../query-runner/QueryRunner"
import { ObjectLiteral } from "../../common/ObjectLiteral"
import { TransactionNotStartedError } from "../../error/TransactionNotStartedError"
import { TableColumn } from "../../schema-builder/table/TableColumn"
import { Table } from "../../schema-builder/table/Table"
import { TableIndex } from "../../schema-builder/table/TableIndex"
import { TableForeignKey } from "../../schema-builder/table/TableForeignKey"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { View } from "../../schema-builder/view/View"
import { Query } from "../Query"
import { CockroachDriver } from "./CockroachDriver"
import { ReadStream } from "../../platform/PlatformTools"
import { QueryFailedError } from "../../error/QueryFailedError"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { TableIndexOptions } from "../../schema-builder/options/TableIndexOptions"
import { TableUnique } from "../../schema-builder/table/TableUnique"
import { BaseQueryRunner } from "../../query-runner/BaseQueryRunner"
import { OrmUtils } from "../../util/OrmUtils"
import { Table } from "../../schema-builder/table/Table"
import { TableCheck } from "../../schema-builder/table/TableCheck"
import { TableColumn } from "../../schema-builder/table/TableColumn"
import { TableExclusion } from "../../schema-builder/table/TableExclusion"
import { TableForeignKey } from "../../schema-builder/table/TableForeignKey"
import { TableIndex } from "../../schema-builder/table/TableIndex"
import { TableUnique } from "../../schema-builder/table/TableUnique"
import { View } from "../../schema-builder/view/View"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
import { InstanceChecker } from "../../util/InstanceChecker"
import { OrmUtils } from "../../util/OrmUtils"
import { VersionUtils } from "../../util/VersionUtils"
import { Query } from "../Query"
import { ColumnType } from "../types/ColumnTypes"
import { IsolationLevel } from "../types/IsolationLevel"
import { TableExclusion } from "../../schema-builder/table/TableExclusion"
import { ReplicationMode } from "../types/ReplicationMode"
import { TypeORMError } from "../../error"
import { MetadataTableType } from "../types/MetadataTableType"
import { InstanceChecker } from "../../util/InstanceChecker"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
import { VersionUtils } from "../../util/VersionUtils"
import { ReplicationMode } from "../types/ReplicationMode"
import { CockroachDriver } from "./CockroachDriver"
/**
* Runs queries on a single postgres database connection.
@ -270,15 +270,11 @@ export class CockroachQueryRunner
if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
const databaseConnection = await this.connect()
const broadcasterResult = new BroadcasterResult()
this.driver.connection.logger.logQuery(query, parameters, this)
this.broadcaster.broadcastBeforeQueryEvent(
broadcasterResult,
query,
parameters,
)
await this.broadcaster.broadcast("BeforeQuery", query, parameters)
const broadcasterResult = new BroadcasterResult()
const queryStartTime = Date.now()
if (this.isTransactionActive && this.storeQueries) {

View File

@ -1,12 +1,12 @@
import { ObjectLiteral } from "../../common/ObjectLiteral"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { TypeORMError } from "../../error"
import { QueryFailedError } from "../../error/QueryFailedError"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { QueryResult } from "../../query-runner/QueryResult"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
import { AbstractSqliteQueryRunner } from "../sqlite-abstract/AbstractSqliteQueryRunner"
import { CordovaDriver } from "./CordovaDriver"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { TypeORMError } from "../../error"
import { QueryResult } from "../../query-runner/QueryResult"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
/**
* Runs queries on a single sqlite database connection.
@ -53,15 +53,11 @@ export class CordovaQueryRunner extends AbstractSqliteQueryRunner {
if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
const databaseConnection = await this.connect()
const broadcasterResult = new BroadcasterResult()
this.driver.connection.logger.logQuery(query, parameters, this)
this.broadcaster.broadcastBeforeQueryEvent(
broadcasterResult,
query,
parameters,
)
await this.broadcaster.broadcast("BeforeQuery", query, parameters)
const broadcasterResult = new BroadcasterResult()
const queryStartTime = Date.now()
try {

View File

@ -1,10 +1,10 @@
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { QueryFailedError } from "../../error/QueryFailedError"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { QueryResult } from "../../query-runner/QueryResult"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
import { AbstractSqliteQueryRunner } from "../sqlite-abstract/AbstractSqliteQueryRunner"
import { ExpoDriver } from "./ExpoDriver"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { QueryResult } from "../../query-runner/QueryResult"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
export class ExpoQueryRunner extends AbstractSqliteQueryRunner {
driver: ExpoDriver
@ -35,11 +35,7 @@ export class ExpoQueryRunner extends AbstractSqliteQueryRunner {
const broadcasterResult = new BroadcasterResult()
this.driver.connection.logger.logQuery(query, parameters, this)
this.broadcaster.broadcastBeforeQueryEvent(
broadcasterResult,
query,
parameters,
)
await this.broadcaster.broadcast("BeforeQuery", query, parameters)
const queryStartTime = Date.now()
@ -103,6 +99,7 @@ export class ExpoQueryRunner extends AbstractSqliteQueryRunner {
throw new QueryFailedError(query, parameters, err)
} finally {
await broadcasterResult.wait()
await statement.finalizeAsync()
}
}

View File

@ -1,32 +1,32 @@
import { ObjectLiteral } from "../../common/ObjectLiteral"
import { TypeORMError } from "../../error"
import { QueryFailedError } from "../../error/QueryFailedError"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { TransactionNotStartedError } from "../../error/TransactionNotStartedError"
import { ReadStream } from "../../platform/PlatformTools"
import { BaseQueryRunner } from "../../query-runner/BaseQueryRunner"
import { QueryResult } from "../../query-runner/QueryResult"
import { QueryRunner } from "../../query-runner/QueryRunner"
import { ObjectLiteral } from "../../common/ObjectLiteral"
import { TransactionNotStartedError } from "../../error/TransactionNotStartedError"
import { TableColumn } from "../../schema-builder/table/TableColumn"
import { TableIndexOptions } from "../../schema-builder/options/TableIndexOptions"
import { Table } from "../../schema-builder/table/Table"
import { TableCheck } from "../../schema-builder/table/TableCheck"
import { TableColumn } from "../../schema-builder/table/TableColumn"
import { TableExclusion } from "../../schema-builder/table/TableExclusion"
import { TableForeignKey } from "../../schema-builder/table/TableForeignKey"
import { TableIndex } from "../../schema-builder/table/TableIndex"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { View } from "../../schema-builder/view/View"
import { Query } from "../Query"
import { MysqlDriver } from "./MysqlDriver"
import { ReadStream } from "../../platform/PlatformTools"
import { OrmUtils } from "../../util/OrmUtils"
import { QueryFailedError } from "../../error/QueryFailedError"
import { TableIndexOptions } from "../../schema-builder/options/TableIndexOptions"
import { TableUnique } from "../../schema-builder/table/TableUnique"
import { BaseQueryRunner } from "../../query-runner/BaseQueryRunner"
import { View } from "../../schema-builder/view/View"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { ColumnType } from "../types/ColumnTypes"
import { TableCheck } from "../../schema-builder/table/TableCheck"
import { IsolationLevel } from "../types/IsolationLevel"
import { TableExclusion } from "../../schema-builder/table/TableExclusion"
import { VersionUtils } from "../../util/VersionUtils"
import { ReplicationMode } from "../types/ReplicationMode"
import { TypeORMError } from "../../error"
import { MetadataTableType } from "../types/MetadataTableType"
import { InstanceChecker } from "../../util/InstanceChecker"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
import { InstanceChecker } from "../../util/InstanceChecker"
import { OrmUtils } from "../../util/OrmUtils"
import { VersionUtils } from "../../util/VersionUtils"
import { Query } from "../Query"
import { ColumnType } from "../types/ColumnTypes"
import { IsolationLevel } from "../types/IsolationLevel"
import { MetadataTableType } from "../types/MetadataTableType"
import { ReplicationMode } from "../types/ReplicationMode"
import { MysqlDriver } from "./MysqlDriver"
/**
* Runs queries on a single mysql database connection.
@ -187,18 +187,16 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner {
): Promise<any> {
if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
const databaseConnection = await this.connect()
this.driver.connection.logger.logQuery(query, parameters, this)
await this.broadcaster.broadcast("BeforeQuery", query, parameters)
const broadcasterResult = new BroadcasterResult()
const queryStartTime = Date.now()
return new Promise(async (ok, fail) => {
const broadcasterResult = new BroadcasterResult()
try {
const databaseConnection = await this.connect()
this.driver.connection.logger.logQuery(query, parameters, this)
this.broadcaster.broadcastBeforeQueryEvent(
broadcasterResult,
query,
parameters,
)
const enableQueryTimeout =
this.driver.options.enableQueryTimeout
const maxQueryExecutionTime =
@ -207,7 +205,6 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner {
enableQueryTimeout && maxQueryExecutionTime
? { sql: query, timeout: maxQueryExecutionTime }
: query
const queryStartTime = Date.now()
databaseConnection.query(
queryPayload,
parameters,

View File

@ -1,10 +1,10 @@
import { ObjectLiteral } from "../../common/ObjectLiteral"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { QueryFailedError } from "../../error/QueryFailedError"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { QueryResult } from "../../query-runner/QueryResult"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { AbstractSqliteQueryRunner } from "../sqlite-abstract/AbstractSqliteQueryRunner"
import { NativescriptDriver } from "./NativescriptDriver"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { QueryResult } from "../../query-runner/QueryResult"
/**
* Runs queries on a single sqlite database connection.
@ -54,8 +54,9 @@ export class NativescriptQueryRunner extends AbstractSqliteQueryRunner {
const connection = this.driver.connection
const databaseConnection = await this.connect()
return new Promise(async (ok, fail) => {
const databaseConnection = await this.connect()
const isInsertQuery = query.substr(0, 11) === "INSERT INTO"
connection.logger.logQuery(query, parameters, this)

View File

@ -1,30 +1,30 @@
import { QueryRunner } from "../../query-runner/QueryRunner"
import { ObjectLiteral } from "../../common/ObjectLiteral"
import { TypeORMError } from "../../error"
import { QueryFailedError } from "../../error/QueryFailedError"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { TransactionNotStartedError } from "../../error/TransactionNotStartedError"
import { TableColumn } from "../../schema-builder/table/TableColumn"
import { ReadStream } from "../../platform/PlatformTools"
import { BaseQueryRunner } from "../../query-runner/BaseQueryRunner"
import { QueryResult } from "../../query-runner/QueryResult"
import { QueryRunner } from "../../query-runner/QueryRunner"
import { Table } from "../../schema-builder/table/Table"
import { TableCheck } from "../../schema-builder/table/TableCheck"
import { TableColumn } from "../../schema-builder/table/TableColumn"
import { TableExclusion } from "../../schema-builder/table/TableExclusion"
import { TableForeignKey } from "../../schema-builder/table/TableForeignKey"
import { TableIndex } from "../../schema-builder/table/TableIndex"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { View } from "../../schema-builder/view/View"
import { Query } from "../Query"
import { OracleDriver } from "./OracleDriver"
import { ReadStream } from "../../platform/PlatformTools"
import { QueryFailedError } from "../../error/QueryFailedError"
import { TableUnique } from "../../schema-builder/table/TableUnique"
import { View } from "../../schema-builder/view/View"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { BaseQueryRunner } from "../../query-runner/BaseQueryRunner"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
import { InstanceChecker } from "../../util/InstanceChecker"
import { OrmUtils } from "../../util/OrmUtils"
import { TableCheck } from "../../schema-builder/table/TableCheck"
import { Query } from "../Query"
import { ColumnType } from "../types/ColumnTypes"
import { IsolationLevel } from "../types/IsolationLevel"
import { TableExclusion } from "../../schema-builder/table/TableExclusion"
import { ReplicationMode } from "../types/ReplicationMode"
import { TypeORMError } from "../../error"
import { QueryResult } from "../../query-runner/QueryResult"
import { MetadataTableType } from "../types/MetadataTableType"
import { InstanceChecker } from "../../util/InstanceChecker"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
import { ReplicationMode } from "../types/ReplicationMode"
import { OracleDriver } from "./OracleDriver"
/**
* Runs queries on a single oracle database connection.
@ -198,15 +198,11 @@ export class OracleQueryRunner extends BaseQueryRunner implements QueryRunner {
if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
const databaseConnection = await this.connect()
const broadcasterResult = new BroadcasterResult()
this.driver.connection.logger.logQuery(query, parameters, this)
this.broadcaster.broadcastBeforeQueryEvent(
broadcasterResult,
query,
parameters,
)
await this.broadcaster.broadcast("BeforeQuery", query, parameters)
const broadcasterResult = new BroadcasterResult()
const queryStartTime = Date.now()
try {

View File

@ -243,14 +243,11 @@ export class PostgresQueryRunner
if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
const databaseConnection = await this.connect()
const broadcasterResult = new BroadcasterResult()
this.driver.connection.logger.logQuery(query, parameters, this)
this.broadcaster.broadcastBeforeQueryEvent(
broadcasterResult,
query,
parameters,
)
await this.broadcaster.broadcast("BeforeQuery", query, parameters)
const broadcasterResult = new BroadcasterResult()
try {
const queryStartTime = Date.now()

View File

@ -1,11 +1,11 @@
import { ObjectLiteral } from "../../common/ObjectLiteral"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { QueryFailedError } from "../../error/QueryFailedError"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { QueryResult } from "../../query-runner/QueryResult"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
import { AbstractSqliteQueryRunner } from "../sqlite-abstract/AbstractSqliteQueryRunner"
import { ReactNativeDriver } from "./ReactNativeDriver"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { QueryResult } from "../../query-runner/QueryResult"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
/**
* Runs queries on a single sqlite database connection.
@ -45,107 +45,109 @@ export class ReactNativeQueryRunner extends AbstractSqliteQueryRunner {
/**
* Executes a given SQL query.
*/
query(
async query(
query: string,
parameters?: any[],
useStructuredResult = false,
): Promise<any> {
if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
const databaseConnection = await this.connect()
this.driver.connection.logger.logQuery(query, parameters, this)
await this.broadcaster.broadcast("BeforeQuery", query, parameters)
const broadcasterResult = new BroadcasterResult()
const queryStartTime = Date.now()
return new Promise(async (ok, fail) => {
const databaseConnection = await this.connect()
const broadcasterResult = new BroadcasterResult()
this.driver.connection.logger.logQuery(query, parameters, this)
this.broadcaster.broadcastBeforeQueryEvent(
broadcasterResult,
query,
parameters,
)
const queryStartTime = Date.now()
databaseConnection.executeSql(
query,
parameters,
async (raw: any) => {
// log slow queries if maxQueryExecution time is set
const maxQueryExecutionTime =
this.driver.options.maxQueryExecutionTime
const queryEndTime = Date.now()
const queryExecutionTime = queryEndTime - queryStartTime
this.broadcaster.broadcastAfterQueryEvent(
broadcasterResult,
query,
parameters,
true,
queryExecutionTime,
raw,
undefined,
)
if (
maxQueryExecutionTime &&
queryExecutionTime > maxQueryExecutionTime
)
this.driver.connection.logger.logQuerySlow(
try {
databaseConnection.executeSql(
query,
parameters,
async (raw: any) => {
// log slow queries if maxQueryExecution time is set
const maxQueryExecutionTime =
this.driver.options.maxQueryExecutionTime
const queryEndTime = Date.now()
const queryExecutionTime = queryEndTime - queryStartTime
this.broadcaster.broadcastAfterQueryEvent(
broadcasterResult,
query,
parameters,
true,
queryExecutionTime,
raw,
undefined,
)
if (
maxQueryExecutionTime &&
queryExecutionTime > maxQueryExecutionTime
)
this.driver.connection.logger.logQuerySlow(
queryExecutionTime,
query,
parameters,
this,
)
if (broadcasterResult.promises.length > 0)
await Promise.all(broadcasterResult.promises)
const result = new QueryResult()
if (raw?.hasOwnProperty("rowsAffected")) {
result.affected = raw.rowsAffected
}
if (raw?.hasOwnProperty("rows")) {
const records = []
for (let i = 0; i < raw.rows.length; i++) {
records.push(raw.rows.item(i))
}
result.raw = records
result.records = records
}
// return id of inserted row, if query was insert statement.
if (query.substr(0, 11) === "INSERT INTO") {
result.raw = raw.insertId
}
if (useStructuredResult) {
ok(result)
} else {
ok(result.raw)
}
},
async (err: any) => {
this.driver.connection.logger.logQueryError(
err,
query,
parameters,
this,
)
this.broadcaster.broadcastAfterQueryEvent(
broadcasterResult,
query,
parameters,
false,
undefined,
undefined,
err,
)
if (broadcasterResult.promises.length > 0)
await Promise.all(broadcasterResult.promises)
const result = new QueryResult()
if (raw?.hasOwnProperty("rowsAffected")) {
result.affected = raw.rowsAffected
}
if (raw?.hasOwnProperty("rows")) {
const records = []
for (let i = 0; i < raw.rows.length; i++) {
records.push(raw.rows.item(i))
}
result.raw = records
result.records = records
}
// return id of inserted row, if query was insert statement.
if (query.substr(0, 11) === "INSERT INTO") {
result.raw = raw.insertId
}
if (useStructuredResult) {
ok(result)
} else {
ok(result.raw)
}
},
async (err: any) => {
this.driver.connection.logger.logQueryError(
err,
query,
parameters,
this,
)
this.broadcaster.broadcastAfterQueryEvent(
broadcasterResult,
query,
parameters,
false,
undefined,
undefined,
err,
)
await broadcasterResult.wait()
fail(new QueryFailedError(query, parameters, err))
},
)
fail(new QueryFailedError(query, parameters, err))
},
)
} catch (err) {
fail(err)
} finally {
await broadcasterResult.wait()
}
})
}

View File

@ -1,10 +1,13 @@
import { promisify } from "util"
import { ObjectLiteral } from "../../common/ObjectLiteral"
import { QueryFailedError, TypeORMError } from "../../error"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { TransactionAlreadyStartedError } from "../../error/TransactionAlreadyStartedError"
import { TransactionNotStartedError } from "../../error/TransactionNotStartedError"
import { ColumnType } from "../types/ColumnTypes"
import { ReadStream } from "../../platform/PlatformTools"
import { BaseQueryRunner } from "../../query-runner/BaseQueryRunner"
import { QueryLock } from "../../query-runner/QueryLock"
import { QueryResult } from "../../query-runner/QueryResult"
import { QueryRunner } from "../../query-runner/QueryRunner"
import { TableIndexOptions } from "../../schema-builder/options/TableIndexOptions"
import { Table } from "../../schema-builder/table/Table"
@ -16,18 +19,15 @@ import { TableIndex } from "../../schema-builder/table/TableIndex"
import { TableUnique } from "../../schema-builder/table/TableUnique"
import { View } from "../../schema-builder/view/View"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
import { InstanceChecker } from "../../util/InstanceChecker"
import { OrmUtils } from "../../util/OrmUtils"
import { Query } from "../Query"
import { ColumnType } from "../types/ColumnTypes"
import { IsolationLevel } from "../types/IsolationLevel"
import { SapDriver } from "./SapDriver"
import { ReplicationMode } from "../types/ReplicationMode"
import { QueryFailedError, TypeORMError } from "../../error"
import { QueryResult } from "../../query-runner/QueryResult"
import { QueryLock } from "../../query-runner/QueryLock"
import { MetadataTableType } from "../types/MetadataTableType"
import { InstanceChecker } from "../../util/InstanceChecker"
import { promisify } from "util"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
import { ReplicationMode } from "../types/ReplicationMode"
import { SapDriver } from "./SapDriver"
/**
* Runs queries on a single SQL Server database connection.
@ -193,20 +193,17 @@ export class SapQueryRunner extends BaseQueryRunner implements QueryRunner {
const release = await this.lock.acquire()
const databaseConnection = await this.connect()
let statement: any
const result = new QueryResult()
this.driver.connection.logger.logQuery(query, parameters, this)
await this.broadcaster.broadcast("BeforeQuery", query, parameters)
const broadcasterResult = new BroadcasterResult()
try {
const databaseConnection = await this.connect()
this.driver.connection.logger.logQuery(query, parameters, this)
this.broadcaster.broadcastBeforeQueryEvent(
broadcasterResult,
query,
parameters,
)
const queryStartTime = Date.now()
const isInsertQuery = query.substr(0, 11) === "INSERT INTO"

View File

@ -1,10 +1,11 @@
import { ObjectLiteral } from "../../common/ObjectLiteral"
import { TypeORMError } from "../../error"
import { QueryFailedError } from "../../error/QueryFailedError"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { TransactionNotStartedError } from "../../error/TransactionNotStartedError"
import { ColumnType } from "../types/ColumnTypes"
import { ReadStream } from "../../platform/PlatformTools"
import { BaseQueryRunner } from "../../query-runner/BaseQueryRunner"
import { QueryResult } from "../../query-runner/QueryResult"
import { QueryRunner } from "../../query-runner/QueryRunner"
import { TableIndexOptions } from "../../schema-builder/options/TableIndexOptions"
import { Table } from "../../schema-builder/table/Table"
@ -16,15 +17,14 @@ import { TableIndex } from "../../schema-builder/table/TableIndex"
import { TableUnique } from "../../schema-builder/table/TableUnique"
import { View } from "../../schema-builder/view/View"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
import { OrmUtils } from "../../util/OrmUtils"
import { Query } from "../Query"
import { ColumnType } from "../types/ColumnTypes"
import { IsolationLevel } from "../types/IsolationLevel"
import { ReplicationMode } from "../types/ReplicationMode"
import { TypeORMError } from "../../error"
import { QueryResult } from "../../query-runner/QueryResult"
import { MetadataTableType } from "../types/MetadataTableType"
import { ReplicationMode } from "../types/ReplicationMode"
import { SpannerDriver } from "./SpannerDriver"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
/**
* Runs queries on a single postgres database connection.
@ -156,11 +156,15 @@ export class SpannerQueryRunner extends BaseQueryRunner implements QueryRunner {
): Promise<any> {
if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
await this.connect()
this.driver.connection.logger.logQuery(query, parameters, this)
await this.broadcaster.broadcast("BeforeQuery", query, parameters)
const broadcasterResult = new BroadcasterResult()
try {
const queryStartTime = Date.now()
await this.connect()
let rawResult:
| [
any[],
@ -184,13 +188,6 @@ export class SpannerQueryRunner extends BaseQueryRunner implements QueryRunner {
}
try {
this.driver.connection.logger.logQuery(query, parameters, this)
this.broadcaster.broadcastBeforeQueryEvent(
broadcasterResult,
query,
parameters,
)
rawResult = await executor.run({
sql: query,
params: parameters

View File

@ -1,12 +1,12 @@
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { ConnectionIsNotSetError } from "../../error/ConnectionIsNotSetError"
import { QueryFailedError } from "../../error/QueryFailedError"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { QueryResult } from "../../query-runner/QueryResult"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
import { AbstractSqliteQueryRunner } from "../sqlite-abstract/AbstractSqliteQueryRunner"
import { SqliteConnectionOptions } from "./SqliteConnectionOptions"
import { SqliteDriver } from "./SqliteDriver"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { ConnectionIsNotSetError } from "../../error/ConnectionIsNotSetError"
import { QueryResult } from "../../query-runner/QueryResult"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
/**
* Runs queries on a single sqlite database connection.
@ -48,7 +48,7 @@ export class SqliteQueryRunner extends AbstractSqliteQueryRunner {
/**
* Executes a given SQL query.
*/
query(
async query(
query: string,
parameters?: any[],
useStructuredResult = false,
@ -58,23 +58,21 @@ export class SqliteQueryRunner extends AbstractSqliteQueryRunner {
const connection = this.driver.connection
const options = connection.options as SqliteConnectionOptions
const maxQueryExecutionTime = this.driver.options.maxQueryExecutionTime
const broadcasterResult = new BroadcasterResult()
const broadcaster = this.broadcaster
broadcaster.broadcastBeforeQueryEvent(
broadcasterResult,
query,
parameters,
)
if (!connection.isInitialized) {
throw new ConnectionIsNotSetError("sqlite")
}
const databaseConnection = await this.connect()
this.driver.connection.logger.logQuery(query, parameters, this)
await broadcaster.broadcast("BeforeQuery", query, parameters)
const broadcasterResult = new BroadcasterResult()
return new Promise(async (ok, fail) => {
try {
const databaseConnection = await this.connect()
this.driver.connection.logger.logQuery(query, parameters, this)
const queryStartTime = Date.now()
const isInsertQuery = query.startsWith("INSERT ")
const isDeleteQuery = query.startsWith("DELETE ")

View File

@ -1,10 +1,10 @@
import { QueryFailedError } from "../../error/QueryFailedError"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { QueryResult } from "../../query-runner/QueryResult"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
import { AbstractSqliteQueryRunner } from "../sqlite-abstract/AbstractSqliteQueryRunner"
import { SqljsDriver } from "./SqljsDriver"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { QueryFailedError } from "../../error/QueryFailedError"
import { QueryResult } from "../../query-runner/QueryResult"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
/**
* Runs queries on a single sqlite database connection.
@ -85,17 +85,14 @@ export class SqljsQueryRunner extends AbstractSqliteQueryRunner {
const command = query.trim().split(" ", 1)[0]
const databaseConnection = this.driver.databaseConnection
const broadcasterResult = new BroadcasterResult()
this.driver.connection.logger.logQuery(query, parameters, this)
this.broadcaster.broadcastBeforeQueryEvent(
broadcasterResult,
query,
parameters,
)
await this.broadcaster.broadcast("BeforeQuery", query, parameters)
const broadcasterResult = new BroadcasterResult()
const queryStartTime = Date.now()
let statement: any
try {
statement = databaseConnection.prepare(query)
if (parameters) {

View File

@ -1,11 +1,12 @@
import { ObjectLiteral } from "../../common/ObjectLiteral"
import { QueryResult } from "../../query-runner/QueryResult"
import { TypeORMError } from "../../error"
import { QueryFailedError } from "../../error/QueryFailedError"
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
import { TransactionNotStartedError } from "../../error/TransactionNotStartedError"
import { ColumnType } from "../types/ColumnTypes"
import { ReadStream } from "../../platform/PlatformTools"
import { BaseQueryRunner } from "../../query-runner/BaseQueryRunner"
import { QueryLock } from "../../query-runner/QueryLock"
import { QueryResult } from "../../query-runner/QueryResult"
import { QueryRunner } from "../../query-runner/QueryRunner"
import { TableIndexOptions } from "../../schema-builder/options/TableIndexOptions"
import { Table } from "../../schema-builder/table/Table"
@ -17,17 +18,16 @@ import { TableIndex } from "../../schema-builder/table/TableIndex"
import { TableUnique } from "../../schema-builder/table/TableUnique"
import { View } from "../../schema-builder/view/View"
import { Broadcaster } from "../../subscriber/Broadcaster"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
import { InstanceChecker } from "../../util/InstanceChecker"
import { OrmUtils } from "../../util/OrmUtils"
import { Query } from "../Query"
import { ColumnType } from "../types/ColumnTypes"
import { IsolationLevel } from "../types/IsolationLevel"
import { MetadataTableType } from "../types/MetadataTableType"
import { ReplicationMode } from "../types/ReplicationMode"
import { MssqlParameter } from "./MssqlParameter"
import { SqlServerDriver } from "./SqlServerDriver"
import { ReplicationMode } from "../types/ReplicationMode"
import { TypeORMError } from "../../error"
import { QueryLock } from "../../query-runner/QueryLock"
import { MetadataTableType } from "../types/MetadataTableType"
import { InstanceChecker } from "../../util/InstanceChecker"
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
/**
* Runs queries on a single SQL Server database connection.
@ -209,16 +209,12 @@ export class SqlServerQueryRunner
const release = await this.lock.acquire()
this.driver.connection.logger.logQuery(query, parameters, this)
await this.broadcaster.broadcast("BeforeQuery", query, parameters)
const broadcasterResult = new BroadcasterResult()
try {
this.driver.connection.logger.logQuery(query, parameters, this)
this.broadcaster.broadcastBeforeQueryEvent(
broadcasterResult,
query,
parameters,
)
const pool = await (this.mode === "slave"
? this.driver.obtainSlaveConnection()
: this.driver.obtainMasterConnection())

View File

@ -1,15 +1,22 @@
import { EntitySubscriberInterface } from "./EntitySubscriberInterface"
import { ObjectLiteral } from "../common/ObjectLiteral"
import { QueryRunner } from "../query-runner/QueryRunner"
import { EntityMetadata } from "../metadata/EntityMetadata"
import { BroadcasterResult } from "./BroadcasterResult"
import { ColumnMetadata } from "../metadata/ColumnMetadata"
import { EntityMetadata } from "../metadata/EntityMetadata"
import { RelationMetadata } from "../metadata/RelationMetadata"
import { QueryRunner } from "../query-runner/QueryRunner"
import { ObjectUtils } from "../util/ObjectUtils"
import { BroadcasterResult } from "./BroadcasterResult"
import { EntitySubscriberInterface } from "./EntitySubscriberInterface"
interface BroadcasterEvents {
BeforeQuery: () => void
AfterQuery: () => void
BeforeQuery: (query: string, parameters: any[] | undefined) => void
AfterQuery: (
query: string,
parameters: any[] | undefined,
success: boolean,
executionTime: number | undefined,
rawResults: any | undefined,
error: any | undefined,
) => void
BeforeTransactionCommit: () => void
AfterTransactionCommit: () => void

View File

@ -0,0 +1,18 @@
import { PrimaryGeneratedColumn } from "../../../../src"
import { Column } from "../../../../src/decorator/columns/Column"
import { Entity } from "../../../../src/decorator/entity/Entity"
@Entity()
export class User {
@PrimaryGeneratedColumn("uuid")
id: string
@Column()
firstName: string
@Column()
lastName: string
@Column()
isActive: boolean
}

View File

@ -0,0 +1,41 @@
import "reflect-metadata"
import { DataSource } from "../../../src"
import {
createTestingConnections,
reloadTestingDatabases,
closeTestingConnections,
} from "../../utils/test-utils"
import { expect } from "chai"
import { User } from "./entity/User"
describe("github issues > #11085 BeforeQuery promises are not awaited before query execution", () => {
let connections: DataSource[]
before(async () => {
connections = await createTestingConnections({
enabledDrivers: ["postgres"],
entities: [__dirname + "/entity/*{.js,.ts}"],
subscribers: [__dirname + "/subscriber/*{.js,.ts}"],
})
})
beforeEach(() => reloadTestingDatabases(connections))
afterEach(async () => {
await closeTestingConnections(connections)
})
it("should find user since beforeQuery promise must be awaited before query execution", async () =>
Promise.all(
connections.map(async (connection) => {
const userRepository = await connection.getRepository(User)
const user = await userRepository.findBy({
isActive: true,
})
expect(user.length).to.eq(1)
expect(user[0].firstName).to.eq("John")
expect(user[0].lastName).to.eq("Doe")
expect(user[0].isActive).to.eq(true)
}),
))
})

View File

@ -0,0 +1,18 @@
import { EntitySubscriberInterface, EventSubscriber } from "../../../../src"
import { BeforeQueryEvent } from "../../../../src/subscriber/event/QueryEvent"
import { User } from "../entity/User"
@EventSubscriber()
export class UserSubscriber implements EntitySubscriberInterface<any> {
async beforeQuery(event: BeforeQueryEvent<any>): Promise<void> {
if (event.query.includes('FROM "user"')) {
const userRepository = await event.manager.getRepository(User)
await userRepository.insert({
firstName: "John",
lastName: "Doe",
isActive: true,
})
}
}
}