Skip to content

Commit

Permalink
feat(core): add EntityRepository.upsert() shortcut
Browse files Browse the repository at this point in the history
  • Loading branch information
B4nan committed Nov 1, 2022
1 parent 30d04a1 commit 31d6d77
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 0 deletions.
26 changes: 26 additions & 0 deletions packages/core/src/entity/EntityRepository.ts
Expand Up @@ -52,6 +52,32 @@ export class EntityRepository<T extends object> {
return this.em.findOneOrFail<T, P>(this.entityName, where, options);
}

/**
* Creates or updates the entity, based on whether it is already present in the database.
* This method performs an `insert on conflict merge` query ensuring the database is in sync, returning a managed
* entity instance. The method accepts either `entityName` together with the entity `data`, or just entity instance.
*
* ```ts
* // insert into "author" ("age", "email") values (33, 'foo@bar.com') on conflict ("email") do update set "age" = 41
* const author = await em.getRepository(Author).upsert({ email: 'foo@bar.com', age: 33 });
* ```
*
* The entity data needs to contain either the primary key, or any other unique property. Let's consider the following example, where `Author.email` is a unique property:
*
* ```ts
* // insert into "author" ("age", "email") values (33, 'foo@bar.com') on conflict ("email") do update set "age" = 41
* // select "id" from "author" where "email" = 'foo@bar.com'
* const author = await em.getRepository(Author).upsert({ email: 'foo@bar.com', age: 33 });
* ```
*
* Depending on the driver support, this will either use a returning query, or a separate select query, to fetch the primary key if it's missing from the `data`.
*
* If the entity is already present in current context, there won't be any queries - instead, the entity data will be assigned and an explicit `flush` will be required for those changes to be persisted.
*/
async upsert(entityOrData?: EntityData<T> | T, options?: NativeInsertUpdateOptions<T>): Promise<T> {
return this.em.upsert<T>(this.entityName, entityOrData, options);
}

/**
* Finds all entities matching your `where` query. You can pass additional options via the `options` parameter.
*/
Expand Down
3 changes: 3 additions & 0 deletions tests/EntityRepository.test.ts
Expand Up @@ -15,6 +15,7 @@ const methods = {
qb: jest.fn(),
findOne: jest.fn(),
findOneOrFail: jest.fn(),
upsert: jest.fn(),
find: jest.fn(),
findAndCount: jest.fn(),
remove: jest.fn(),
Expand Down Expand Up @@ -62,6 +63,8 @@ describe('EntityRepository', () => {
expect(methods.findOne.mock.calls[0]).toEqual([Publisher, 'bar', undefined]);
await repo.findOneOrFail('bar');
expect(methods.findOneOrFail.mock.calls[0]).toEqual([Publisher, 'bar', undefined]);
await repo.upsert({ name: 'bar', id: '1' });
expect(methods.upsert.mock.calls[0]).toEqual([Publisher, { name: 'bar', id: '1' }, undefined]);
await repo.createQueryBuilder();
expect(methods.createQueryBuilder.mock.calls[0]).toEqual([Publisher, undefined]);
await repo.qb();
Expand Down

0 comments on commit 31d6d77

Please sign in to comment.