feat: improve performance for GET /api/album & /api/album/:id (#17124)

* fix(server) optimize number of sql calls for GET /api/albums

remove unnecessary join for getMetadataForIds
remove separate call to getLastUpdatedAssetForAlbumId

* fix(server) remove unnecessary getLastUpdatedAssetForAlbumId call for GET /api/album/:id

also remove getLastUpdatedAssetForAlbumId query as it is no longer referenced

* fix(server): correct lastModifiedAssetTimestamp return type + formatting and typing

* chore(server): address type issue with tests found via npm:check

tests & lint still pass before this commit.
This commit is contained in:
PathToLife
2025-04-01 00:28:41 +13:00
committed by GitHub
parent 238c151ac3
commit 09f4476f97
6 changed files with 71 additions and 51 deletions

View File

@@ -12,6 +12,7 @@ export interface AlbumAssetCount {
assetCount: number;
startDate: Date | null;
endDate: Date | null;
lastModifiedAssetTimestamp: Date | null;
}
export interface AlbumInfoOptions {
@@ -132,18 +133,21 @@ export class AlbumRepository {
return [];
}
return this.db
.selectFrom('albums')
.innerJoin('albums_assets_assets as album_assets', 'album_assets.albumsId', 'albums.id')
.innerJoin('assets', 'assets.id', 'album_assets.assetsId')
.select('albums.id as albumId')
.select((eb) => eb.fn.min('assets.localDateTime').as('startDate'))
.select((eb) => eb.fn.max('assets.localDateTime').as('endDate'))
.select((eb) => sql<number>`${eb.fn.count('assets.id')}::int`.as('assetCount'))
.where('albums.id', 'in', ids)
.where('assets.deletedAt', 'is', null)
.groupBy('albums.id')
.execute();
return (
this.db
.selectFrom('assets')
.innerJoin('albums_assets_assets as album_assets', 'album_assets.assetsId', 'assets.id')
.select('album_assets.albumsId as albumId')
.select((eb) => eb.fn.min(sql<Date>`("assets"."localDateTime" AT TIME ZONE 'UTC'::text)::date`).as('startDate'))
.select((eb) => eb.fn.max(sql<Date>`("assets"."localDateTime" AT TIME ZONE 'UTC'::text)::date`).as('endDate'))
// lastModifiedAssetTimestamp is only used in mobile app, please remove if not need
.select((eb) => eb.fn.max('assets.updatedAt').as('lastModifiedAssetTimestamp'))
.select((eb) => sql<number>`${eb.fn.count('assets.id')}::int`.as('assetCount'))
.where('album_assets.albumsId', 'in', ids)
.where('assets.deletedAt', 'is', null)
.groupBy('album_assets.albumsId')
.execute()
);
}
@GenerateSql({ params: [DummyValue.UUID] })

View File

@@ -728,17 +728,6 @@ export class AssetRepository {
return paginationHelper(items as any as AssetEntity[], pagination.take);
}
getLastUpdatedAssetForAlbumId(albumId: string): Promise<AssetEntity | undefined> {
return this.db
.selectFrom('assets')
.selectAll('assets')
.innerJoin('albums_assets_assets', 'assets.id', 'albums_assets_assets.assetsId')
.where('albums_assets_assets.albumsId', '=', asUuid(albumId))
.orderBy('updatedAt', 'desc')
.limit(1)
.executeTakeFirst() as Promise<AssetEntity | undefined>;
}
getStatistics(ownerId: string, { isArchived, isFavorite, isTrashed }: AssetStatsOptions): Promise<AssetStats> {
return this.db
.selectFrom('assets')