mirror of
https://github.com/immich-app/immich.git
synced 2025-03-11 02:23:09 -05:00
refactor: migrate memory repository (#15532)
This commit is contained in:
parent
ca3619658b
commit
1f19a65d1a
12 changed files with 47 additions and 55 deletions
|
@ -93,8 +93,6 @@ describe('/memories', () => {
|
|||
data: { year: 2021 },
|
||||
createdAt: expect.any(String),
|
||||
updatedAt: expect.any(String),
|
||||
deletedAt: null,
|
||||
seenAt: null,
|
||||
isSaved: false,
|
||||
memoryAt: expect.any(String),
|
||||
ownerId: user.userId,
|
||||
|
|
|
@ -2,8 +2,9 @@ import { ApiProperty } from '@nestjs/swagger';
|
|||
import { Type } from 'class-transformer';
|
||||
import { IsEnum, IsInt, IsObject, IsPositive, ValidateNested } from 'class-validator';
|
||||
import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto';
|
||||
import { MemoryEntity } from 'src/entities/memory.entity';
|
||||
import { AssetEntity } from 'src/entities/asset.entity';
|
||||
import { MemoryType } from 'src/enum';
|
||||
import { MemoryItem } from 'src/types';
|
||||
import { ValidateBoolean, ValidateDate, ValidateUUID } from 'src/validation';
|
||||
|
||||
class MemoryBaseDto {
|
||||
|
@ -69,18 +70,18 @@ export class MemoryResponseDto {
|
|||
assets!: AssetResponseDto[];
|
||||
}
|
||||
|
||||
export const mapMemory = (entity: MemoryEntity): MemoryResponseDto => {
|
||||
export const mapMemory = (entity: MemoryItem): MemoryResponseDto => {
|
||||
return {
|
||||
id: entity.id,
|
||||
createdAt: entity.createdAt,
|
||||
updatedAt: entity.updatedAt,
|
||||
deletedAt: entity.deletedAt,
|
||||
deletedAt: entity.deletedAt ?? undefined,
|
||||
memoryAt: entity.memoryAt,
|
||||
seenAt: entity.seenAt,
|
||||
seenAt: entity.seenAt ?? undefined,
|
||||
ownerId: entity.ownerId,
|
||||
type: entity.type,
|
||||
data: entity.data,
|
||||
type: entity.type as MemoryType,
|
||||
data: entity.data as unknown as MemoryData,
|
||||
isSaved: entity.isSaved,
|
||||
assets: entity.assets.map((asset) => mapAsset(asset)),
|
||||
assets: ('assets' in entity ? entity.assets : []).map((asset) => mapAsset(asset as AssetEntity)),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
import { Insertable, Updateable } from 'kysely';
|
||||
import { Memories } from 'src/db';
|
||||
import { MemoryEntity, OnThisDayData } from 'src/entities/memory.entity';
|
||||
import { IBulkAsset } from 'src/utils/asset.util';
|
||||
|
||||
export const IMemoryRepository = 'IMemoryRepository';
|
||||
|
||||
export interface IMemoryRepository extends IBulkAsset {
|
||||
search(ownerId: string): Promise<MemoryEntity[]>;
|
||||
get(id: string): Promise<MemoryEntity | undefined>;
|
||||
create(
|
||||
memory: Omit<Insertable<Memories>, 'data'> & { data: OnThisDayData },
|
||||
assetIds: Set<string>,
|
||||
): Promise<MemoryEntity>;
|
||||
update(id: string, memory: Updateable<Memories>): Promise<MemoryEntity>;
|
||||
delete(id: string): Promise<void>;
|
||||
}
|
|
@ -11,7 +11,6 @@ import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
|||
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
|
||||
import { IMapRepository } from 'src/interfaces/map.interface';
|
||||
import { IMediaRepository } from 'src/interfaces/media.interface';
|
||||
import { IMemoryRepository } from 'src/interfaces/memory.interface';
|
||||
import { IMetadataRepository } from 'src/interfaces/metadata.interface';
|
||||
import { IMoveRepository } from 'src/interfaces/move.interface';
|
||||
import { INotificationRepository } from 'src/interfaces/notification.interface';
|
||||
|
@ -78,6 +77,7 @@ export const repositories = [
|
|||
AuditRepository,
|
||||
ApiKeyRepository,
|
||||
ConfigRepository,
|
||||
MemoryRepository,
|
||||
ViewRepository,
|
||||
];
|
||||
|
||||
|
@ -95,7 +95,6 @@ export const providers = [
|
|||
{ provide: IMachineLearningRepository, useClass: MachineLearningRepository },
|
||||
{ provide: IMapRepository, useClass: MapRepository },
|
||||
{ provide: IMediaRepository, useClass: MediaRepository },
|
||||
{ provide: IMemoryRepository, useClass: MemoryRepository },
|
||||
{ provide: IMetadataRepository, useClass: MetadataRepository },
|
||||
{ provide: IMoveRepository, useClass: MoveRepository },
|
||||
{ provide: INotificationRepository, useClass: NotificationRepository },
|
||||
|
|
|
@ -4,29 +4,28 @@ import { jsonArrayFrom } from 'kysely/helpers/postgres';
|
|||
import { InjectKysely } from 'nestjs-kysely';
|
||||
import { DB, Memories } from 'src/db';
|
||||
import { Chunked, ChunkedSet, DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { MemoryEntity } from 'src/entities/memory.entity';
|
||||
import { IMemoryRepository } from 'src/interfaces/memory.interface';
|
||||
import { IBulkAsset } from 'src/utils/asset.util';
|
||||
|
||||
@Injectable()
|
||||
export class MemoryRepository implements IMemoryRepository {
|
||||
export class MemoryRepository implements IBulkAsset {
|
||||
constructor(@InjectKysely() private db: Kysely<DB>) {}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID] })
|
||||
search(ownerId: string): Promise<MemoryEntity[]> {
|
||||
search(ownerId: string) {
|
||||
return this.db
|
||||
.selectFrom('memories')
|
||||
.selectAll()
|
||||
.where('ownerId', '=', ownerId)
|
||||
.orderBy('memoryAt', 'desc')
|
||||
.execute() as Promise<MemoryEntity[]>;
|
||||
.execute();
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID] })
|
||||
get(id: string): Promise<MemoryEntity | undefined> {
|
||||
return this.getByIdBuilder(id).executeTakeFirst() as unknown as Promise<MemoryEntity | undefined>;
|
||||
get(id: string) {
|
||||
return this.getByIdBuilder(id).executeTakeFirst();
|
||||
}
|
||||
|
||||
async create(memory: Insertable<Memories>, assetIds: Set<string>): Promise<MemoryEntity> {
|
||||
async create(memory: Insertable<Memories>, assetIds: Set<string>) {
|
||||
const id = await this.db.transaction().execute(async (tx) => {
|
||||
const { id } = await tx.insertInto('memories').values(memory).returning('id').executeTakeFirstOrThrow();
|
||||
|
||||
|
@ -38,25 +37,25 @@ export class MemoryRepository implements IMemoryRepository {
|
|||
return id;
|
||||
});
|
||||
|
||||
return this.getByIdBuilder(id).executeTakeFirstOrThrow() as unknown as Promise<MemoryEntity>;
|
||||
return this.getByIdBuilder(id).executeTakeFirstOrThrow();
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID, { ownerId: DummyValue.UUID, isSaved: true }] })
|
||||
async update(id: string, memory: Updateable<Memories>): Promise<MemoryEntity> {
|
||||
async update(id: string, memory: Updateable<Memories>) {
|
||||
await this.db.updateTable('memories').set(memory).where('id', '=', id).execute();
|
||||
return this.getByIdBuilder(id).executeTakeFirstOrThrow() as unknown as Promise<MemoryEntity>;
|
||||
return this.getByIdBuilder(id).executeTakeFirstOrThrow();
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID] })
|
||||
async delete(id: string): Promise<void> {
|
||||
async delete(id: string) {
|
||||
await this.db.deleteFrom('memories').where('id', '=', id).execute();
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
|
||||
@ChunkedSet({ paramIndex: 1 })
|
||||
async getAssetIds(id: string, assetIds: string[]): Promise<Set<string>> {
|
||||
async getAssetIds(id: string, assetIds: string[]) {
|
||||
if (assetIds.length === 0) {
|
||||
return new Set();
|
||||
return new Set<string>();
|
||||
}
|
||||
|
||||
const results = await this.db
|
||||
|
@ -70,7 +69,7 @@ export class MemoryRepository implements IMemoryRepository {
|
|||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
|
||||
async addAssetIds(id: string, assetIds: string[]): Promise<void> {
|
||||
async addAssetIds(id: string, assetIds: string[]) {
|
||||
if (assetIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -83,7 +82,7 @@ export class MemoryRepository implements IMemoryRepository {
|
|||
|
||||
@Chunked({ paramIndex: 1 })
|
||||
@GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
|
||||
async removeAssetIds(id: string, assetIds: string[]): Promise<void> {
|
||||
async removeAssetIds(id: string, assetIds: string[]) {
|
||||
if (assetIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
|||
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
|
||||
import { IMapRepository } from 'src/interfaces/map.interface';
|
||||
import { IMediaRepository } from 'src/interfaces/media.interface';
|
||||
import { IMemoryRepository } from 'src/interfaces/memory.interface';
|
||||
import { IMetadataRepository } from 'src/interfaces/metadata.interface';
|
||||
import { IMoveRepository } from 'src/interfaces/move.interface';
|
||||
import { INotificationRepository } from 'src/interfaces/notification.interface';
|
||||
|
@ -44,6 +43,7 @@ import { ActivityRepository } from 'src/repositories/activity.repository';
|
|||
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
||||
import { AuditRepository } from 'src/repositories/audit.repository';
|
||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||
import { MemoryRepository } from 'src/repositories/memory.repository';
|
||||
import { ViewRepository } from 'src/repositories/view-repository';
|
||||
import { AccessRequest, checkAccess, requireAccess } from 'src/utils/access';
|
||||
import { getConfig, updateConfig } from 'src/utils/config';
|
||||
|
@ -70,7 +70,7 @@ export class BaseService {
|
|||
@Inject(IMachineLearningRepository) protected machineLearningRepository: IMachineLearningRepository,
|
||||
@Inject(IMapRepository) protected mapRepository: IMapRepository,
|
||||
@Inject(IMediaRepository) protected mediaRepository: IMediaRepository,
|
||||
@Inject(IMemoryRepository) protected memoryRepository: IMemoryRepository,
|
||||
protected memoryRepository: MemoryRepository,
|
||||
@Inject(IMetadataRepository) protected metadataRepository: IMetadataRepository,
|
||||
@Inject(IMoveRepository) protected moveRepository: IMoveRepository,
|
||||
@Inject(INotificationRepository) protected notificationRepository: INotificationRepository,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { BadRequestException } from '@nestjs/common';
|
||||
import { MemoryType } from 'src/enum';
|
||||
import { IMemoryRepository } from 'src/interfaces/memory.interface';
|
||||
import { MemoryService } from 'src/services/memory.service';
|
||||
import { IMemoryRepository } from 'src/types';
|
||||
import { authStub } from 'test/fixtures/auth.stub';
|
||||
import { memoryStub } from 'test/fixtures/memory.stub';
|
||||
import { userStub } from 'test/fixtures/user.stub';
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import { JsonObject } from 'src/db';
|
||||
import { BulkIdResponseDto, BulkIdsDto } from 'src/dtos/asset-ids.response.dto';
|
||||
import { AuthDto } from 'src/dtos/auth.dto';
|
||||
import { MemoryCreateDto, MemoryResponseDto, MemoryUpdateDto, mapMemory } from 'src/dtos/memory.dto';
|
||||
|
@ -32,7 +33,7 @@ export class MemoryService extends BaseService {
|
|||
{
|
||||
ownerId: auth.user.id,
|
||||
type: dto.type,
|
||||
data: dto.data,
|
||||
data: dto.data as unknown as JsonObject,
|
||||
isSaved: dto.isSaved,
|
||||
memoryAt: dto.memoryAt,
|
||||
seenAt: dto.seenAt,
|
||||
|
|
|
@ -5,6 +5,7 @@ import { ActivityRepository } from 'src/repositories/activity.repository';
|
|||
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
||||
import { AuditRepository } from 'src/repositories/audit.repository';
|
||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||
import { MemoryRepository } from 'src/repositories/memory.repository';
|
||||
import { ViewRepository } from 'src/repositories/view-repository';
|
||||
|
||||
export type DeepPartial<T> = T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T;
|
||||
|
@ -23,6 +24,7 @@ export type IAccessRepository = { [K in keyof AccessRepository]: RepositoryInter
|
|||
export type IApiKeyRepository = RepositoryInterface<ApiKeyRepository>;
|
||||
export type IAuditRepository = RepositoryInterface<AuditRepository>;
|
||||
export type IConfigRepository = RepositoryInterface<ConfigRepository>;
|
||||
export type IMemoryRepository = RepositoryInterface<MemoryRepository>;
|
||||
export type IViewRepository = RepositoryInterface<ViewRepository>;
|
||||
|
||||
export type ActivityItem =
|
||||
|
@ -33,3 +35,7 @@ export type ApiKeyItem =
|
|||
| Awaited<ReturnType<IApiKeyRepository['create']>>
|
||||
| NonNullable<Awaited<ReturnType<IApiKeyRepository['getById']>>>
|
||||
| Awaited<ReturnType<IApiKeyRepository['getByUserId']>>[0];
|
||||
|
||||
export type MemoryItem =
|
||||
| Awaited<ReturnType<IMemoryRepository['create']>>
|
||||
| Awaited<ReturnType<IMemoryRepository['search']>>[0];
|
||||
|
|
13
server/test/fixtures/memory.stub.ts
vendored
13
server/test/fixtures/memory.stub.ts
vendored
|
@ -1,10 +1,9 @@
|
|||
import { MemoryEntity } from 'src/entities/memory.entity';
|
||||
import { MemoryType } from 'src/enum';
|
||||
import { assetStub } from 'test/fixtures/asset.stub';
|
||||
import { userStub } from 'test/fixtures/user.stub';
|
||||
|
||||
export const memoryStub = {
|
||||
empty: <MemoryEntity>{
|
||||
empty: {
|
||||
id: 'memoryEmpty',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
|
@ -15,8 +14,10 @@ export const memoryStub = {
|
|||
data: { year: 2024 },
|
||||
isSaved: false,
|
||||
assets: [],
|
||||
},
|
||||
memory1: <MemoryEntity>{
|
||||
deletedAt: null,
|
||||
seenAt: null,
|
||||
} as unknown as any,
|
||||
memory1: {
|
||||
id: 'memory1',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
|
@ -27,5 +28,7 @@ export const memoryStub = {
|
|||
data: { year: 2024 },
|
||||
isSaved: false,
|
||||
assets: [assetStub.image1],
|
||||
},
|
||||
deletedAt: null,
|
||||
seenAt: null,
|
||||
} as unknown as any,
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { IMemoryRepository } from 'src/interfaces/memory.interface';
|
||||
import { IMemoryRepository } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newMemoryRepositoryMock = (): Mocked<IMemoryRepository> => {
|
||||
|
|
|
@ -7,6 +7,7 @@ import { AccessRepository } from 'src/repositories/access.repository';
|
|||
import { ActivityRepository } from 'src/repositories/activity.repository';
|
||||
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
||||
import { AuditRepository } from 'src/repositories/audit.repository';
|
||||
import { MemoryRepository } from 'src/repositories/memory.repository';
|
||||
import { ViewRepository } from 'src/repositories/view-repository';
|
||||
import { BaseService } from 'src/services/base.service';
|
||||
import {
|
||||
|
@ -14,6 +15,7 @@ import {
|
|||
IActivityRepository,
|
||||
IApiKeyRepository,
|
||||
IAuditRepository,
|
||||
IMemoryRepository,
|
||||
IViewRepository,
|
||||
} from 'src/types';
|
||||
import { newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
|
||||
|
@ -132,7 +134,7 @@ export const newTestService = <T extends BaseService>(
|
|||
machineLearningMock,
|
||||
mapMock,
|
||||
mediaMock,
|
||||
memoryMock,
|
||||
memoryMock as IMemoryRepository as MemoryRepository,
|
||||
metadataMock,
|
||||
moveMock,
|
||||
notificationMock,
|
||||
|
|
Loading…
Add table
Reference in a new issue