From a3a2ced3a99a4632126c075dc58828e81905cc8d Mon Sep 17 00:00:00 2001 From: mertalev <101130780+mertalev@users.noreply.github.com> Date: Sun, 4 May 2025 20:11:48 -0400 Subject: [PATCH] stack as tuple --- server/src/dtos/time-bucket.dto.ts | 15 +++++++++++---- server/src/repositories/asset.repository.ts | 12 ++++-------- server/src/services/timeline.service.types.ts | 3 +-- web/src/lib/stores/assets-store.svelte.ts | 6 +++--- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/server/src/dtos/time-bucket.dto.ts b/server/src/dtos/time-bucket.dto.ts index 5703ea7707..45689d12d1 100644 --- a/server/src/dtos/time-bucket.dto.ts +++ b/server/src/dtos/time-bucket.dto.ts @@ -83,10 +83,17 @@ export class TimeBucketAssetResponseDto implements TimeBucketAssets { @ApiProperty({ type: 'array', items: { type: 'string', nullable: true } }) duration!: (string | null)[]; - stackCount?: number[]; - - @ApiProperty({ type: 'array', items: { type: 'string', nullable: true } }) - stackId?: (string | null)[]; + // id, count + @ApiProperty({ + type: 'array', + items: { + type: 'array', + nullable: true, + items: { oneOf: [{ type: 'string' }, { type: 'number' }], minItems: 2, maxItems: 2 }, + }, + description: 'The stack ID and stack asset count as a tuple', + }) + stack?: ([string, number] | null)[]; @ApiProperty({ type: 'array', items: { type: 'string', nullable: true } }) projectionType!: (string | null)[]; diff --git a/server/src/repositories/asset.repository.ts b/server/src/repositories/asset.repository.ts index f3e40a5598..d191639fa7 100644 --- a/server/src/repositories/asset.repository.ts +++ b/server/src/repositories/asset.repository.ts @@ -652,14 +652,15 @@ export class AssetRepository { (eb) => eb .selectFrom('assets as stacked') - .select((eb) => eb.fn.coalesce(eb.fn.count(eb.table('stacked')), eb.lit(0)).as('stackCount')) + .select(sql`json_build_array(stacked."stackId", count('stacked'))`.as('stack')) .whereRef('stacked.stackId', '=', 'assets.stackId') .where('stacked.deletedAt', 'is', null) .where('stacked.isArchived', '=', false) + .groupBy('stacked.stackId') .as('stacked_assets'), (join) => join.onTrue(), ) - .select(['assets.stackId', 'stackCount']), + .select('stack'), ) .$if(!!options.assetType, (qb) => qb.where('assets.type', '=', options.assetType!)) .$if(options.isDuplicate !== undefined, (qb) => @@ -690,12 +691,7 @@ export class AssetRepository { eb.fn.coalesce(eb.fn('array_agg', ['status']), sql.lit('{}')).as('status'), eb.fn.coalesce(eb.fn('array_agg', ['thumbhash']), sql.lit('{}')).as('thumbhash'), ]) - .$if(!!options.withStacked, (qb) => - qb.select((eb) => [ - eb.fn('array_agg', ['stackCount']).as('stackCount'), - eb.fn('array_agg', ['stackId']).as('stackId'), - ]), - ), + .$if(!!options.withStacked, (qb) => qb.select((eb) => eb.fn('array_agg', ['stack']).as('stack'))), ) .selectFrom('agg') .select(sql`to_json(agg)::text`.as('assets')); diff --git a/server/src/services/timeline.service.types.ts b/server/src/services/timeline.service.types.ts index 4bf1f77b3b..06eb378b6a 100644 --- a/server/src/services/timeline.service.types.ts +++ b/server/src/services/timeline.service.types.ts @@ -19,8 +19,7 @@ export type TimeBucketAssets = { isImage: number[]; thumbhash: (string | null)[]; localDateTime: string[]; - stackCount?: number[]; - stackId?: (string | null)[]; + stack?: ([string, number] | null)[]; duration: (string | null)[]; projectionType: (string | null)[]; livePhotoVideoId: (string | null)[]; diff --git a/web/src/lib/stores/assets-store.svelte.ts b/web/src/lib/stores/assets-store.svelte.ts index 2990724efa..684d39155d 100644 --- a/web/src/lib/stores/assets-store.svelte.ts +++ b/web/src/lib/stores/assets-store.svelte.ts @@ -437,11 +437,11 @@ export class AssetBucket { people: [], projectionType: bucketAssets.projectionType[i], ratio: bucketAssets.ratio[i], - stack: bucketAssets.stackId?.[i] + stack: bucketAssets.stack?.[i] ? { - id: bucketAssets.stackId[i]!, + id: bucketAssets.stack[i]![0] as string, primaryAssetId: bucketAssets.id[i], - assetCount: bucketAssets.stackCount![i], + assetCount: bucketAssets.stack[i]![1] as number, } : null, thumbhash: bucketAssets.thumbhash[i],