Skip to content

Commit

Permalink
fix(core): ensure eager loading on deeper levels work with joined str…
Browse files Browse the repository at this point in the history
…ategy
  • Loading branch information
B4nan committed Dec 15, 2023
1 parent 9f63378 commit cc5f476
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 6 deletions.
21 changes: 15 additions & 6 deletions packages/core/src/entity/EntityLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,32 +76,41 @@ export class EntityLoader {
}

normalizePopulate<T>(entityName: string, populate: PopulateOptions<T>[] | true, strategy?: LoadStrategy, lookup = true): PopulateOptions<T>[] {
const meta = this.metadata.find(entityName)!;

if (populate === true || populate.some(p => p.all)) {
populate = this.lookupAllRelationships(entityName);
} else {
populate = Utils.asArray(populate);
}

// convert nested `field` with dot syntax to PopulateOptions with `children` array
this.expandDotPaths(populate, meta);

if (lookup) {
populate = this.lookupEagerLoadedRelationships(entityName, populate, strategy);

// convert nested `field` with dot syntax produced by eager relations
this.expandDotPaths(populate, meta);
}

// convert nested `field` with dot syntax to PopulateOptions with children array
populate.forEach(p => {
// merge same fields
return this.mergeNestedPopulate(populate);
}

private expandDotPaths<Entity>(normalized: PopulateOptions<Entity>[], meta: EntityMetadata<any>) {
normalized.forEach(p => {
if (!p.field.includes('.')) {
return;
}

const [f, ...parts] = p.field.split('.');
p.field = f;
p.children = p.children || [];
const prop = this.metadata.find(entityName)!.properties[f];
const prop = meta.properties[f];
p.strategy ??= prop.strategy;
p.children.push(this.expandNestedPopulate(prop.type, parts, p.strategy, p.all));
});

// merge same fields
return this.mergeNestedPopulate(populate);
}

/**
Expand Down
102 changes: 102 additions & 0 deletions tests/issues/GHx7.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import {
Collection,
Entity,
ManyToOne,
OneToMany,
PrimaryKey,
Property,
} from '@mikro-orm/core';
import { MikroORM } from '@mikro-orm/sqlite';

@Entity()
class Part {

@PrimaryKey()
id!: string;

@Property()
name!: string;

}

@Entity()
class Job {

@PrimaryKey()
id!: string;

@OneToMany(() => JobConnection, so => so.job, { orphanRemoval: true })
jobConnections = new Collection<JobConnection>(this);

}

@Entity()
class JobConnection {

@PrimaryKey()
id!: string;

@OneToMany(() => OrderItem, e => e.jobConnection, { orphanRemoval: true })
orderItems = new Collection<OrderItem>(this);

@ManyToOne(() => Job)
job?: Job;

}

@Entity()
class OrderItem {

@PrimaryKey()
id!: string;

@ManyToOne(() => Part, { eager: true })
part!: Part;

@ManyToOne(() => JobConnection)
jobConnection?: JobConnection;

}

let orm: MikroORM;

beforeAll(async () => {
orm = await MikroORM.init({
entities: [Part, OrderItem, JobConnection, Job],
dbName: ':memory:',
});
await orm.schema.createSchema();
});

afterAll(async () => {
await orm.close(true);
});

test(`nested eager not respected when populating non-eager parent`, async () => {
orm.em.create(Job, {
id: '1',
jobConnections: [
{
id: '1',
orderItems: [{ id: '1', part: { id: '1', name: 'part' } }],
},
],
});
orm.em.create(Job, {
id: '2',
jobConnections: [
{
id: '2',
orderItems: [{ id: '2', part: { id: '2', name: 'part' } }],
},
],
});
await orm.em.flush();
orm.em.clear();

const jobs = await orm.em.find(Job, {}, {
populate: ['jobConnections.orderItems'],
});

expect(jobs[0].jobConnections[0].orderItems[0].part.name).toBeDefined();
});

0 comments on commit cc5f476

Please sign in to comment.