Skip to content

Commit

Permalink
fix(core): only check the same entity type when detecting early updat…
Browse files Browse the repository at this point in the history
…e/delete

Closes #4895
  • Loading branch information
B4nan committed Nov 5, 2023
1 parent e3346e4 commit fef7a1b
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 7 deletions.
17 changes: 10 additions & 7 deletions packages/core/src/unit-of-work/UnitOfWork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -476,30 +476,33 @@ export class UnitOfWork {
}

// Check insert stack if there are any entities matching something from delete stack. This can happen when recreating entities.
const inserts: ChangeSet<any>[] = [];
const inserts: Dictionary<ChangeSet<any>[]> = {};

for (const cs of this.changeSets.values()) {
if (cs.type === ChangeSetType.CREATE) {
inserts.push(cs);
inserts[cs.meta.className] ??= [];
inserts[cs.meta.className].push(cs);
}
}

for (const cs of this.changeSets.values()) {
if (cs.type === ChangeSetType.UPDATE) {
this.findEarlyUpdates(cs, inserts);
this.findEarlyUpdates(cs, inserts[cs.meta.className]);
}
}

for (const entity of this.removeStack) {
const wrapped = helper(entity);

/* istanbul ignore next */
if (helper(entity).__processing) {
if (wrapped.__processing) {
continue;
}

const deletePkHash = [helper(entity).getSerializedPrimaryKey(), ...this.expandUniqueProps(entity)];
const deletePkHash = [wrapped.getSerializedPrimaryKey(), ...this.expandUniqueProps(entity)];
let type = ChangeSetType.DELETE;

for (const cs of inserts) {
for (const cs of inserts[wrapped.__meta.className] ?? []) {
if (deletePkHash.some(hash => hash === cs.getSerializedPrimaryKey() || this.expandUniqueProps(cs.entity).find(child => hash === child))) {
type = ChangeSetType.DELETE_EARLY;
}
Expand Down Expand Up @@ -957,7 +960,7 @@ export class UnitOfWork {
}
}

private findEarlyUpdates<T extends object>(changeSet: ChangeSet<T>, inserts: ChangeSet<T>[]): void {
private findEarlyUpdates<T extends object>(changeSet: ChangeSet<T>, inserts: ChangeSet<T>[] = []): void {
const props = changeSet.meta.uniqueProps;

for (const prop of props) {
Expand Down
60 changes: 60 additions & 0 deletions tests/features/unit-of-work/GH4895.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { MikroORM } from '@mikro-orm/sqlite';
import { Entity, PrimaryKey } from '@mikro-orm/core';

@Entity()
class A {

@PrimaryKey()
id!: string;

}

@Entity()
class B {

@PrimaryKey()
id!: string;

}

let orm: MikroORM;
const types: string[][] = [];

beforeAll(async () => {
orm = await MikroORM.init({
entities: [A, B],
dbName: `:memory:`,
subscribers: [{
onFlush: args => {
const changeSets = args.uow.getChangeSets();
types.push(changeSets.map(cs => cs.type));
},
}],
});

await orm.schema.ensureDatabase();
});

beforeEach(async () => {
await orm.schema.dropSchema();
await orm.schema.createSchema();
});

afterAll(() => orm.close(true));

test('GH #4895', async () => {
await orm.em.transactional(async em => {
em.create(A, { id: '1a' });
em.remove(em.getReference(B, '1a'));
});

await orm.em.transactional(async em => {
em.create(A, { id: '2a' });
em.remove(em.getReference(B, '2b'));
});

expect(types).toEqual([
['create', 'delete'],
['create', 'delete'],
]);
});

0 comments on commit fef7a1b

Please sign in to comment.