mirror of
https://github.com/immich-app/immich.git
synced 2025-07-09 03:04:16 -04:00
refactor(server): migrate album-user repo to kysely (#15351)
This commit is contained in:
parent
c5476a99b1
commit
2903ad8156
@ -86,6 +86,7 @@ class SqlGenerator {
|
|||||||
this.sqlLogger.logQuery(event.query.sql);
|
this.sqlLogger.logQuery(event.query.sql);
|
||||||
} else if (event.level === 'error') {
|
} else if (event.level === 'error') {
|
||||||
this.sqlLogger.logQueryError(event.error as Error, event.query.sql);
|
this.sqlLogger.logQueryError(event.error as Error, event.query.sql);
|
||||||
|
this.sqlLogger.logQuery(event.query.sql);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
import { AlbumUserEntity } from 'src/entities/album-user.entity';
|
import { Insertable, Selectable, Updateable } from 'kysely';
|
||||||
|
import { AlbumsSharedUsersUsers } from 'src/db';
|
||||||
|
|
||||||
export const IAlbumUserRepository = 'IAlbumUserRepository';
|
export const IAlbumUserRepository = 'IAlbumUserRepository';
|
||||||
|
|
||||||
export type AlbumPermissionId = {
|
export type AlbumPermissionId = {
|
||||||
albumId: string;
|
albumsId: string;
|
||||||
userId: string;
|
usersId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface IAlbumUserRepository {
|
export interface IAlbumUserRepository {
|
||||||
create(albumUser: Partial<AlbumUserEntity>): Promise<AlbumUserEntity>;
|
create(albumUser: Insertable<AlbumsSharedUsersUsers>): Promise<Selectable<AlbumsSharedUsersUsers>>;
|
||||||
update({ userId, albumId }: AlbumPermissionId, albumPermission: Partial<AlbumUserEntity>): Promise<AlbumUserEntity>;
|
update(
|
||||||
delete({ userId, albumId }: AlbumPermissionId): Promise<void>;
|
id: AlbumPermissionId,
|
||||||
|
albumPermission: Updateable<AlbumsSharedUsersUsers>,
|
||||||
|
): Promise<Selectable<AlbumsSharedUsersUsers>>;
|
||||||
|
delete(id: AlbumPermissionId): Promise<void>;
|
||||||
}
|
}
|
||||||
|
25
server/src/queries/album.user.repository.sql
Normal file
25
server/src/queries/album.user.repository.sql
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
-- NOTE: This file is auto generated by ./sql-generator
|
||||||
|
|
||||||
|
-- AlbumUserRepository.create
|
||||||
|
insert into
|
||||||
|
"albums_shared_users_users" ("usersId", "albumsId")
|
||||||
|
values
|
||||||
|
($1, $2)
|
||||||
|
returning
|
||||||
|
*
|
||||||
|
|
||||||
|
-- AlbumUserRepository.update
|
||||||
|
update "albums_shared_users_users"
|
||||||
|
set
|
||||||
|
"role" = $1
|
||||||
|
where
|
||||||
|
"usersId" = $2
|
||||||
|
and "albumsId" = $3
|
||||||
|
returning
|
||||||
|
*
|
||||||
|
|
||||||
|
-- AlbumUserRepository.delete
|
||||||
|
delete from "albums_shared_users_users"
|
||||||
|
where
|
||||||
|
"usersId" = $1
|
||||||
|
and "albumsId" = $2
|
@ -1,26 +1,40 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { Insertable, Kysely, Selectable, Updateable } from 'kysely';
|
||||||
import { AlbumUserEntity } from 'src/entities/album-user.entity';
|
import { InjectKysely } from 'nestjs-kysely';
|
||||||
|
import { AlbumsSharedUsersUsers, DB } from 'src/db';
|
||||||
|
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||||
|
import { AlbumUserRole } from 'src/enum';
|
||||||
import { AlbumPermissionId, IAlbumUserRepository } from 'src/interfaces/album-user.interface';
|
import { AlbumPermissionId, IAlbumUserRepository } from 'src/interfaces/album-user.interface';
|
||||||
import { Repository } from 'typeorm';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AlbumUserRepository implements IAlbumUserRepository {
|
export class AlbumUserRepository implements IAlbumUserRepository {
|
||||||
constructor(@InjectRepository(AlbumUserEntity) private repository: Repository<AlbumUserEntity>) {}
|
constructor(@InjectKysely() private db: Kysely<DB>) {}
|
||||||
|
|
||||||
async create(albumUser: Partial<AlbumUserEntity>): Promise<AlbumUserEntity> {
|
@GenerateSql({ params: [{ usersId: DummyValue.UUID, albumsId: DummyValue.UUID }] })
|
||||||
const { userId, albumId } = await this.repository.save(albumUser);
|
create(albumUser: Insertable<AlbumsSharedUsersUsers>): Promise<Selectable<AlbumsSharedUsersUsers>> {
|
||||||
return this.repository.findOneOrFail({ where: { userId, albumId } });
|
return this.db.insertInto('albums_shared_users_users').values(albumUser).returningAll().executeTakeFirstOrThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
async update({ userId, albumId }: AlbumPermissionId, dto: Partial<AlbumUserEntity>): Promise<AlbumUserEntity> {
|
@GenerateSql({ params: [{ usersId: DummyValue.UUID, albumsId: DummyValue.UUID }, { role: AlbumUserRole.VIEWER }] })
|
||||||
await this.repository.update({ userId, albumId }, dto);
|
update(
|
||||||
return this.repository.findOneOrFail({
|
{ usersId, albumsId }: AlbumPermissionId,
|
||||||
where: { userId, albumId },
|
dto: Updateable<AlbumsSharedUsersUsers>,
|
||||||
});
|
): Promise<Selectable<AlbumsSharedUsersUsers>> {
|
||||||
|
return this.db
|
||||||
|
.updateTable('albums_shared_users_users')
|
||||||
|
.set(dto)
|
||||||
|
.where('usersId', '=', usersId)
|
||||||
|
.where('albumsId', '=', albumsId)
|
||||||
|
.returningAll()
|
||||||
|
.executeTakeFirstOrThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete({ userId, albumId }: AlbumPermissionId): Promise<void> {
|
@GenerateSql({ params: [{ usersId: DummyValue.UUID, albumsId: DummyValue.UUID }] })
|
||||||
await this.repository.delete({ userId, albumId });
|
async delete({ usersId, albumsId }: AlbumPermissionId): Promise<void> {
|
||||||
|
await this.db
|
||||||
|
.deleteFrom('albums_shared_users_users')
|
||||||
|
.where('usersId', '=', usersId)
|
||||||
|
.where('albumsId', '=', albumsId)
|
||||||
|
.execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -323,18 +323,16 @@ describe(AlbumService.name, () => {
|
|||||||
albumMock.update.mockResolvedValue(albumStub.sharedWithAdmin);
|
albumMock.update.mockResolvedValue(albumStub.sharedWithAdmin);
|
||||||
userMock.get.mockResolvedValue(userStub.user2);
|
userMock.get.mockResolvedValue(userStub.user2);
|
||||||
albumUserMock.create.mockResolvedValue({
|
albumUserMock.create.mockResolvedValue({
|
||||||
userId: userStub.user2.id,
|
usersId: userStub.user2.id,
|
||||||
user: userStub.user2,
|
albumsId: albumStub.sharedWithAdmin.id,
|
||||||
albumId: albumStub.sharedWithAdmin.id,
|
|
||||||
album: albumStub.sharedWithAdmin,
|
|
||||||
role: AlbumUserRole.EDITOR,
|
role: AlbumUserRole.EDITOR,
|
||||||
});
|
});
|
||||||
await sut.addUsers(authStub.user1, albumStub.sharedWithAdmin.id, {
|
await sut.addUsers(authStub.user1, albumStub.sharedWithAdmin.id, {
|
||||||
albumUsers: [{ userId: authStub.user2.user.id }],
|
albumUsers: [{ userId: authStub.user2.user.id }],
|
||||||
});
|
});
|
||||||
expect(albumUserMock.create).toHaveBeenCalledWith({
|
expect(albumUserMock.create).toHaveBeenCalledWith({
|
||||||
userId: authStub.user2.user.id,
|
usersId: authStub.user2.user.id,
|
||||||
albumId: albumStub.sharedWithAdmin.id,
|
albumsId: albumStub.sharedWithAdmin.id,
|
||||||
});
|
});
|
||||||
expect(eventMock.emit).toHaveBeenCalledWith('album.invite', {
|
expect(eventMock.emit).toHaveBeenCalledWith('album.invite', {
|
||||||
id: albumStub.sharedWithAdmin.id,
|
id: albumStub.sharedWithAdmin.id,
|
||||||
@ -361,8 +359,8 @@ describe(AlbumService.name, () => {
|
|||||||
|
|
||||||
expect(albumUserMock.delete).toHaveBeenCalledTimes(1);
|
expect(albumUserMock.delete).toHaveBeenCalledTimes(1);
|
||||||
expect(albumUserMock.delete).toHaveBeenCalledWith({
|
expect(albumUserMock.delete).toHaveBeenCalledWith({
|
||||||
albumId: albumStub.sharedWithUser.id,
|
albumsId: albumStub.sharedWithUser.id,
|
||||||
userId: userStub.user1.id,
|
usersId: userStub.user1.id,
|
||||||
});
|
});
|
||||||
expect(albumMock.getById).toHaveBeenCalledWith(albumStub.sharedWithUser.id, { withAssets: false });
|
expect(albumMock.getById).toHaveBeenCalledWith(albumStub.sharedWithUser.id, { withAssets: false });
|
||||||
});
|
});
|
||||||
@ -388,8 +386,8 @@ describe(AlbumService.name, () => {
|
|||||||
|
|
||||||
expect(albumUserMock.delete).toHaveBeenCalledTimes(1);
|
expect(albumUserMock.delete).toHaveBeenCalledTimes(1);
|
||||||
expect(albumUserMock.delete).toHaveBeenCalledWith({
|
expect(albumUserMock.delete).toHaveBeenCalledWith({
|
||||||
albumId: albumStub.sharedWithUser.id,
|
albumsId: albumStub.sharedWithUser.id,
|
||||||
userId: authStub.user1.user.id,
|
usersId: authStub.user1.user.id,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -400,8 +398,8 @@ describe(AlbumService.name, () => {
|
|||||||
|
|
||||||
expect(albumUserMock.delete).toHaveBeenCalledTimes(1);
|
expect(albumUserMock.delete).toHaveBeenCalledTimes(1);
|
||||||
expect(albumUserMock.delete).toHaveBeenCalledWith({
|
expect(albumUserMock.delete).toHaveBeenCalledWith({
|
||||||
albumId: albumStub.sharedWithUser.id,
|
albumsId: albumStub.sharedWithUser.id,
|
||||||
userId: authStub.user1.user.id,
|
usersId: authStub.user1.user.id,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -433,7 +431,7 @@ describe(AlbumService.name, () => {
|
|||||||
role: AlbumUserRole.EDITOR,
|
role: AlbumUserRole.EDITOR,
|
||||||
});
|
});
|
||||||
expect(albumUserMock.update).toHaveBeenCalledWith(
|
expect(albumUserMock.update).toHaveBeenCalledWith(
|
||||||
{ albumId: albumStub.sharedWithAdmin.id, userId: userStub.admin.id },
|
{ albumsId: albumStub.sharedWithAdmin.id, usersId: userStub.admin.id },
|
||||||
{ role: AlbumUserRole.EDITOR },
|
{ role: AlbumUserRole.EDITOR },
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -229,7 +229,7 @@ export class AlbumService extends BaseService {
|
|||||||
throw new BadRequestException('User not found');
|
throw new BadRequestException('User not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.albumUserRepository.create({ userId, albumId: id, role });
|
await this.albumUserRepository.create({ usersId: userId, albumsId: id, role });
|
||||||
await this.eventRepository.emit('album.invite', { id, userId });
|
await this.eventRepository.emit('album.invite', { id, userId });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,12 +257,12 @@ export class AlbumService extends BaseService {
|
|||||||
await this.requireAccess({ auth, permission: Permission.ALBUM_SHARE, ids: [id] });
|
await this.requireAccess({ auth, permission: Permission.ALBUM_SHARE, ids: [id] });
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.albumUserRepository.delete({ albumId: id, userId });
|
await this.albumUserRepository.delete({ albumsId: id, usersId: userId });
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateUser(auth: AuthDto, id: string, userId: string, dto: Partial<AlbumUserEntity>): Promise<void> {
|
async updateUser(auth: AuthDto, id: string, userId: string, dto: Partial<AlbumUserEntity>): Promise<void> {
|
||||||
await this.requireAccess({ auth, permission: Permission.ALBUM_SHARE, ids: [id] });
|
await this.requireAccess({ auth, permission: Permission.ALBUM_SHARE, ids: [id] });
|
||||||
await this.albumUserRepository.update({ albumId: id, userId }, { role: dto.role });
|
await this.albumUserRepository.update({ albumsId: id, usersId: userId }, { role: dto.role });
|
||||||
}
|
}
|
||||||
|
|
||||||
private async findOrFail(id: string, options: AlbumInfoOptions) {
|
private async findOrFail(id: string, options: AlbumInfoOptions) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user