diff --git a/e2e/src/api/specs/memory.e2e-spec.ts b/e2e/src/api/specs/memory.e2e-spec.ts index a404da0ada..d91a570f77 100644 --- a/e2e/src/api/specs/memory.e2e-spec.ts +++ b/e2e/src/api/specs/memory.e2e-spec.ts @@ -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, diff --git a/server/src/dtos/memory.dto.ts b/server/src/dtos/memory.dto.ts index 5d2e13a9ad..194bb8ac38 100644 --- a/server/src/dtos/memory.dto.ts +++ b/server/src/dtos/memory.dto.ts @@ -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)), }; }; diff --git a/server/src/interfaces/memory.interface.ts b/server/src/interfaces/memory.interface.ts deleted file mode 100644 index 327822adc1..0000000000 --- a/server/src/interfaces/memory.interface.ts +++ /dev/null @@ -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; - get(id: string): Promise; - create( - memory: Omit, 'data'> & { data: OnThisDayData }, - assetIds: Set, - ): Promise; - update(id: string, memory: Updateable): Promise; - delete(id: string): Promise; -} diff --git a/server/src/repositories/index.ts b/server/src/repositories/index.ts index a041cfdb0b..ffc0d953d7 100644 --- a/server/src/repositories/index.ts +++ b/server/src/repositories/index.ts @@ -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 }, diff --git a/server/src/repositories/memory.repository.ts b/server/src/repositories/memory.repository.ts index 3a32e750b7..042738fe4c 100644 --- a/server/src/repositories/memory.repository.ts +++ b/server/src/repositories/memory.repository.ts @@ -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) {} @GenerateSql({ params: [DummyValue.UUID] }) - search(ownerId: string): Promise { + search(ownerId: string) { return this.db .selectFrom('memories') .selectAll() .where('ownerId', '=', ownerId) .orderBy('memoryAt', 'desc') - .execute() as Promise; + .execute(); } @GenerateSql({ params: [DummyValue.UUID] }) - get(id: string): Promise { - return this.getByIdBuilder(id).executeTakeFirst() as unknown as Promise; + get(id: string) { + return this.getByIdBuilder(id).executeTakeFirst(); } - async create(memory: Insertable, assetIds: Set): Promise { + async create(memory: Insertable, assetIds: Set) { 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; + return this.getByIdBuilder(id).executeTakeFirstOrThrow(); } @GenerateSql({ params: [DummyValue.UUID, { ownerId: DummyValue.UUID, isSaved: true }] }) - async update(id: string, memory: Updateable): Promise { + async update(id: string, memory: Updateable) { await this.db.updateTable('memories').set(memory).where('id', '=', id).execute(); - return this.getByIdBuilder(id).executeTakeFirstOrThrow() as unknown as Promise; + return this.getByIdBuilder(id).executeTakeFirstOrThrow(); } @GenerateSql({ params: [DummyValue.UUID] }) - async delete(id: string): Promise { + 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> { + async getAssetIds(id: string, assetIds: string[]) { if (assetIds.length === 0) { - return new Set(); + return new Set(); } 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 { + 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 { + async removeAssetIds(id: string, assetIds: string[]) { if (assetIds.length === 0) { return; } diff --git a/server/src/services/base.service.ts b/server/src/services/base.service.ts index 0ab7979c14..1a20b4c97e 100644 --- a/server/src/services/base.service.ts +++ b/server/src/services/base.service.ts @@ -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, diff --git a/server/src/services/memory.service.spec.ts b/server/src/services/memory.service.spec.ts index 9c5336eb6e..a5fa6a9cab 100644 --- a/server/src/services/memory.service.spec.ts +++ b/server/src/services/memory.service.spec.ts @@ -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'; diff --git a/server/src/services/memory.service.ts b/server/src/services/memory.service.ts index 926571e43c..e3aa1f3574 100644 --- a/server/src/services/memory.service.ts +++ b/server/src/services/memory.service.ts @@ -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, diff --git a/server/src/types.ts b/server/src/types.ts index 63bd8f8f05..42e1b8e94b 100644 --- a/server/src/types.ts +++ b/server/src/types.ts @@ -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 extends object ? { [K in keyof T]?: DeepPartial } : T; @@ -23,6 +24,7 @@ export type IAccessRepository = { [K in keyof AccessRepository]: RepositoryInter export type IApiKeyRepository = RepositoryInterface; export type IAuditRepository = RepositoryInterface; export type IConfigRepository = RepositoryInterface; +export type IMemoryRepository = RepositoryInterface; export type IViewRepository = RepositoryInterface; export type ActivityItem = @@ -33,3 +35,7 @@ export type ApiKeyItem = | Awaited> | NonNullable>> | Awaited>[0]; + +export type MemoryItem = + | Awaited> + | Awaited>[0]; diff --git a/server/test/fixtures/memory.stub.ts b/server/test/fixtures/memory.stub.ts index 50872d8ac1..5b3d5635c4 100644 --- a/server/test/fixtures/memory.stub.ts +++ b/server/test/fixtures/memory.stub.ts @@ -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: { + empty: { id: 'memoryEmpty', createdAt: new Date(), updatedAt: new Date(), @@ -15,8 +14,10 @@ export const memoryStub = { data: { year: 2024 }, isSaved: false, assets: [], - }, - memory1: { + 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, }; diff --git a/server/test/repositories/memory.repository.mock.ts b/server/test/repositories/memory.repository.mock.ts index fc3c968767..c818c29195 100644 --- a/server/test/repositories/memory.repository.mock.ts +++ b/server/test/repositories/memory.repository.mock.ts @@ -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 => { diff --git a/server/test/utils.ts b/server/test/utils.ts index a5537dcc2d..01fb1f7465 100644 --- a/server/test/utils.ts +++ b/server/test/utils.ts @@ -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 = ( machineLearningMock, mapMock, mediaMock, - memoryMock, + memoryMock as IMemoryRepository as MemoryRepository, metadataMock, moveMock, notificationMock,