diff --git a/server/src/interfaces/asset.interface.ts b/server/src/interfaces/asset.interface.ts index 1b32c57d41..b25e42ba0e 100644 --- a/server/src/interfaces/asset.interface.ts +++ b/server/src/interfaces/asset.interface.ts @@ -146,6 +146,11 @@ export interface UpsertFileOptions { export type AssetPathEntity = Pick; +export interface DayOfYearAssets { + yearsAgo: number; + assets: AssetEntity[]; +} + export const IAssetRepository = 'IAssetRepository'; export interface IAssetRepository { @@ -156,7 +161,7 @@ export interface IAssetRepository { select?: FindOptionsSelect, ): Promise; getByIdsWithAllRelations(ids: string[]): Promise; - getByDayOfYear(ownerIds: string[], monthDay: MonthDay): Promise; + getByDayOfYear(ownerIds: string[], monthDay: MonthDay): Promise; getByChecksum(options: { ownerId: string; checksum: Buffer; libraryId?: string }): Promise; getByChecksums(userId: string, checksums: Buffer[]): Promise; getUploadAssetIdByChecksum(ownerId: string, checksum: Buffer): Promise; diff --git a/server/src/queries/asset.repository.sql b/server/src/queries/asset.repository.sql index e7f5b558b0..f4b1b2fea1 100644 --- a/server/src/queries/asset.repository.sql +++ b/server/src/queries/asset.repository.sql @@ -68,22 +68,19 @@ SELECT FROM "assets" "entity" LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "entity"."id" - LEFT JOIN "asset_files" "files" ON "files"."assetId" = "entity"."id" + INNER JOIN "asset_files" "files" ON "files"."assetId" = "entity"."id" WHERE ( - "entity"."ownerId" IN ($1) - AND "entity"."isVisible" = true - AND "entity"."isArchived" = false + "files"."type" = $1 AND EXTRACT( - DAY + YEAR + FROM + CURRENT_DATE AT TIME ZONE 'UTC' + ) - EXTRACT( + YEAR FROM "entity"."localDateTime" AT TIME ZONE 'UTC' - ) = $2 - AND EXTRACT( - MONTH - FROM - "entity"."localDateTime" AT TIME ZONE 'UTC' - ) = $3 + ) > 0 ) AND ("entity"."deletedAt" IS NULL) ORDER BY diff --git a/server/src/repositories/asset.repository.ts b/server/src/repositories/asset.repository.ts index ce7d257b40..b3066a37bc 100644 --- a/server/src/repositories/asset.repository.ts +++ b/server/src/repositories/asset.repository.ts @@ -17,6 +17,7 @@ import { AssetUpdateAllOptions, AssetUpdateDuplicateOptions, AssetUpdateOptions, + DayOfYearAssets, IAssetRepository, LivePhotoSearchOptions, MonthDay, @@ -74,8 +75,8 @@ export class AssetRepository implements IAssetRepository { } @GenerateSql({ params: [[DummyValue.UUID], { day: 1, month: 1 }] }) - getByDayOfYear(ownerIds: string[], { day, month }: MonthDay): Promise { - return this.repository + async getByDayOfYear(ownerIds: string[], { day, month }: MonthDay): Promise { + const assets = await this.repository .createQueryBuilder('entity') .where( `entity.ownerId IN (:...ownerIds) @@ -90,9 +91,25 @@ export class AssetRepository implements IAssetRepository { }, ) .leftJoinAndSelect('entity.exifInfo', 'exifInfo') - .leftJoinAndSelect('entity.files', 'files') + .innerJoinAndSelect('entity.files', 'files') + .where('files.type = :type', { type: AssetFileType.THUMBNAIL }) + .andWhere( + `EXTRACT(YEAR FROM CURRENT_DATE AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM entity.localDateTime AT TIME ZONE 'UTC') > 0`, + ) .orderBy('entity.fileCreatedAt', 'ASC') .getMany(); + + const groups: Record = {}; + const currentYear = new Date().getFullYear(); + for (const asset of assets) { + const yearsAgo = currentYear - asset.localDateTime.getFullYear(); + if (!groups[yearsAgo]) { + groups[yearsAgo] = { yearsAgo, assets: [] }; + } + groups[yearsAgo].assets.push(asset); + } + + return Object.values(groups); } @GenerateSql({ params: [[DummyValue.UUID]] }) diff --git a/server/src/services/asset.service.spec.ts b/server/src/services/asset.service.spec.ts index 9063df9dc2..5aab5032af 100755 --- a/server/src/services/asset.service.spec.ts +++ b/server/src/services/asset.service.spec.ts @@ -80,7 +80,20 @@ describe(AssetService.name, () => { const image4 = { ...assetStub.image, localDateTime: new Date(2009, 1, 15) }; partnerMock.getAll.mockResolvedValue([]); - assetMock.getByDayOfYear.mockResolvedValue([image1, image2, image3, image4]); + assetMock.getByDayOfYear.mockResolvedValue([ + { + yearsAgo: 1, + assets: [image1, image2], + }, + { + yearsAgo: 9, + assets: [image3], + }, + { + yearsAgo: 15, + assets: [image4], + }, + ]); await expect(sut.getMemoryLane(authStub.admin, { day: 15, month: 1 })).resolves.toEqual([ { yearsAgo: 1, title: '1 year ago', assets: [mapAsset(image1), mapAsset(image2)] }, diff --git a/server/src/services/asset.service.ts b/server/src/services/asset.service.ts index 98d6ec00f6..8751037119 100644 --- a/server/src/services/asset.service.ts +++ b/server/src/services/asset.service.ts @@ -43,28 +43,13 @@ export class AssetService extends BaseService { }); const userIds = [auth.user.id, ...partnerIds]; - const assets = await this.assetRepository.getByDayOfYear(userIds, dto); - const assetsWithThumbnails = assets.filter(({ files }) => !!getAssetFiles(files).thumbnailFile); - const groups: Record = {}; - const currentYear = new Date().getFullYear(); - for (const asset of assetsWithThumbnails) { - const yearsAgo = currentYear - asset.localDateTime.getFullYear(); - if (!groups[yearsAgo]) { - groups[yearsAgo] = []; - } - groups[yearsAgo].push(asset); - } - - return Object.keys(groups) - .map(Number) - .sort((a, b) => a - b) - .filter((yearsAgo) => yearsAgo > 0) - .map((yearsAgo) => ({ - yearsAgo, - // TODO move this to clients - title: `${yearsAgo} year${yearsAgo > 1 ? 's' : ''} ago`, - assets: groups[yearsAgo].map((asset) => mapAsset(asset, { auth })), - })); + const groups = await this.assetRepository.getByDayOfYear(userIds, dto); + return groups.map(({ yearsAgo, assets }) => ({ + yearsAgo, + // TODO move this to clients + title: `${yearsAgo} year${yearsAgo > 1 ? 's' : ''} ago`, + assets: assets.map((asset) => mapAsset(asset, { auth })), + })); } async getStatistics(auth: AuthDto, dto: AssetStatsDto) {