mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
fix: nested transactions issues (#10210)
* fix: nested transactions issues * Forgot test description --------- Co-authored-by: Dmitry Zotov <dmzt08@gmail.com>
This commit is contained in:
parent
3cda7ec39d
commit
25e6ecdfd2
@ -2,6 +2,7 @@ version: "3"
|
||||
services:
|
||||
# mysql
|
||||
mysql:
|
||||
platform: linux/amd64
|
||||
image: "mysql:5.7.37"
|
||||
container_name: "typeorm-mysql"
|
||||
ports:
|
||||
|
||||
11
package-lock.json
generated
11
package-lock.json
generated
@ -6478,6 +6478,17 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hdb-pool": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/hdb-pool/-/hdb-pool-0.1.6.tgz",
|
||||
"integrity": "sha512-8VZOLn1EHamm1NmTFQj2iqjVcfonYIsD7F5DU2bz2N+gF+knp6/MbAVeRXkJtya717IBkPeA5iv0/1iPuYo4ZA==",
|
||||
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
|
||||
@ -99,11 +99,12 @@ export class AuroraMysqlQueryRunner
|
||||
}
|
||||
|
||||
if (this.transactionDepth === 0) {
|
||||
this.transactionDepth += 1
|
||||
await this.client.startTransaction()
|
||||
} else {
|
||||
await this.query(`SAVEPOINT typeorm_${this.transactionDepth}`)
|
||||
this.transactionDepth += 1
|
||||
await this.query(`SAVEPOINT typeorm_${this.transactionDepth - 1}`)
|
||||
}
|
||||
this.transactionDepth += 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionStart")
|
||||
}
|
||||
@ -118,14 +119,15 @@ export class AuroraMysqlQueryRunner
|
||||
await this.broadcaster.broadcast("BeforeTransactionCommit")
|
||||
|
||||
if (this.transactionDepth > 1) {
|
||||
this.transactionDepth -= 1
|
||||
await this.query(
|
||||
`RELEASE SAVEPOINT typeorm_${this.transactionDepth - 1}`,
|
||||
`RELEASE SAVEPOINT typeorm_${this.transactionDepth}`,
|
||||
)
|
||||
} else {
|
||||
this.transactionDepth -= 1
|
||||
await this.client.commitTransaction()
|
||||
this.isTransactionActive = false
|
||||
}
|
||||
this.transactionDepth -= 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionCommit")
|
||||
}
|
||||
@ -140,14 +142,15 @@ export class AuroraMysqlQueryRunner
|
||||
await this.broadcaster.broadcast("BeforeTransactionRollback")
|
||||
|
||||
if (this.transactionDepth > 1) {
|
||||
this.transactionDepth -= 1
|
||||
await this.query(
|
||||
`ROLLBACK TO SAVEPOINT typeorm_${this.transactionDepth - 1}`,
|
||||
`ROLLBACK TO SAVEPOINT typeorm_${this.transactionDepth}`,
|
||||
)
|
||||
} else {
|
||||
this.transactionDepth -= 1
|
||||
await this.client.rollbackTransaction()
|
||||
this.isTransactionActive = false
|
||||
}
|
||||
this.transactionDepth -= 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionRollback")
|
||||
}
|
||||
|
||||
@ -108,11 +108,12 @@ export class AuroraPostgresQueryRunner
|
||||
}
|
||||
|
||||
if (this.transactionDepth === 0) {
|
||||
this.transactionDepth += 1
|
||||
await this.client.startTransaction()
|
||||
} else {
|
||||
await this.query(`SAVEPOINT typeorm_${this.transactionDepth}`)
|
||||
this.transactionDepth += 1
|
||||
await this.query(`SAVEPOINT typeorm_${this.transactionDepth} - 1`)
|
||||
}
|
||||
this.transactionDepth += 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionStart")
|
||||
}
|
||||
@ -127,14 +128,15 @@ export class AuroraPostgresQueryRunner
|
||||
await this.broadcaster.broadcast("BeforeTransactionCommit")
|
||||
|
||||
if (this.transactionDepth > 1) {
|
||||
this.transactionDepth -= 1
|
||||
await this.query(
|
||||
`RELEASE SAVEPOINT typeorm_${this.transactionDepth - 1}`,
|
||||
`RELEASE SAVEPOINT typeorm_${this.transactionDepth}`,
|
||||
)
|
||||
} else {
|
||||
this.transactionDepth -= 1
|
||||
await this.client.commitTransaction()
|
||||
this.isTransactionActive = false
|
||||
}
|
||||
this.transactionDepth -= 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionCommit")
|
||||
}
|
||||
@ -149,14 +151,15 @@ export class AuroraPostgresQueryRunner
|
||||
await this.broadcaster.broadcast("BeforeTransactionRollback")
|
||||
|
||||
if (this.transactionDepth > 1) {
|
||||
this.transactionDepth -= 1
|
||||
await this.query(
|
||||
`ROLLBACK TO SAVEPOINT typeorm_${this.transactionDepth - 1}`,
|
||||
`ROLLBACK TO SAVEPOINT typeorm_${this.transactionDepth}`,
|
||||
)
|
||||
} else {
|
||||
this.transactionDepth -= 1
|
||||
await this.client.rollbackTransaction()
|
||||
this.isTransactionActive = false
|
||||
}
|
||||
this.transactionDepth -= 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionRollback")
|
||||
}
|
||||
|
||||
@ -189,6 +189,7 @@ export class CockroachQueryRunner
|
||||
}
|
||||
|
||||
if (this.transactionDepth === 0) {
|
||||
this.transactionDepth += 1
|
||||
await this.query("START TRANSACTION")
|
||||
await this.query("SAVEPOINT cockroach_restart")
|
||||
if (isolationLevel) {
|
||||
@ -197,10 +198,10 @@ export class CockroachQueryRunner
|
||||
)
|
||||
}
|
||||
} else {
|
||||
await this.query(`SAVEPOINT typeorm_${this.transactionDepth}`)
|
||||
this.transactionDepth += 1
|
||||
await this.query(`SAVEPOINT typeorm_${this.transactionDepth - 1}`)
|
||||
}
|
||||
|
||||
this.transactionDepth += 1
|
||||
this.storeQueries = true
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionStart")
|
||||
@ -216,18 +217,18 @@ export class CockroachQueryRunner
|
||||
await this.broadcaster.broadcast("BeforeTransactionCommit")
|
||||
|
||||
if (this.transactionDepth > 1) {
|
||||
await this.query(
|
||||
`RELEASE SAVEPOINT typeorm_${this.transactionDepth - 1}`,
|
||||
)
|
||||
this.transactionDepth -= 1
|
||||
await this.query(
|
||||
`RELEASE SAVEPOINT typeorm_${this.transactionDepth}`,
|
||||
)
|
||||
} else {
|
||||
this.storeQueries = false
|
||||
this.transactionDepth -= 1
|
||||
await this.query("RELEASE SAVEPOINT cockroach_restart")
|
||||
await this.query("COMMIT")
|
||||
this.queries = []
|
||||
this.isTransactionActive = false
|
||||
this.transactionRetries = 0
|
||||
this.transactionDepth -= 1
|
||||
}
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionCommit")
|
||||
@ -243,17 +244,18 @@ export class CockroachQueryRunner
|
||||
await this.broadcaster.broadcast("BeforeTransactionRollback")
|
||||
|
||||
if (this.transactionDepth > 1) {
|
||||
this.transactionDepth -= 1
|
||||
await this.query(
|
||||
`ROLLBACK TO SAVEPOINT typeorm_${this.transactionDepth - 1}`,
|
||||
`ROLLBACK TO SAVEPOINT typeorm_${this.transactionDepth}`,
|
||||
)
|
||||
} else {
|
||||
this.storeQueries = false
|
||||
this.transactionDepth -= 1
|
||||
await this.query("ROLLBACK")
|
||||
this.queries = []
|
||||
this.isTransactionActive = false
|
||||
this.transactionRetries = 0
|
||||
}
|
||||
this.transactionDepth -= 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionRollback")
|
||||
}
|
||||
|
||||
@ -118,6 +118,7 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner {
|
||||
throw err
|
||||
}
|
||||
if (this.transactionDepth === 0) {
|
||||
this.transactionDepth += 1
|
||||
if (isolationLevel) {
|
||||
await this.query(
|
||||
"SET TRANSACTION ISOLATION LEVEL " + isolationLevel,
|
||||
@ -125,9 +126,9 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner {
|
||||
}
|
||||
await this.query("START TRANSACTION")
|
||||
} else {
|
||||
await this.query(`SAVEPOINT typeorm_${this.transactionDepth}`)
|
||||
this.transactionDepth += 1
|
||||
await this.query(`SAVEPOINT typeorm_${this.transactionDepth - 1}`)
|
||||
}
|
||||
this.transactionDepth += 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionStart")
|
||||
}
|
||||
@ -142,14 +143,15 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner {
|
||||
await this.broadcaster.broadcast("BeforeTransactionCommit")
|
||||
|
||||
if (this.transactionDepth > 1) {
|
||||
this.transactionDepth -= 1
|
||||
await this.query(
|
||||
`RELEASE SAVEPOINT typeorm_${this.transactionDepth - 1}`,
|
||||
`RELEASE SAVEPOINT typeorm_${this.transactionDepth}`,
|
||||
)
|
||||
} else {
|
||||
this.transactionDepth -= 1
|
||||
await this.query("COMMIT")
|
||||
this.isTransactionActive = false
|
||||
}
|
||||
this.transactionDepth -= 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionCommit")
|
||||
}
|
||||
@ -164,14 +166,15 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner {
|
||||
await this.broadcaster.broadcast("BeforeTransactionRollback")
|
||||
|
||||
if (this.transactionDepth > 1) {
|
||||
this.transactionDepth -= 1
|
||||
await this.query(
|
||||
`ROLLBACK TO SAVEPOINT typeorm_${this.transactionDepth - 1}`,
|
||||
`ROLLBACK TO SAVEPOINT typeorm_${this.transactionDepth}`,
|
||||
)
|
||||
} else {
|
||||
this.transactionDepth -= 1
|
||||
await this.query("ROLLBACK")
|
||||
this.isTransactionActive = false
|
||||
}
|
||||
this.transactionDepth -= 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionRollback")
|
||||
}
|
||||
|
||||
@ -135,13 +135,14 @@ export class OracleQueryRunner extends BaseQueryRunner implements QueryRunner {
|
||||
}
|
||||
|
||||
if (this.transactionDepth === 0) {
|
||||
this.transactionDepth += 1
|
||||
await this.query(
|
||||
"SET TRANSACTION ISOLATION LEVEL " + isolationLevel,
|
||||
)
|
||||
} else {
|
||||
await this.query(`SAVEPOINT typeorm_${this.transactionDepth}`)
|
||||
this.transactionDepth += 1
|
||||
await this.query(`SAVEPOINT typeorm_${this.transactionDepth - 1}`)
|
||||
}
|
||||
this.transactionDepth += 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionStart")
|
||||
}
|
||||
@ -174,14 +175,15 @@ export class OracleQueryRunner extends BaseQueryRunner implements QueryRunner {
|
||||
await this.broadcaster.broadcast("BeforeTransactionRollback")
|
||||
|
||||
if (this.transactionDepth > 1) {
|
||||
this.transactionDepth -= 1
|
||||
await this.query(
|
||||
`ROLLBACK TO SAVEPOINT typeorm_${this.transactionDepth - 1}`,
|
||||
`ROLLBACK TO SAVEPOINT typeorm_${this.transactionDepth}`,
|
||||
)
|
||||
} else {
|
||||
this.transactionDepth -= 1
|
||||
await this.query("ROLLBACK")
|
||||
this.isTransactionActive = false
|
||||
}
|
||||
this.transactionDepth -= 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionRollback")
|
||||
}
|
||||
|
||||
@ -173,6 +173,7 @@ export class PostgresQueryRunner
|
||||
}
|
||||
|
||||
if (this.transactionDepth === 0) {
|
||||
this.transactionDepth += 1
|
||||
await this.query("START TRANSACTION")
|
||||
if (isolationLevel) {
|
||||
await this.query(
|
||||
@ -180,9 +181,9 @@ export class PostgresQueryRunner
|
||||
)
|
||||
}
|
||||
} else {
|
||||
await this.query(`SAVEPOINT typeorm_${this.transactionDepth}`)
|
||||
this.transactionDepth += 1
|
||||
await this.query(`SAVEPOINT typeorm_${this.transactionDepth - 1}`)
|
||||
}
|
||||
this.transactionDepth += 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionStart")
|
||||
}
|
||||
@ -197,14 +198,15 @@ export class PostgresQueryRunner
|
||||
await this.broadcaster.broadcast("BeforeTransactionCommit")
|
||||
|
||||
if (this.transactionDepth > 1) {
|
||||
this.transactionDepth -= 1
|
||||
await this.query(
|
||||
`RELEASE SAVEPOINT typeorm_${this.transactionDepth - 1}`,
|
||||
`RELEASE SAVEPOINT typeorm_${this.transactionDepth}`,
|
||||
)
|
||||
} else {
|
||||
this.transactionDepth -= 1
|
||||
await this.query("COMMIT")
|
||||
this.isTransactionActive = false
|
||||
}
|
||||
this.transactionDepth -= 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionCommit")
|
||||
}
|
||||
@ -219,14 +221,15 @@ export class PostgresQueryRunner
|
||||
await this.broadcaster.broadcast("BeforeTransactionRollback")
|
||||
|
||||
if (this.transactionDepth > 1) {
|
||||
this.transactionDepth -= 1
|
||||
await this.query(
|
||||
`ROLLBACK TO SAVEPOINT typeorm_${this.transactionDepth - 1}`,
|
||||
`ROLLBACK TO SAVEPOINT typeorm_${this.transactionDepth}`,
|
||||
)
|
||||
} else {
|
||||
this.transactionDepth -= 1
|
||||
await this.query("ROLLBACK")
|
||||
this.isTransactionActive = false
|
||||
}
|
||||
this.transactionDepth -= 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionRollback")
|
||||
}
|
||||
|
||||
@ -101,6 +101,7 @@ export abstract class AbstractSqliteQueryRunner
|
||||
}
|
||||
|
||||
if (this.transactionDepth === 0) {
|
||||
this.transactionDepth += 1
|
||||
if (isolationLevel) {
|
||||
if (isolationLevel === "READ UNCOMMITTED") {
|
||||
await this.query("PRAGMA read_uncommitted = true")
|
||||
@ -110,9 +111,9 @@ export abstract class AbstractSqliteQueryRunner
|
||||
}
|
||||
await this.query("BEGIN TRANSACTION")
|
||||
} else {
|
||||
await this.query(`SAVEPOINT typeorm_${this.transactionDepth}`)
|
||||
this.transactionDepth += 1
|
||||
await this.query(`SAVEPOINT typeorm_${this.transactionDepth - 1}`)
|
||||
}
|
||||
this.transactionDepth += 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionStart")
|
||||
}
|
||||
@ -127,14 +128,15 @@ export abstract class AbstractSqliteQueryRunner
|
||||
await this.broadcaster.broadcast("BeforeTransactionCommit")
|
||||
|
||||
if (this.transactionDepth > 1) {
|
||||
this.transactionDepth -= 1
|
||||
await this.query(
|
||||
`RELEASE SAVEPOINT typeorm_${this.transactionDepth - 1}`,
|
||||
`RELEASE SAVEPOINT typeorm_${this.transactionDepth}`,
|
||||
)
|
||||
} else {
|
||||
this.transactionDepth -= 1
|
||||
await this.query("COMMIT")
|
||||
this.isTransactionActive = false
|
||||
}
|
||||
this.transactionDepth -= 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionCommit")
|
||||
}
|
||||
@ -149,14 +151,15 @@ export abstract class AbstractSqliteQueryRunner
|
||||
await this.broadcaster.broadcast("BeforeTransactionRollback")
|
||||
|
||||
if (this.transactionDepth > 1) {
|
||||
this.transactionDepth -= 1
|
||||
await this.query(
|
||||
`ROLLBACK TO SAVEPOINT typeorm_${this.transactionDepth - 1}`,
|
||||
`ROLLBACK TO SAVEPOINT typeorm_${this.transactionDepth}`,
|
||||
)
|
||||
} else {
|
||||
this.transactionDepth -= 1
|
||||
await this.query("ROLLBACK")
|
||||
this.isTransactionActive = false
|
||||
}
|
||||
this.transactionDepth -= 1
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionRollback")
|
||||
}
|
||||
|
||||
@ -106,6 +106,7 @@ export class SqlServerQueryRunner
|
||||
}
|
||||
|
||||
if (this.transactionDepth === 0) {
|
||||
this.transactionDepth += 1
|
||||
const pool = await (this.mode === "slave"
|
||||
? this.driver.obtainSlaveConnection()
|
||||
: this.driver.obtainMasterConnection())
|
||||
@ -123,12 +124,12 @@ export class SqlServerQueryRunner
|
||||
this.databaseConnection.begin(transactionCallback)
|
||||
}
|
||||
} else {
|
||||
this.transactionDepth += 1
|
||||
await this.query(
|
||||
`SAVE TRANSACTION typeorm_${this.transactionDepth}`,
|
||||
`SAVE TRANSACTION typeorm_${this.transactionDepth - 1}`,
|
||||
)
|
||||
ok()
|
||||
}
|
||||
this.transactionDepth += 1
|
||||
})
|
||||
|
||||
await this.broadcaster.broadcast("AfterTransactionStart")
|
||||
@ -147,6 +148,7 @@ export class SqlServerQueryRunner
|
||||
|
||||
if (this.transactionDepth === 1) {
|
||||
return new Promise<void>((ok, fail) => {
|
||||
this.transactionDepth -= 1
|
||||
this.databaseConnection.commit(async (err: any) => {
|
||||
if (err) return fail(err)
|
||||
this.isTransactionActive = false
|
||||
@ -156,7 +158,6 @@ export class SqlServerQueryRunner
|
||||
|
||||
ok()
|
||||
this.connection.logger.logQuery("COMMIT")
|
||||
this.transactionDepth -= 1
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -175,12 +176,13 @@ export class SqlServerQueryRunner
|
||||
await this.broadcaster.broadcast("BeforeTransactionRollback")
|
||||
|
||||
if (this.transactionDepth > 1) {
|
||||
await this.query(
|
||||
`ROLLBACK TRANSACTION typeorm_${this.transactionDepth - 1}`,
|
||||
)
|
||||
this.transactionDepth -= 1
|
||||
await this.query(
|
||||
`ROLLBACK TRANSACTION typeorm_${this.transactionDepth}`,
|
||||
)
|
||||
} else {
|
||||
return new Promise<void>((ok, fail) => {
|
||||
this.transactionDepth -= 1
|
||||
this.databaseConnection.rollback(async (err: any) => {
|
||||
if (err) return fail(err)
|
||||
this.isTransactionActive = false
|
||||
@ -190,7 +192,6 @@ export class SqlServerQueryRunner
|
||||
|
||||
ok()
|
||||
this.connection.logger.logQuery("ROLLBACK")
|
||||
this.transactionDepth -= 1
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
44
test/github-issues/10209/entity/asset.ts
Normal file
44
test/github-issues/10209/entity/asset.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
DeleteDateColumn,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
UpdateDateColumn,
|
||||
} from "../../../../src"
|
||||
import { ConfigurationEntity } from "./configuration"
|
||||
|
||||
export enum AssetStatus {
|
||||
new = 0,
|
||||
deleted = -999,
|
||||
}
|
||||
|
||||
@Entity("assets")
|
||||
export class AssetEntity {
|
||||
@PrimaryGeneratedColumn("uuid")
|
||||
id!: string
|
||||
|
||||
@Column({ type: "varchar", length: 255 })
|
||||
name!: string
|
||||
|
||||
@Column({ type: "uuid" })
|
||||
configuration_id!: string
|
||||
|
||||
@Column({ type: "numeric" })
|
||||
status!: AssetStatus
|
||||
|
||||
@CreateDateColumn()
|
||||
created_at!: Date
|
||||
|
||||
@UpdateDateColumn()
|
||||
updated_at!: Date
|
||||
|
||||
@DeleteDateColumn()
|
||||
deleted_at!: Date | null
|
||||
|
||||
@ManyToOne(() => ConfigurationEntity, { nullable: false })
|
||||
@JoinColumn({ name: "configuration_id" })
|
||||
configuration!: ConfigurationEntity
|
||||
}
|
||||
50
test/github-issues/10209/entity/configuration.ts
Normal file
50
test/github-issues/10209/entity/configuration.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
PrimaryGeneratedColumn,
|
||||
UpdateDateColumn,
|
||||
} from "../../../../src"
|
||||
import { AssetEntity } from "./asset"
|
||||
import { LocationEntity } from "./location"
|
||||
|
||||
export enum ConfigurationStatus {
|
||||
deleted = -999,
|
||||
new = 0,
|
||||
}
|
||||
|
||||
@Entity("configurations")
|
||||
export class ConfigurationEntity {
|
||||
@PrimaryGeneratedColumn("uuid")
|
||||
id!: string
|
||||
|
||||
@Column({ type: "varchar", length: 255 })
|
||||
name!: string
|
||||
|
||||
@Column({ type: "numeric" })
|
||||
status!: ConfigurationStatus
|
||||
|
||||
@Column({ type: "uuid", nullable: false })
|
||||
location_id!: string
|
||||
|
||||
@ManyToOne(() => LocationEntity, { nullable: false })
|
||||
@JoinColumn({ name: "location_id" })
|
||||
location!: LocationEntity
|
||||
|
||||
@Column({ type: "boolean", default: true })
|
||||
active!: boolean
|
||||
|
||||
@OneToMany(() => AssetEntity, (asset) => asset.configuration, {
|
||||
cascade: true,
|
||||
})
|
||||
assets!: AssetEntity[]
|
||||
|
||||
@CreateDateColumn()
|
||||
created_at!: Date
|
||||
|
||||
@UpdateDateColumn()
|
||||
updated_at!: Date
|
||||
}
|
||||
34
test/github-issues/10209/entity/location.ts
Normal file
34
test/github-issues/10209/entity/location.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
OneToMany,
|
||||
PrimaryGeneratedColumn,
|
||||
UpdateDateColumn,
|
||||
} from "../../../../src"
|
||||
import { ConfigurationEntity } from "./configuration"
|
||||
|
||||
@Entity("locations")
|
||||
export class LocationEntity {
|
||||
@PrimaryGeneratedColumn("uuid")
|
||||
id!: string
|
||||
|
||||
@Column({ type: "varchar", length: 255 })
|
||||
name!: string
|
||||
|
||||
@Column({ type: "boolean", default: true })
|
||||
active!: boolean
|
||||
|
||||
@CreateDateColumn()
|
||||
created_at!: Date
|
||||
|
||||
@UpdateDateColumn()
|
||||
updated_at!: Date
|
||||
|
||||
@OneToMany(
|
||||
() => ConfigurationEntity,
|
||||
(configuration) => configuration.location,
|
||||
{ cascade: true },
|
||||
)
|
||||
configurations!: ConfigurationEntity[]
|
||||
}
|
||||
88
test/github-issues/10209/issue-10209.ts
Normal file
88
test/github-issues/10209/issue-10209.ts
Normal file
@ -0,0 +1,88 @@
|
||||
import "reflect-metadata"
|
||||
import {
|
||||
createTestingConnections,
|
||||
closeTestingConnections,
|
||||
reloadTestingDatabases,
|
||||
} from "../../utils/test-utils"
|
||||
import { DataSource } from "../../../src/data-source/DataSource"
|
||||
import { expect } from "chai"
|
||||
import { LocationEntity } from "./entity/location"
|
||||
import {
|
||||
ConfigurationEntity,
|
||||
ConfigurationStatus,
|
||||
} from "./entity/configuration"
|
||||
import { AssetEntity, AssetStatus } from "./entity/asset"
|
||||
|
||||
describe("github issues > #10209", () => {
|
||||
let dataSources: DataSource[]
|
||||
before(
|
||||
async () =>
|
||||
(dataSources = await createTestingConnections({
|
||||
entities: [__dirname + "/entity/*{.js,.ts}"],
|
||||
schemaCreate: true,
|
||||
dropSchema: true,
|
||||
})),
|
||||
)
|
||||
beforeEach(() => reloadTestingDatabases(dataSources))
|
||||
after(() => closeTestingConnections(dataSources))
|
||||
|
||||
it("should not fail to run multiple nested transactions in parallel", () =>
|
||||
Promise.all(
|
||||
dataSources.map(async (dataSource) => {
|
||||
const manager = dataSource.createEntityManager()
|
||||
|
||||
await manager.transaction(async (txManager) => {
|
||||
const location = txManager.create(LocationEntity)
|
||||
location.name = "location-0"
|
||||
location.configurations = []
|
||||
for (let c = 0; c < 3; c++) {
|
||||
const config = txManager.create(ConfigurationEntity)
|
||||
config.name = `config-${c}`
|
||||
config.status = ConfigurationStatus.new
|
||||
config.assets = []
|
||||
for (let a = 0; a < 5; a++) {
|
||||
const asset = txManager.create(AssetEntity)
|
||||
asset.name = `asset-${c}-${a}`
|
||||
asset.status = AssetStatus.new
|
||||
config.assets.push(asset)
|
||||
}
|
||||
location.configurations.push(config)
|
||||
}
|
||||
|
||||
await txManager.save(location)
|
||||
})
|
||||
|
||||
const location =
|
||||
(await manager.findOne(LocationEntity, {
|
||||
where: {
|
||||
name: "location-0",
|
||||
},
|
||||
relations: ["configurations", "configurations.assets"],
|
||||
})) || ({} as LocationEntity)
|
||||
|
||||
await manager.transaction(async (txManager) => {
|
||||
return Promise.all(
|
||||
location.configurations.map(async (config) => {
|
||||
await txManager.transaction(async (txManager2) => {
|
||||
await Promise.all(
|
||||
config.assets.map(async (asset) => {
|
||||
asset.status = AssetStatus.deleted
|
||||
await txManager2.save(asset)
|
||||
await txManager2.softDelete(
|
||||
AssetEntity,
|
||||
asset,
|
||||
)
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
config.status = ConfigurationStatus.deleted
|
||||
return await txManager.save(config)
|
||||
}),
|
||||
)
|
||||
})
|
||||
// We only care that the transaction above didn't fail
|
||||
expect(true).to.be.true
|
||||
}),
|
||||
))
|
||||
})
|
||||
Loading…
x
Reference in New Issue
Block a user