-
-
Notifications
You must be signed in to change notification settings - Fork 611
Closed
Labels
bugSomething isn't workingSomething isn't working
Description
Describe the bug
We've noticed some unexpected update queries are being executed for persisted getters on the entity.
@Entity()
class User {
@Property({nullable: true, type: JsonType})
children?: Child[];
@Property({ type: ArrayType, nullable: true, persist: true, hydrate: false })
get childEmails(): string[] | undefined {
return this.children?.map((c) => c.email.toLowerCase()).filter((e) => !!e);
}
}Simply fetching this data for this entity from the database would mark the childEmails as dirty and make an update query on the next flush.
While making the reproduction, I've noted that it doesn't occur when using the mysql driver.
(Code below is taken from the reproduction)
Sample entity:
import { ArrayType, Entity, JsonType, PrimaryKey, Property } from '@mikro-orm/postgresql';
export type Child = {
email: string;
}
@Entity()
export class User {
@PrimaryKey()
id!: number;
@Property({nullable: true, type: JsonType})
children?: Child[];
@Property({ type: ArrayType, nullable: true, persist: true, hydrate: false })
get childEmails(): string[] | undefined {
return this.children?.map((c) => c.email.toLowerCase()).filter((e) => !!e);
}
}Mysql test
import { MikroORM } from '@mikro-orm/sqlite';
import { User } from './entity';
let orm: MikroORM;
beforeAll(async () => {
orm = await MikroORM.init({
dbName: ':memory:',
entities: [User],
debug: ['query', 'query-params'],
allowGlobalContext: true, // only for testing
});
await orm.schema.refreshDatabase();
orm.em.create(User, {
children: [{
email: 'test@example.com'
}],
});
await orm.em.flush();
orm.em.clear();
const connection = orm.em.getConnection();
dbExecuteSpy = jest.spyOn(connection, 'execute');
});
let dbExecuteSpy: jest.SpyInstance;
beforeEach(() => {
dbExecuteSpy.mockClear();
});
afterAll(async () => {
await orm.close(true);
});
test('should not try to persist persisted getter if its value has not changed', async () => {
await orm.em.findAll(User);
await orm.em.flush();
expect(dbExecuteSpy).toHaveBeenCalledTimes(1);
expect(dbExecuteSpy).toHaveBeenNthCalledWith<any[]>(
1,
'select `u0`.* from `user` as `u0`',
[],
'all',
undefined,
{ id: 1 },
);
});Postgress test
import { MikroORM, defineConfig } from '@mikro-orm/postgresql';
import { User } from './entity';
let orm: MikroORM;
beforeAll(async () => {
orm = await MikroORM.init(defineConfig({
dbName: 'postgres',
entities: [User],
debug: ['query', 'query-params'],
allowGlobalContext: true, // only for testing
}));
await orm.schema.refreshDatabase();
orm.em.create(User, {
children: [{
email: 'test@example.com'
}],
});
await orm.em.flush();
orm.em.clear();
const connection = orm.em.getConnection();
dbExecuteSpy = jest.spyOn(connection, 'execute');
});
let dbExecuteSpy: jest.SpyInstance;
afterAll(async () => {
await orm.close(true);
});
test('should not try to persist persisted getter if its value has not changed', async () => {
dbExecuteSpy.mockClear();
await orm.em.findAll(User);
await orm.em.flush();
expect(dbExecuteSpy).toHaveBeenCalledTimes(2); // This is unexpected, it should be 1
expect(dbExecuteSpy).toHaveBeenNthCalledWith<any[]>(
1,
'select \"u0\".* from \"user\" as \"u0\"',
[],
'all',
undefined,
{ id: 1 },
);
// This is the additional query that is being done
expect(dbExecuteSpy).toHaveBeenNthCalledWith<any[]>(
2,
'update \"user\" set \"child_emails\" = ? where \"id\" = ?',
[
"{test@example.com}",
1
],
'run',
expect.anything(),
{ id: undefined },
);
});note: reasoning for creating a bug ticket instead of a discussion is the different behavior between the mysql and postgresql driver.
Reproduction
https://github.com/thdk/reproduction/tree/feat/add-test-case
What driver are you using?
@mikro-orm/postgresql
MikroORM version
6.4.17-dev.20
Node.js version
22.2.0
Operating system
mac
Validations
- Read the Contributing Guidelines.
- Read the docs.
- Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord.
- The provided reproduction is a minimal reproducible example of the bug.
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working