Skip to content

Commit

Permalink
fix(query-builder): fix querying for a composite FK when target is jo…
Browse files Browse the repository at this point in the history
…ined

Closes #3738
  • Loading branch information
B4nan committed Nov 14, 2022
1 parent e622acd commit dec4c9c
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 2 deletions.
6 changes: 4 additions & 2 deletions packages/knex/src/query/CriteriaNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,15 @@ export class CriteriaNode implements ICriteriaNode {
}

renameFieldToPK<T>(qb: IQueryBuilder<T>): string {
const alias = qb.getAliasForJoinPath(this.getPath()) ?? qb.alias;
const joinAlias = qb.getAliasForJoinPath(this.getPath());
const alias = joinAlias ?? qb.alias;

if (this.prop!.reference === ReferenceType.MANY_TO_MANY) {
return Utils.getPrimaryKeyHash(this.prop!.inverseJoinColumns.map(col => `${alias}.${col}`));
}

if (this.prop!.owner && this.prop!.joinColumns.length > 1) {
// if we found a matching join, we need to use the target table column names, as we use that alias instead of the root
if (!joinAlias && this.prop!.owner && this.prop!.joinColumns.length > 1) {
return Utils.getPrimaryKeyHash(this.prop!.joinColumns.map(col => `${alias}.${col}`));
}

Expand Down
90 changes: 90 additions & 0 deletions tests/issues/GH3738.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import {
Collection,
Entity,
LoadStrategy,
ManyToOne,
OneToMany, OptionalProps,
PrimaryKey,
Property,
} from '@mikro-orm/core';
import { MikroORM } from '@mikro-orm/postgresql';
import { randomUUID } from 'crypto';

@Entity()
export class Question {

[OptionalProps]?: 'createdAt';

@PrimaryKey({ type: 'uuid' })
id: string = randomUUID();

@PrimaryKey({ length: 6 })
createdAt: Date = new Date();

@OneToMany(() => Answer, answer => answer.question)
answers: Collection<Answer> = new Collection<Answer>(this);

@Property({ length: 255 })
name!: string;

}

@Entity()
export class Answer {

[OptionalProps]?: 'createdAt';

@PrimaryKey({ type: 'uuid' })
id: string = randomUUID();

@PrimaryKey({ length: 6 })
createdAt: Date = new Date();

@ManyToOne({ entity: () => Question })
question!: Question;

}

describe('GH issue 3738', () => {

let orm: MikroORM;
let question: Question;

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

question = orm.em.create(Question, { answers: [{}], name: 'test question' });
await orm.em.flush();
});

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

test('test with populate', async () => {
const foundWithPopulate = await orm.em.find(Answer, { question }, { populate: ['question'] });
expect(foundWithPopulate[0]).toBeDefined();
});

test('test without populate', async () => {
const foundWithoutPopulate = await orm.em.find(Answer, { question });
expect(foundWithoutPopulate[0]).toBeDefined();
});

test('test with query builder 1', async () => {
const foundWithQb = await orm.em.createQueryBuilder(Answer).where({ question }).getResult();
expect(foundWithQb).toBeDefined();
await orm.em.populate(foundWithQb, ['question']);
expect(foundWithQb[0].question).toBeDefined();
});

test('test with query builder 2', async () => {
const foundWithQb = await orm.em.createQueryBuilder(Answer).leftJoin('question', 'q').where({ question }).getResult();
expect(foundWithQb).toBeDefined();
expect(foundWithQb[0].question).toBeDefined();
});
});

0 comments on commit dec4c9c

Please sign in to comment.