Skip to content

Commit

Permalink
fix(core): improve handling of not managed references created via `re…
Browse files Browse the repository at this point in the history
…f()/rel()`

Closes #4027
  • Loading branch information
B4nan committed Feb 10, 2023
1 parent 68e073b commit 2e814e8
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 3 deletions.
5 changes: 5 additions & 0 deletions packages/core/src/entity/EntityFactory.ts
Expand Up @@ -5,6 +5,7 @@ import { QueryHelper } from '../utils/QueryHelper';
import { EventType, ReferenceType } from '../enums';
import { Reference } from './Reference';
import { helper } from './wrap';
import type { EntityComparator } from '../utils/EntityComparator';

export interface FactoryOptions {
initialized?: boolean;
Expand Down Expand Up @@ -178,6 +179,10 @@ export class EntityFactory {
return this.createEntity(data, meta2, options);
}

getComparator(): EntityComparator {
return this.comparator;
}

private createEntity<T extends object>(data: EntityData<T>, meta: EntityMetadata<T>, options: FactoryOptions): T {
if (options.newEntity || meta.forceConstructor || meta.virtual) {
if (!meta.class) {
Expand Down
8 changes: 7 additions & 1 deletion packages/core/src/entity/Reference.ts
Expand Up @@ -60,11 +60,17 @@ export class Reference<T> {

static createNakedFromPK<T extends object, PK extends keyof T | unknown = PrimaryProperty<T>>(entityType: EntityClass<T>, pk: Primary<T>, options?: { schema?: string }): T {
const factory = entityType.prototype.__factory as EntityFactory;
return factory.createReference(entityType, pk, {
const entity = factory.createReference(entityType, pk, {
merge: false,
convertCustomTypes: false,
...options,
});

const wrapped = helper(entity);
wrapped.__meta.primaryKeys.forEach(key => wrapped.__loadedProperties.add(key));
wrapped.__originalEntityData = factory.getComparator().prepareEntity(entity);

return entity;
}

/**
Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/unit-of-work/UnitOfWork.ts
Expand Up @@ -718,7 +718,6 @@ export class UnitOfWork {
}

const collection = reference as Collection<AnyEntity>;
const requireFullyInitialized = type === Cascade.PERSIST; // only cascade persist needs fully initialized items

if ([ReferenceType.ONE_TO_MANY, ReferenceType.MANY_TO_MANY].includes(prop.reference) && collection) {
if (type === Cascade.MERGE && collection.isInitialized()) {
Expand All @@ -727,7 +726,6 @@ export class UnitOfWork {

collection
.getItems(false)
.filter(item => !requireFullyInitialized || helper(item).__initialized)
.forEach(item => this.cascade(item, type, visited, options));
}
}
Expand Down
76 changes: 76 additions & 0 deletions tests/issues/GH4027.test.ts
@@ -0,0 +1,76 @@
import { MikroORM } from '@mikro-orm/sqlite';
import { Entity, PrimaryKey, Property, ManyToMany, Collection, ref, SimpleLogger } from '@mikro-orm/core';
import { mockLogger } from '../helpers';

@Entity()
export class Parent {

@PrimaryKey()
id!: string;

@Property()
createdAt!: Date;

@ManyToMany({ entity: () => Child, owner: true })
refs = new Collection<Child>(this);

}

@Entity()
export class Child {

@PrimaryKey()
id!: string;

@Property()
createdAt!: Date;

}

let orm: MikroORM;

beforeAll(async () => {
orm = await MikroORM.init({
dbName: ':memory:',
entities: [Parent],
loggerFactory: options => new SimpleLogger(options),
});
await orm.schema.refreshDatabase();
});

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

test('GH 4027', async () => {
const mock = mockLogger(orm);

// Child entity create
let em = orm.em.fork();

const e2 = new Child();
e2.id = 'e80ccf60-5cb2-4972-9227-7a4b9138c845';
e2.createdAt = new Date(1676050010440);

em.persist(e2);

await em.flush();

// Parent referencing child create
em = orm.em.fork();
const e1 = new Parent();
e1.id = '9a061473-4a98-477d-ad03-fd7bcba3ec4f';
e1.createdAt = new Date(1676050010441);
e1.refs.set([ref(Child, e2.id)]);
em.persist(e1);

await em.flush();

expect(mock.mock.calls).toEqual([
['[query] begin'],
["[query] insert into `child` (`id`, `created_at`) values ('e80ccf60-5cb2-4972-9227-7a4b9138c845', 1676050010440) returning `id`"],
['[query] commit'],
['[query] begin'],
["[query] insert into `parent` (`id`, `created_at`) values ('9a061473-4a98-477d-ad03-fd7bcba3ec4f', 1676050010441) returning `id`"],
["[query] insert into `parent_refs` (`parent_id`, `child_id`) values ('9a061473-4a98-477d-ad03-fd7bcba3ec4f', 'e80ccf60-5cb2-4972-9227-7a4b9138c845') returning `parent_id`, `child_id`"],
['[query] commit'],
]);
});

0 comments on commit 2e814e8

Please sign in to comment.