Skip to content

Commit

Permalink
fix(knex): hydrate nullable relations with joined strategy
Browse files Browse the repository at this point in the history
Related: #4675
  • Loading branch information
B4nan committed Sep 24, 2023
1 parent 427cc88 commit 8ddaa93
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 1 deletion.
5 changes: 4 additions & 1 deletion packages/knex/src/AbstractSqlDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,11 +249,14 @@ export abstract class AbstractSqlDriver<Connection extends AbstractSqlConnection
}));

if (!hasPK) {
// initialize empty collections
if ([ReferenceType.MANY_TO_MANY, ReferenceType.ONE_TO_MANY].includes(relation.reference)) {
result[relation.name] = result[relation.name] || [] as unknown as T[keyof T & string];
}

if ([ReferenceType.MANY_TO_ONE, ReferenceType.ONE_TO_ONE].includes(relation.reference)) {
result[relation.name] = null;
}

return;
}

Expand Down
114 changes: 114 additions & 0 deletions tests/issues/GH4675.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import {
Entity,
LoadStrategy,
ManyToOne,
OneToOne,
OptionalProps,
PrimaryKey,
Property,
Ref,
Unique,
} from '@mikro-orm/core';
import { MikroORM } from '@mikro-orm/sqlite';

@Entity()
export class User {

@PrimaryKey()
id!: number;

@Property()
@Unique()
username!: string;

@OneToOne({ entity: () => Profile, mappedBy: (profile: Profile) => profile.user, nullable: true })
profile!: Ref<Profile> | null;

[OptionalProps]?: 'profile';

}

@Entity()
export class Profile {

@PrimaryKey()
id!: number;

@OneToOne({ entity: () => User, inversedBy: user => user.profile, owner: true, hidden: true })
user!: User;

@Property()
name!: string;

}

@Entity()
export class Session {

@PrimaryKey()
id!: number;

@Property()
token!: string;

@ManyToOne({ entity: () => User })
user!: User;

}

let orm: MikroORM;

test('GH #4675', async () => {
orm = await MikroORM.init({
entities: [Session],
dbName: ':memory:',
});
await orm.schema.createSchema();

const user = await orm.em.insert(User, { username: 'username' });
await orm.em.insert(Session, { token: 'abc123', user });

const session1 = await orm.em.findOneOrFail(Session, { token: 'abc123' }, {
populate: ['user', 'user.profile'],
strategy: LoadStrategy.SELECT_IN,
disableIdentityMap: true,
});
expect(session1.user.profile).toBeNull();

const session2 = await orm.em.findOneOrFail(Session, { token: 'abc123' }, {
populate: ['user', 'user.profile'],
strategy: LoadStrategy.JOINED,
disableIdentityMap: true,
});
expect(session2.user.profile).toBeNull();

await orm.close();
});

test('GH #4675 (forceUndefined: true)', async () => {
orm = await MikroORM.init({
entities: [Session],
dbName: ':memory:',
forceUndefined: true,
});
await orm.schema.createSchema();

const user = await orm.em.insert(User, { username: 'username' });
await orm.em.insert(Session, { token: 'abc123', user });

const session1 = await orm.em.findOneOrFail(Session, { token: 'abc123' }, {
populate: ['user', 'user.profile'],
strategy: LoadStrategy.SELECT_IN,
disableIdentityMap: true,
});
expect(session1.user.profile).toBeUndefined();

const session2 = await orm.em.findOneOrFail(Session, { token: 'abc123' }, {
populate: ['user', 'user.profile'],
strategy: LoadStrategy.JOINED,
disableIdentityMap: true,
});
expect(session2.user.profile).toBeUndefined();

await orm.close();
});

0 comments on commit 8ddaa93

Please sign in to comment.