mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 10:37:11 -04:00 
			
		
		
		
	refactor(server): move filters to getByDayOfYear query (#14628)
move filters to getByDayOfYear query
This commit is contained in:
		
							parent
							
								
									25ca3b1124
								
							
						
					
					
						commit
						9eff1c4b34
					
				| @ -146,6 +146,11 @@ export interface UpsertFileOptions { | ||||
| 
 | ||||
| export type AssetPathEntity = Pick<AssetEntity, 'id' | 'originalPath' | 'isOffline'>; | ||||
| 
 | ||||
| export interface DayOfYearAssets { | ||||
|   yearsAgo: number; | ||||
|   assets: AssetEntity[]; | ||||
| } | ||||
| 
 | ||||
| export const IAssetRepository = 'IAssetRepository'; | ||||
| 
 | ||||
| export interface IAssetRepository { | ||||
| @ -156,7 +161,7 @@ export interface IAssetRepository { | ||||
|     select?: FindOptionsSelect<AssetEntity>, | ||||
|   ): Promise<AssetEntity[]>; | ||||
|   getByIdsWithAllRelations(ids: string[]): Promise<AssetEntity[]>; | ||||
|   getByDayOfYear(ownerIds: string[], monthDay: MonthDay): Promise<AssetEntity[]>; | ||||
|   getByDayOfYear(ownerIds: string[], monthDay: MonthDay): Promise<DayOfYearAssets[]>; | ||||
|   getByChecksum(options: { ownerId: string; checksum: Buffer; libraryId?: string }): Promise<AssetEntity | null>; | ||||
|   getByChecksums(userId: string, checksums: Buffer[]): Promise<AssetEntity[]>; | ||||
|   getUploadAssetIdByChecksum(ownerId: string, checksum: Buffer): Promise<string | undefined>; | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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<AssetEntity[]> { | ||||
|     return this.repository | ||||
|   async getByDayOfYear(ownerIds: string[], { day, month }: MonthDay): Promise<DayOfYearAssets[]> { | ||||
|     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<number, DayOfYearAssets> = {}; | ||||
|     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]] }) | ||||
|  | ||||
| @ -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)] }, | ||||
|  | ||||
| @ -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<number, AssetEntity[]> = {}; | ||||
|     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) { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user