Skip to content

Commit

Permalink
fix(query-builder): only map the first result with `qb.getSingleResul…
Browse files Browse the repository at this point in the history
…t()`

Closes #5182
  • Loading branch information
B4nan committed Jan 29, 2024
1 parent fd85fc8 commit 0e56fe1
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 3 deletions.
10 changes: 7 additions & 3 deletions packages/knex/src/query/QueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -825,7 +825,7 @@ export class QueryBuilder<T extends object = AnyEntity> {
/**
* Executes the query, returning array of results
*/
async getResultList(): Promise<T[]> {
async getResultList(limit?: number): Promise<T[]> {
await this.em!.tryFlush(this.mainAlias.entityName, { flushMode: this.flushMode });
const res = await this.execute<EntityData<T>[]>('all', true);
const entities: T[] = [];
Expand All @@ -850,6 +850,10 @@ export class QueryBuilder<T extends object = AnyEntity> {
const entity = this.em!.map<T>(this.mainAlias.entityName, r, { schema: this._schema });
propagatePopulateHint(entity, this._populate);
entities.push(entity);

if (limit != null && --limit === 0) {
break;
}
}

return entities;
Expand All @@ -859,8 +863,8 @@ export class QueryBuilder<T extends object = AnyEntity> {
* Executes the query, returning the first result or null
*/
async getSingleResult(): Promise<T | null> {
const res = await this.getResultList();
return res[0] || null;
const [res] = await this.getResultList(1);
return res || null;
}

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

@Entity()
class Author {

@PrimaryKey()
id!: number;

@ManyToMany(() => Tag)
tags = new Collection<Tag>(this);

@ManyToMany(() => Post)
posts = new Collection<Post>(this);

}

@Entity()
class Tag {

@PrimaryKey()
id!: number;

@ManyToMany(() => Post)
posts = new Collection<Post>(this);

@ManyToMany(() => Author, 'tags')
authors = new Collection<Post>(this);

}

@Entity()
class Post {

@PrimaryKey()
id!: number;

@ManyToMany(() => Tag, 'posts')
tags = new Collection<Tag>(this);

@ManyToMany(() => Author, 'posts')
authors = new Collection<Author>(this);

}

let orm: MikroORM;

beforeAll(async () => {
orm = await MikroORM.init({
dbName: ':memory:',
entities: [Author, Post, Tag],
});
await orm.schema.createSchema();

const author1 = orm.em.create(Author, { id: 1 });
const author2 = orm.em.create(Author, { id: 2 });
const tag1 = orm.em.create(Tag, { id: 1 });
const post1 = orm.em.create(Post, { id: 1 });
const post2 = orm.em.create(Post, { id: 2 });

author1.tags.add(tag1);
author1.posts.add(post1);
tag1.posts.add(post1);

author2.tags.add(tag1);
author2.posts.add(post2);
tag1.posts.add(post2);

await orm.em.flush();
orm.em.clear();
});

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

test('it should map the entities correctly', async () => {
const fork = orm.em.fork();
const result = await fork
.qb(Author, 'a')
.select('*')
.leftJoinAndSelect('a.tags', 't')
.leftJoinAndSelect('t.posts', 'p')
.leftJoin('p.authors', 'a2')
.where('a.id = a2.id')
.orderBy({ 'a.id': 'DESC' })
.getSingleResult();
expect(result!.tags[0].posts[0].id).toBe(2);
});

test('the above test should return the same result as this one', async () => {
const fork = orm.em.fork();
const result = await fork
.qb(Author, 'a')
.select('*')
.leftJoinAndSelect('a.tags', 't')
.leftJoinAndSelect('t.posts', 'p')
.leftJoin('p.authors', 'a2')
.where('a.id = a2.id')
.orderBy({ 'a.id': 'DESC' })
.execute();
const authors = result.map(r => fork.fork().map(Author, r));
expect(authors[0].tags[0].posts[0].id).toBe(2);
});

0 comments on commit 0e56fe1

Please sign in to comment.