Skip to content

Commit

Permalink
fix(knex): fix populating M:N from inverse side with joined strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
B4nan committed Oct 18, 2023
1 parent 6c8c15f commit 9f82e95
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 4 deletions.
2 changes: 1 addition & 1 deletion packages/knex/src/AbstractSqlDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,7 @@ export abstract class AbstractSqlDriver<Connection extends AbstractSqlConnection
});
}

const items = owners.length ? await this.rethrow(qb.execute('all')) : [];
const items = owners.length ? await this.rethrow(qb.execute('all', { mergeResults: false })) : [];

const map: Dictionary<T[]> = {};
const pkProps = ownerMeta.getPrimaryProps();
Expand Down
15 changes: 12 additions & 3 deletions packages/knex/src/query/QueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ import type { SqlEntityManager } from '../SqlEntityManager';
import { CriteriaNodeFactory } from './CriteriaNodeFactory';
import type { Field, JoinOptions } from '../typings';

export interface ExecuteOptions {
mapResults?: boolean;
mergeResults?: boolean;
}

/**
* SQL query builder with fluent interface.
*
Expand Down Expand Up @@ -619,7 +624,11 @@ export class QueryBuilder<T extends object = AnyEntity> {
* Executes this QB and returns the raw results, mapped to the property names (unless disabled via last parameter).
* Use `method` to specify what kind of result you want to get (array/single/meta).
*/
async execute<U = any>(method: 'all' | 'get' | 'run' = 'all', mapResults = true): Promise<U> {
async execute<U = any>(method: 'all' | 'get' | 'run' = 'all', options?: ExecuteOptions | boolean): Promise<U> {
options = typeof options === 'boolean' ? { mapResults: options } : (options ?? {});
options.mergeResults ??= true;
options.mapResults ??= true;

if (!this.connectionType && method !== 'run' && [QueryType.INSERT, QueryType.UPDATE, QueryType.DELETE, QueryType.TRUNCATE].includes(this.type ?? QueryType.SELECT)) {
this.connectionType = 'write';
}
Expand All @@ -635,7 +644,7 @@ export class QueryBuilder<T extends object = AnyEntity> {
const res = await this.driver.getConnection(type).execute(query.sql, query.bindings as any[], method, this.context);
const meta = this.mainAlias.metadata;

if (!mapResults || !meta) {
if (!options.mapResults || !meta) {
await this.em?.storeCache(this._cache, cached!, res);
return res as unknown as U;
}
Expand All @@ -651,7 +660,7 @@ export class QueryBuilder<T extends object = AnyEntity> {
const map: Dictionary = {};
mapped = res.map(r => this.driver.mapResult<T>(r, meta, this._populate, this, map)!);

if (joinedProps.length > 0) {
if (options.mergeResults && joinedProps.length > 0) {
mapped = this.driver.mergeJoinedResult(mapped, this.mainAlias.metadata!, joinedProps);
}
} else {
Expand Down
64 changes: 64 additions & 0 deletions tests/issues/GHx5.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Collection, Entity, LoadStrategy, PrimaryKey, ManyToMany } from '@mikro-orm/core';
import { MikroORM } from '@mikro-orm/sqlite';

@Entity()
class User {

@PrimaryKey()
id!: number;

@ManyToMany(() => Car)
cars = new Collection<Car>(this);

}

@Entity()
class Car {

@PrimaryKey()
id!: number;

@ManyToMany(() => User, u => u.cars)
users = new Collection<User>(this);

}

let orm: MikroORM;

beforeAll(async () => {
orm = await MikroORM.init({
dbName: ':memory:',
entities: [User],
loadStrategy: LoadStrategy.JOINED,
});
await orm.schema.createSchema();
});

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

test('loading M:N via em.populate from inverse side with joined strategy', async () => {
const u1 = orm.em.create(User, {});
const u2 = orm.em.create(User, {});
const c1 = orm.em.create(Car, {});
const c2 = orm.em.create(Car, {});
u1.cars.add(c1);
u1.cars.add(c2);
u2.cars.add(c1);
u2.cars.add(c2);
await orm.em.flush();
orm.em.clear();

const cars = await orm.em.find(Car, {});
await orm.em.populate(cars, ['users']);

expect(cars[0].users.toArray()).toEqual([
{ id: 1 },
{ id: 2 },
]);
expect(cars[1].users.toArray()).toEqual([
{ id: 1 },
{ id: 2 },
]);
});

0 comments on commit 9f82e95

Please sign in to comment.