mirror of
https://github.com/immich-app/immich.git
synced 2025-04-14 12:06:25 +02:00
refactor: migrate partner repo to kysely (#15366)
This commit is contained in:
parent
d5a9294eeb
commit
097183b31d
5 changed files with 276 additions and 30 deletions
server/src
interfaces
queries
repositories
services
|
@ -1,3 +1,5 @@
|
||||||
|
import { Updateable } from 'kysely';
|
||||||
|
import { Partners } from 'src/db';
|
||||||
import { PartnerEntity } from 'src/entities/partner.entity';
|
import { PartnerEntity } from 'src/entities/partner.entity';
|
||||||
|
|
||||||
export interface PartnerIds {
|
export interface PartnerIds {
|
||||||
|
@ -14,8 +16,8 @@ export const IPartnerRepository = 'IPartnerRepository';
|
||||||
|
|
||||||
export interface IPartnerRepository {
|
export interface IPartnerRepository {
|
||||||
getAll(userId: string): Promise<PartnerEntity[]>;
|
getAll(userId: string): Promise<PartnerEntity[]>;
|
||||||
get(partner: PartnerIds): Promise<PartnerEntity | null>;
|
get(partner: PartnerIds): Promise<PartnerEntity | undefined>;
|
||||||
create(partner: PartnerIds): Promise<PartnerEntity>;
|
create(partner: PartnerIds): Promise<PartnerEntity>;
|
||||||
remove(entity: PartnerEntity): Promise<void>;
|
remove(partner: PartnerIds): Promise<void>;
|
||||||
update(entity: Partial<PartnerEntity>): Promise<PartnerEntity>;
|
update(partner: PartnerIds, entity: Updateable<Partners>): Promise<PartnerEntity>;
|
||||||
}
|
}
|
||||||
|
|
189
server/src/queries/partner.repository.sql
Normal file
189
server/src/queries/partner.repository.sql
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
-- NOTE: This file is auto generated by ./sql-generator
|
||||||
|
|
||||||
|
-- PartnerRepository.getAll
|
||||||
|
select
|
||||||
|
"partners".*,
|
||||||
|
(
|
||||||
|
select
|
||||||
|
to_json(obj)
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"email",
|
||||||
|
"profileImagePath",
|
||||||
|
"profileChangedAt"
|
||||||
|
from
|
||||||
|
"users" as "sharedBy"
|
||||||
|
where
|
||||||
|
"sharedBy"."id" = "partners"."sharedById"
|
||||||
|
) as obj
|
||||||
|
) as "sharedBy",
|
||||||
|
(
|
||||||
|
select
|
||||||
|
to_json(obj)
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"email",
|
||||||
|
"profileImagePath",
|
||||||
|
"profileChangedAt"
|
||||||
|
from
|
||||||
|
"users" as "sharedWith"
|
||||||
|
where
|
||||||
|
"sharedWith"."id" = "partners"."sharedWithId"
|
||||||
|
) as obj
|
||||||
|
) as "sharedWith"
|
||||||
|
from
|
||||||
|
"partners"
|
||||||
|
inner join "users" as "sharedBy" on "partners"."sharedById" = "sharedBy"."id"
|
||||||
|
and "sharedBy"."deletedAt" is null
|
||||||
|
inner join "users" as "sharedWith" on "partners"."sharedWithId" = "sharedWith"."id"
|
||||||
|
and "sharedWith"."deletedAt" is null
|
||||||
|
where
|
||||||
|
(
|
||||||
|
"sharedWithId" = $1
|
||||||
|
or "sharedById" = $2
|
||||||
|
)
|
||||||
|
|
||||||
|
-- PartnerRepository.get
|
||||||
|
select
|
||||||
|
"partners".*,
|
||||||
|
(
|
||||||
|
select
|
||||||
|
to_json(obj)
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"email",
|
||||||
|
"profileImagePath",
|
||||||
|
"profileChangedAt"
|
||||||
|
from
|
||||||
|
"users" as "sharedBy"
|
||||||
|
where
|
||||||
|
"sharedBy"."id" = "partners"."sharedById"
|
||||||
|
) as obj
|
||||||
|
) as "sharedBy",
|
||||||
|
(
|
||||||
|
select
|
||||||
|
to_json(obj)
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"email",
|
||||||
|
"profileImagePath",
|
||||||
|
"profileChangedAt"
|
||||||
|
from
|
||||||
|
"users" as "sharedWith"
|
||||||
|
where
|
||||||
|
"sharedWith"."id" = "partners"."sharedWithId"
|
||||||
|
) as obj
|
||||||
|
) as "sharedWith"
|
||||||
|
from
|
||||||
|
"partners"
|
||||||
|
inner join "users" as "sharedBy" on "partners"."sharedById" = "sharedBy"."id"
|
||||||
|
and "sharedBy"."deletedAt" is null
|
||||||
|
inner join "users" as "sharedWith" on "partners"."sharedWithId" = "sharedWith"."id"
|
||||||
|
and "sharedWith"."deletedAt" is null
|
||||||
|
where
|
||||||
|
"sharedWithId" = $1
|
||||||
|
and "sharedById" = $2
|
||||||
|
|
||||||
|
-- PartnerRepository.create
|
||||||
|
insert into
|
||||||
|
"partners" ("sharedWithId", "sharedById")
|
||||||
|
values
|
||||||
|
($1, $2)
|
||||||
|
returning
|
||||||
|
*,
|
||||||
|
(
|
||||||
|
select
|
||||||
|
to_json(obj)
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"email",
|
||||||
|
"profileImagePath",
|
||||||
|
"profileChangedAt"
|
||||||
|
from
|
||||||
|
"users" as "sharedBy"
|
||||||
|
where
|
||||||
|
"sharedBy"."id" = "partners"."sharedById"
|
||||||
|
) as obj
|
||||||
|
) as "sharedBy",
|
||||||
|
(
|
||||||
|
select
|
||||||
|
to_json(obj)
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"email",
|
||||||
|
"profileImagePath",
|
||||||
|
"profileChangedAt"
|
||||||
|
from
|
||||||
|
"users" as "sharedWith"
|
||||||
|
where
|
||||||
|
"sharedWith"."id" = "partners"."sharedWithId"
|
||||||
|
) as obj
|
||||||
|
) as "sharedWith"
|
||||||
|
|
||||||
|
-- PartnerRepository.update
|
||||||
|
update "partners"
|
||||||
|
set
|
||||||
|
"inTimeline" = $1
|
||||||
|
where
|
||||||
|
"sharedWithId" = $2
|
||||||
|
and "sharedById" = $3
|
||||||
|
returning
|
||||||
|
*,
|
||||||
|
(
|
||||||
|
select
|
||||||
|
to_json(obj)
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"email",
|
||||||
|
"profileImagePath",
|
||||||
|
"profileChangedAt"
|
||||||
|
from
|
||||||
|
"users" as "sharedBy"
|
||||||
|
where
|
||||||
|
"sharedBy"."id" = "partners"."sharedById"
|
||||||
|
) as obj
|
||||||
|
) as "sharedBy",
|
||||||
|
(
|
||||||
|
select
|
||||||
|
to_json(obj)
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"email",
|
||||||
|
"profileImagePath",
|
||||||
|
"profileChangedAt"
|
||||||
|
from
|
||||||
|
"users" as "sharedWith"
|
||||||
|
where
|
||||||
|
"sharedWith"."id" = "partners"."sharedWithId"
|
||||||
|
) as obj
|
||||||
|
) as "sharedWith"
|
||||||
|
|
||||||
|
-- PartnerRepository.remove
|
||||||
|
delete from "partners"
|
||||||
|
where
|
||||||
|
"sharedWithId" = $1
|
||||||
|
and "sharedById" = $2
|
|
@ -1,37 +1,93 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { ExpressionBuilder, Insertable, JoinBuilder, Kysely, Updateable } from 'kysely';
|
||||||
|
import { jsonObjectFrom } from 'kysely/helpers/postgres';
|
||||||
|
import { InjectKysely } from 'nestjs-kysely';
|
||||||
|
import { DB, Partners, Users } from 'src/db';
|
||||||
|
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||||
import { PartnerEntity } from 'src/entities/partner.entity';
|
import { PartnerEntity } from 'src/entities/partner.entity';
|
||||||
import { IPartnerRepository, PartnerIds } from 'src/interfaces/partner.interface';
|
import { IPartnerRepository, PartnerIds } from 'src/interfaces/partner.interface';
|
||||||
import { DeepPartial, Repository } from 'typeorm';
|
|
||||||
|
const columns = ['id', 'name', 'email', 'profileImagePath', 'profileChangedAt'] as const;
|
||||||
|
|
||||||
|
const onSharedBy = (join: JoinBuilder<DB & { sharedBy: Users }, 'partners' | 'sharedBy'>) =>
|
||||||
|
join.onRef('partners.sharedById', '=', 'sharedBy.id').on('sharedBy.deletedAt', 'is', null);
|
||||||
|
|
||||||
|
const onSharedWith = (join: JoinBuilder<DB & { sharedWith: Users }, 'partners' | 'sharedWith'>) =>
|
||||||
|
join.onRef('partners.sharedWithId', '=', 'sharedWith.id').on('sharedWith.deletedAt', 'is', null);
|
||||||
|
|
||||||
|
const withSharedBy = (eb: ExpressionBuilder<DB, 'partners'>) => {
|
||||||
|
return jsonObjectFrom(
|
||||||
|
eb.selectFrom('users as sharedBy').select(columns).whereRef('sharedBy.id', '=', 'partners.sharedById'),
|
||||||
|
).as('sharedBy');
|
||||||
|
};
|
||||||
|
|
||||||
|
const withSharedWith = (eb: ExpressionBuilder<DB, 'partners'>) => {
|
||||||
|
return jsonObjectFrom(
|
||||||
|
eb.selectFrom('users as sharedWith').select(columns).whereRef('sharedWith.id', '=', 'partners.sharedWithId'),
|
||||||
|
).as('sharedWith');
|
||||||
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PartnerRepository implements IPartnerRepository {
|
export class PartnerRepository implements IPartnerRepository {
|
||||||
constructor(@InjectRepository(PartnerEntity) private repository: Repository<PartnerEntity>) {}
|
constructor(@InjectKysely() private db: Kysely<DB>) {}
|
||||||
|
|
||||||
|
@GenerateSql({ params: [DummyValue.UUID] })
|
||||||
getAll(userId: string): Promise<PartnerEntity[]> {
|
getAll(userId: string): Promise<PartnerEntity[]> {
|
||||||
return this.repository.find({ where: [{ sharedWithId: userId }, { sharedById: userId }] });
|
return this.db
|
||||||
|
.selectFrom('partners')
|
||||||
|
.innerJoin('users as sharedBy', onSharedBy)
|
||||||
|
.innerJoin('users as sharedWith', onSharedWith)
|
||||||
|
.selectAll('partners')
|
||||||
|
.select(withSharedBy)
|
||||||
|
.select(withSharedWith)
|
||||||
|
.where((eb) => eb.or([eb('sharedWithId', '=', userId), eb('sharedById', '=', userId)]))
|
||||||
|
.execute() as Promise<PartnerEntity[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
get({ sharedWithId, sharedById }: PartnerIds): Promise<PartnerEntity | null> {
|
@GenerateSql({ params: [{ sharedWithId: DummyValue.UUID, sharedById: DummyValue.UUID }] })
|
||||||
return this.repository.findOne({ where: { sharedById, sharedWithId } });
|
get({ sharedWithId, sharedById }: PartnerIds): Promise<PartnerEntity | undefined> {
|
||||||
|
return this.db
|
||||||
|
.selectFrom('partners')
|
||||||
|
.innerJoin('users as sharedBy', onSharedBy)
|
||||||
|
.innerJoin('users as sharedWith', onSharedWith)
|
||||||
|
.selectAll('partners')
|
||||||
|
.select(withSharedBy)
|
||||||
|
.select(withSharedWith)
|
||||||
|
.where('sharedWithId', '=', sharedWithId)
|
||||||
|
.where('sharedById', '=', sharedById)
|
||||||
|
.executeTakeFirst() as unknown as Promise<PartnerEntity | undefined>;
|
||||||
}
|
}
|
||||||
|
|
||||||
create({ sharedById, sharedWithId }: PartnerIds): Promise<PartnerEntity> {
|
@GenerateSql({ params: [{ sharedWithId: DummyValue.UUID, sharedById: DummyValue.UUID }] })
|
||||||
return this.save({ sharedBy: { id: sharedById }, sharedWith: { id: sharedWithId } });
|
create(values: Insertable<Partners>): Promise<PartnerEntity> {
|
||||||
|
return this.db
|
||||||
|
.insertInto('partners')
|
||||||
|
.values(values)
|
||||||
|
.returningAll()
|
||||||
|
.returning(withSharedBy)
|
||||||
|
.returning(withSharedWith)
|
||||||
|
.executeTakeFirstOrThrow() as unknown as Promise<PartnerEntity>;
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(entity: PartnerEntity): Promise<void> {
|
@GenerateSql({ params: [{ sharedWithId: DummyValue.UUID, sharedById: DummyValue.UUID }, { inTimeline: true }] })
|
||||||
await this.repository.remove(entity);
|
update({ sharedWithId, sharedById }: PartnerIds, values: Updateable<Partners>): Promise<PartnerEntity> {
|
||||||
|
return this.db
|
||||||
|
.updateTable('partners')
|
||||||
|
.set(values)
|
||||||
|
.where('sharedWithId', '=', sharedWithId)
|
||||||
|
.where('sharedById', '=', sharedById)
|
||||||
|
.returningAll()
|
||||||
|
.returning(withSharedBy)
|
||||||
|
.returning(withSharedWith)
|
||||||
|
.executeTakeFirstOrThrow() as unknown as Promise<PartnerEntity>;
|
||||||
}
|
}
|
||||||
|
|
||||||
update(entity: Partial<PartnerEntity>): Promise<PartnerEntity> {
|
@GenerateSql({ params: [{ sharedWithId: DummyValue.UUID, sharedById: DummyValue.UUID }] })
|
||||||
return this.save(entity);
|
async remove({ sharedWithId, sharedById }: PartnerIds): Promise<void> {
|
||||||
}
|
await this.db
|
||||||
|
.deleteFrom('partners')
|
||||||
private async save(entity: DeepPartial<PartnerEntity>): Promise<PartnerEntity> {
|
.where('sharedWithId', '=', sharedWithId)
|
||||||
await this.repository.save(entity);
|
.where('sharedById', '=', sharedById)
|
||||||
return this.repository.findOneOrFail({
|
.execute();
|
||||||
where: { sharedById: entity.sharedById, sharedWithId: entity.sharedWithId },
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ describe(PartnerService.name, () => {
|
||||||
|
|
||||||
describe('create', () => {
|
describe('create', () => {
|
||||||
it('should create a new partner', async () => {
|
it('should create a new partner', async () => {
|
||||||
partnerMock.get.mockResolvedValue(null);
|
partnerMock.get.mockResolvedValue(void 0);
|
||||||
partnerMock.create.mockResolvedValue(partnerStub.adminToUser1);
|
partnerMock.create.mockResolvedValue(partnerStub.adminToUser1);
|
||||||
|
|
||||||
await expect(sut.create(authStub.admin, authStub.user1.user.id)).resolves.toBeDefined();
|
await expect(sut.create(authStub.admin, authStub.user1.user.id)).resolves.toBeDefined();
|
||||||
|
@ -67,7 +67,7 @@ describe(PartnerService.name, () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error when the partner does not exist', async () => {
|
it('should throw an error when the partner does not exist', async () => {
|
||||||
partnerMock.get.mockResolvedValue(null);
|
partnerMock.get.mockResolvedValue(void 0);
|
||||||
|
|
||||||
await expect(sut.remove(authStub.admin, authStub.user1.user.id)).rejects.toBeInstanceOf(BadRequestException);
|
await expect(sut.remove(authStub.admin, authStub.user1.user.id)).rejects.toBeInstanceOf(BadRequestException);
|
||||||
|
|
||||||
|
@ -87,11 +87,10 @@ describe(PartnerService.name, () => {
|
||||||
partnerMock.update.mockResolvedValue(partnerStub.adminToUser1);
|
partnerMock.update.mockResolvedValue(partnerStub.adminToUser1);
|
||||||
|
|
||||||
await expect(sut.update(authStub.admin, 'shared-by-id', { inTimeline: true })).resolves.toBeDefined();
|
await expect(sut.update(authStub.admin, 'shared-by-id', { inTimeline: true })).resolves.toBeDefined();
|
||||||
expect(partnerMock.update).toHaveBeenCalledWith({
|
expect(partnerMock.update).toHaveBeenCalledWith(
|
||||||
sharedById: 'shared-by-id',
|
{ sharedById: 'shared-by-id', sharedWithId: authStub.admin.user.id },
|
||||||
sharedWithId: authStub.admin.user.id,
|
{ inTimeline: true },
|
||||||
inTimeline: true,
|
);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -43,7 +43,7 @@ export class PartnerService extends BaseService {
|
||||||
await this.requireAccess({ auth, permission: Permission.PARTNER_UPDATE, ids: [sharedById] });
|
await this.requireAccess({ auth, permission: Permission.PARTNER_UPDATE, ids: [sharedById] });
|
||||||
const partnerId: PartnerIds = { sharedById, sharedWithId: auth.user.id };
|
const partnerId: PartnerIds = { sharedById, sharedWithId: auth.user.id };
|
||||||
|
|
||||||
const entity = await this.partnerRepository.update({ ...partnerId, inTimeline: dto.inTimeline });
|
const entity = await this.partnerRepository.update(partnerId, { inTimeline: dto.inTimeline });
|
||||||
return this.mapPartner(entity, PartnerDirection.SharedWith);
|
return this.mapPartner(entity, PartnerDirection.SharedWith);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue