Skip to content

Commit

Permalink
fix(core): fix returning clause for upsert with embeddables (#4427)
Browse files Browse the repository at this point in the history
Currently, when you run upsert on an entity with an embeddable, the name
of the embeddable is included in the returning statement and causing
`InvalidFieldNameException`.

The produced query without the change:
``` 
insert into `foo_bar_with_embeddable` (`_id`) values (1) on conflict (`_id`) do nothing returning `fooBarEmbeddable`, `foo_bar_embeddable_name`;
````
  • Loading branch information
jsprw committed Jun 7, 2023
1 parent fa1c696 commit b9682f0
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 4 deletions.
4 changes: 2 additions & 2 deletions packages/knex/src/AbstractSqlDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ export abstract class AbstractSqlDriver<Connection extends AbstractSqlConnection
qb.insert(data as T)
.onConflict(uniqueFields.map(p => meta?.properties[p]?.fieldNames[0] ?? p))
.merge(Object.keys(data).filter(f => !uniqueFields.includes(f)))
.returning(meta?.comparableProps.filter(p => !p.lazy && !(p.name in data)).map(p => p.name) ?? '*');
.returning(meta?.comparableProps.filter(p => !p.lazy && !p.embeddable && !(p.name in data)).map(p => p.name) ?? '*');
} else {
qb.update(data).where(where);
}
Expand All @@ -452,7 +452,7 @@ export abstract class AbstractSqlDriver<Connection extends AbstractSqlConnection
qb.insert(data)
.onConflict(uniqueFields.map(p => meta.properties[p]?.fieldNames[0] ?? p))
.merge(Object.keys(data[0]).filter(f => !uniqueFields.includes(f)))
.returning(meta.comparableProps.filter(p => !p.lazy && !(p.name in data[0])).map(p => p.name) ?? '*');
.returning(meta.comparableProps.filter(p => !p.lazy && !p.embeddable && !(p.name in data[0])).map(p => p.name) ?? '*');
return qb.execute('run', false);
}

Expand Down
38 changes: 36 additions & 2 deletions tests/features/upsert/upsert.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
MikroORM, Entity, PrimaryKey, ManyToOne, Property, SimpleLogger,
Unique, Ref, ref, EventSubscriber, EventArgs, OneToMany, Collection,
Unique, Ref, ref, EventSubscriber, EventArgs, OneToMany, Collection, Embeddable, Embedded,
} from '@mikro-orm/core';
import { mockLogger } from '../../helpers';

Expand Down Expand Up @@ -74,6 +74,27 @@ export class FooBar {

}

@Entity()
export class FooBarWithEmbeddable {

static id = 1;

@PrimaryKey({ name: '_id' })
id: number = FooBar.id++;

@Embedded(() => FooBarEmbeddable)
fooBarEmbeddable = new FooBarEmbeddable();

}

@Embeddable()
export class FooBarEmbeddable {

@Property({ nullable: true })
name?: string;

}

class Subscriber implements EventSubscriber {

static log: any[] = [];
Expand Down Expand Up @@ -106,7 +127,7 @@ describe.each(Object.keys(options))('em.upsert [%s]', type => {

beforeAll(async () => {
orm = await MikroORM.init({
entities: [Author, Book, FooBar],
entities: [Author, Book, FooBar, FooBarWithEmbeddable],
type,
loggerFactory: options => new SimpleLogger(options),
subscribers: [new Subscriber()],
Expand Down Expand Up @@ -449,4 +470,17 @@ describe.each(Object.keys(options))('em.upsert [%s]', type => {
await assertFooBars([fooBar1, fooBar2, fooBar3], mock);
});


test('em.upsert(entity) with embeddable', async () => {
const testEntity = orm.em.create(FooBarWithEmbeddable, { fooBarEmbeddable: {} });

await orm.em.upsert(testEntity);

expect(testEntity.id).toBeDefined();

const [insertedEntity2] = await orm.em.upsertMany(FooBarWithEmbeddable, [{ id: testEntity.id, fooBarEmbeddable: {} }]);

expect(insertedEntity2).toBe(testEntity);
});

});

0 comments on commit b9682f0

Please sign in to comment.