Skip to content

Commit

Permalink
fix(core): do not mutate data provided to em.upsert/Many
Browse files Browse the repository at this point in the history
Closes #5136
  • Loading branch information
B4nan committed Feb 4, 2024
1 parent bd22d7c commit 5acb4eb
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 1 deletion.
5 changes: 4 additions & 1 deletion packages/core/src/EntityManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,7 @@ export class EntityManager<D extends IDatabaseDriver = IDatabaseDriver> {
where = helper(entity).getPrimaryKey() as FilterQuery<Entity>;
data = em.comparator.prepareEntity(entity);
} else {
data = Utils.copy(data);
where = Utils.extractPK(data, meta) as FilterQuery<Entity>;

if (where) {
Expand Down Expand Up @@ -785,7 +786,8 @@ export class EntityManager<D extends IDatabaseDriver = IDatabaseDriver> {
const entities = new Map<Entity, EntityData<Entity>>();
const entitiesByData = new Map<EntityData<Entity>, Entity>();

for (let row of data) {
for (let i = 0; i < data.length; i++) {
let row = data[i];
let where: FilterQuery<Entity>;

if (Utils.isEntity(row)) {
Expand All @@ -801,6 +803,7 @@ export class EntityManager<D extends IDatabaseDriver = IDatabaseDriver> {
where = helper(entity).getPrimaryKey() as FilterQuery<Entity>;
row = em.comparator.prepareEntity(entity);
} else {
row = data[i] = Utils.copy(row);
where = Utils.extractPK(row, meta) as FilterQuery<Entity>;

if (where) {
Expand Down
75 changes: 75 additions & 0 deletions tests/features/upsert/GH5136.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { Property, Entity, PrimaryKey } from '@mikro-orm/core';
import { MikroORM } from '@mikro-orm/sqlite';

@Entity()
class User {

@PrimaryKey()
id!: number;

@Property()
name: string;

@Property({ unique: true })
email: string;

constructor(name: string, email: string) {
this.name = name;
this.email = email;
}

}

let orm: MikroORM;

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

beforeEach(async () => {
await orm.schema.clearDatabase();
});

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

test('upsert should not modify data object unless it is an entity', async () => {
const data = { name: 'Foo', email: 'foo' };
orm.em.create(User, data);
await orm.em.flush();
orm.em.clear();

expect(data).toMatchObject({ name: 'Foo', email: 'foo' });

data.name = 'Bar';
const newUser = await orm.em.upsert(User, data);

expect(data).toMatchObject({ name: 'Bar', email: 'foo' });
expect({ name: 'Bar', email: 'foo' }).toMatchObject(data);
});

test('upsertMany should not modify data object unless it is an entity', async () => {
const data1 = { name: 'Foo1', email: 'foo1' };
const data2 = { name: 'Foo2', email: 'foo2' };
orm.em.create(User, data1);
orm.em.create(User, data2);
await orm.em.flush();
orm.em.clear();

expect(data1).toMatchObject({ name: 'Foo1', email: 'foo1' });
expect(data2).toMatchObject({ name: 'Foo2', email: 'foo2' });

data1.name = 'Bar1';
data2.name = 'Bar2';
const [newUser1, newUser2] = await orm.em.upsertMany(User, [data1, data2]);

expect(data1).toMatchObject({ name: 'Bar1', email: 'foo1' });
expect(data2).toMatchObject({ name: 'Bar2', email: 'foo2' });
expect({ name: 'Bar1', email: 'foo1' }).toMatchObject(data1);
expect({ name: 'Bar2', email: 'foo2' }).toMatchObject(data2);
});

0 comments on commit 5acb4eb

Please sign in to comment.