From 71cc045405bef25801ae454d56289dd851491f0d Mon Sep 17 00:00:00 2001 From: mertalev <101130780+mertalev@users.noreply.github.com> Date: Mon, 5 May 2025 10:33:48 -0400 Subject: [PATCH] string tuple --- mobile/openapi/README.md | 1 - mobile/openapi/lib/api.dart | 1 - mobile/openapi/lib/api_client.dart | 2 - .../model/time_bucket_asset_response_dto.dart | 12 +-- ..._asset_response_dto_stack_inner_inner.dart | 91 ------------------- open-api/immich-openapi-specs.json | 18 +--- open-api/typescript-sdk/src/fetch-client.ts | 4 +- server/src/dtos/time-bucket.dto.ts | 9 +- server/src/queries/asset.repository.sql | 2 +- server/src/repositories/asset.repository.ts | 2 +- server/src/services/timeline.service.types.ts | 2 +- web/src/lib/stores/assets-store.svelte.ts | 4 +- 12 files changed, 21 insertions(+), 127 deletions(-) delete mode 100644 mobile/openapi/lib/model/time_bucket_asset_response_dto_stack_inner_inner.dart diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index a2b3e35ba8..452a302db1 100644 --- a/mobile/openapi/README.md +++ b/mobile/openapi/README.md @@ -478,7 +478,6 @@ Class | Method | HTTP request | Description - [TemplateResponseDto](doc//TemplateResponseDto.md) - [TestEmailResponseDto](doc//TestEmailResponseDto.md) - [TimeBucketAssetResponseDto](doc//TimeBucketAssetResponseDto.md) - - [TimeBucketAssetResponseDtoStackInnerInner](doc//TimeBucketAssetResponseDtoStackInnerInner.md) - [TimeBucketsResponseDto](doc//TimeBucketsResponseDto.md) - [ToneMapping](doc//ToneMapping.md) - [TranscodeHWAccel](doc//TranscodeHWAccel.md) diff --git a/mobile/openapi/lib/api.dart b/mobile/openapi/lib/api.dart index 72c2c51d4d..06086a5749 100644 --- a/mobile/openapi/lib/api.dart +++ b/mobile/openapi/lib/api.dart @@ -282,7 +282,6 @@ part 'model/template_dto.dart'; part 'model/template_response_dto.dart'; part 'model/test_email_response_dto.dart'; part 'model/time_bucket_asset_response_dto.dart'; -part 'model/time_bucket_asset_response_dto_stack_inner_inner.dart'; part 'model/time_buckets_response_dto.dart'; part 'model/tone_mapping.dart'; part 'model/transcode_hw_accel.dart'; diff --git a/mobile/openapi/lib/api_client.dart b/mobile/openapi/lib/api_client.dart index 2b96c15f9e..f9ae2c9d07 100644 --- a/mobile/openapi/lib/api_client.dart +++ b/mobile/openapi/lib/api_client.dart @@ -620,8 +620,6 @@ class ApiClient { return TestEmailResponseDto.fromJson(value); case 'TimeBucketAssetResponseDto': return TimeBucketAssetResponseDto.fromJson(value); - case 'TimeBucketAssetResponseDtoStackInnerInner': - return TimeBucketAssetResponseDtoStackInnerInner.fromJson(value); case 'TimeBucketsResponseDto': return TimeBucketsResponseDto.fromJson(value); case 'ToneMapping': diff --git a/mobile/openapi/lib/model/time_bucket_asset_response_dto.dart b/mobile/openapi/lib/model/time_bucket_asset_response_dto.dart index 529d560fbc..fbeebb1c8e 100644 --- a/mobile/openapi/lib/model/time_bucket_asset_response_dto.dart +++ b/mobile/openapi/lib/model/time_bucket_asset_response_dto.dart @@ -56,8 +56,8 @@ class TimeBucketAssetResponseDto { List ratio; - /// The stack ID and stack asset count as a tuple - List> stack; + /// (stack ID, stack asset count) tuple + List stack; List thumbhash; @@ -169,11 +169,9 @@ class TimeBucketAssetResponseDto { ratio: json[r'ratio'] is Iterable ? (json[r'ratio'] as Iterable).cast().toList(growable: false) : const [], - stack: json[r'stack'] is List - ? (json[r'stack'] as List).map((e) => - TimeBucketAssetResponseDtoStackInnerInner.listFromJson(json[r'stack']) - ).toList() - : const [], + stack: json[r'stack'] is Iterable + ? (json[r'stack'] as Iterable).cast().toList(growable: false) + : const [], thumbhash: json[r'thumbhash'] is Iterable ? (json[r'thumbhash'] as Iterable).cast().toList(growable: false) : const [], diff --git a/mobile/openapi/lib/model/time_bucket_asset_response_dto_stack_inner_inner.dart b/mobile/openapi/lib/model/time_bucket_asset_response_dto_stack_inner_inner.dart deleted file mode 100644 index bc594176cd..0000000000 --- a/mobile/openapi/lib/model/time_bucket_asset_response_dto_stack_inner_inner.dart +++ /dev/null @@ -1,91 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.18 - -// ignore_for_file: unused_element, unused_import -// ignore_for_file: always_put_required_named_parameters_first -// ignore_for_file: constant_identifier_names -// ignore_for_file: lines_longer_than_80_chars - -part of openapi.api; - -class TimeBucketAssetResponseDtoStackInnerInner { - /// Returns a new [TimeBucketAssetResponseDtoStackInnerInner] instance. - TimeBucketAssetResponseDtoStackInnerInner({ - }); - - @override - bool operator ==(Object other) => identical(this, other) || other is TimeBucketAssetResponseDtoStackInnerInner && - - @override - int get hashCode => - // ignore: unnecessary_parenthesis - - @override - String toString() => 'TimeBucketAssetResponseDtoStackInnerInner[]'; - - Map toJson() { - final json = {}; - return json; - } - - /// Returns a new [TimeBucketAssetResponseDtoStackInnerInner] instance and imports its values from - /// [value] if it's a [Map], null otherwise. - // ignore: prefer_constructors_over_static_methods - static TimeBucketAssetResponseDtoStackInnerInner? fromJson(dynamic value) { - upgradeDto(value, "TimeBucketAssetResponseDtoStackInnerInner"); - if (value is Map) { - final json = value.cast(); - - return TimeBucketAssetResponseDtoStackInnerInner( - ); - } - return null; - } - - static List listFromJson(dynamic json, {bool growable = false,}) { - final result = []; - if (json is List && json.isNotEmpty) { - for (final row in json) { - final value = TimeBucketAssetResponseDtoStackInnerInner.fromJson(row); - if (value != null) { - result.add(value); - } - } - } - return result.toList(growable: growable); - } - - static Map mapFromJson(dynamic json) { - final map = {}; - if (json is Map && json.isNotEmpty) { - json = json.cast(); // ignore: parameter_assignments - for (final entry in json.entries) { - final value = TimeBucketAssetResponseDtoStackInnerInner.fromJson(entry.value); - if (value != null) { - map[entry.key] = value; - } - } - } - return map; - } - - // maps a json object with a list of TimeBucketAssetResponseDtoStackInnerInner-objects as value to a dart map - static Map> mapListFromJson(dynamic json, {bool growable = false,}) { - final map = >{}; - if (json is Map && json.isNotEmpty) { - // ignore: parameter_assignments - json = json.cast(); - for (final entry in json.entries) { - map[entry.key] = TimeBucketAssetResponseDtoStackInnerInner.listFromJson(entry.value, growable: growable,); - } - } - return map; - } - - /// The list of required keys that must be present in a JSON. - static const requiredKeys = { - }; -} - diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index 7741586ee2..ff0428405a 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -13646,23 +13646,13 @@ "type": "array" }, "stack": { - "description": "The stack ID and stack asset count as a tuple", + "description": "(stack ID, stack asset count) tuple", "items": { - "items": { - "maxItems": 2, - "minItems": 2, - "oneOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ] - }, "nullable": true, - "type": "array" + "type": "string" }, + "maxItems": 2, + "minItems": 2, "type": "array" }, "thumbhash": { diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts index fbf6eb423a..e2a833b80f 100644 --- a/open-api/typescript-sdk/src/fetch-client.ts +++ b/open-api/typescript-sdk/src/fetch-client.ts @@ -1398,8 +1398,8 @@ export type TimeBucketAssetResponseDto = { ownerId: string[]; projectionType: (string | null)[]; ratio: number[]; - /** The stack ID and stack asset count as a tuple */ - stack?: ((string | number)[] | null)[]; + /** (stack ID, stack asset count) tuple */ + stack?: (string | null)[]; thumbhash: (string | null)[]; }; export type TimeBucketsResponseDto = { diff --git a/server/src/dtos/time-bucket.dto.ts b/server/src/dtos/time-bucket.dto.ts index 45689d12d1..ba1b303ddf 100644 --- a/server/src/dtos/time-bucket.dto.ts +++ b/server/src/dtos/time-bucket.dto.ts @@ -87,13 +87,14 @@ export class TimeBucketAssetResponseDto implements TimeBucketAssets { @ApiProperty({ type: 'array', items: { - type: 'array', + type: 'string', nullable: true, - items: { oneOf: [{ type: 'string' }, { type: 'number' }], minItems: 2, maxItems: 2 }, }, - description: 'The stack ID and stack asset count as a tuple', + maxItems: 2, + minItems: 2, + description: '(stack ID, stack asset count) tuple', }) - stack?: ([string, number] | null)[]; + stack?: ([string, string] | null)[]; @ApiProperty({ type: 'array', items: { type: 'string', nullable: true } }) projectionType!: (string | null)[]; diff --git a/server/src/queries/asset.repository.sql b/server/src/queries/asset.repository.sql index 5fbc582107..1ebe3f7f0c 100644 --- a/server/src/queries/asset.repository.sql +++ b/server/src/queries/asset.repository.sql @@ -293,7 +293,7 @@ with inner join "exif" on "assets"."id" = "exif"."assetId" left join lateral ( select - json_build_array(stacked."stackId", count('stacked')) as "stack" + array[stacked."stackId"::text, count('stacked')::text] as "stack" from "assets" as "stacked" where diff --git a/server/src/repositories/asset.repository.ts b/server/src/repositories/asset.repository.ts index 4b134dcf9c..a32957d17f 100644 --- a/server/src/repositories/asset.repository.ts +++ b/server/src/repositories/asset.repository.ts @@ -652,7 +652,7 @@ export class AssetRepository { (eb) => eb .selectFrom('assets as stacked') - .select(sql`json_build_array(stacked."stackId", count('stacked'))`.as('stack')) + .select(sql`array[stacked."stackId"::text, count('stacked')::text]`.as('stack')) .whereRef('stacked.stackId', '=', 'assets.stackId') .where('stacked.deletedAt', 'is', null) .where('stacked.isArchived', '=', false) diff --git a/server/src/services/timeline.service.types.ts b/server/src/services/timeline.service.types.ts index 06eb378b6a..e96ff6b1ea 100644 --- a/server/src/services/timeline.service.types.ts +++ b/server/src/services/timeline.service.types.ts @@ -19,7 +19,7 @@ export type TimeBucketAssets = { isImage: number[]; thumbhash: (string | null)[]; localDateTime: string[]; - stack?: ([string, number] | null)[]; + stack?: ([string, string] | 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 684d39155d..da8e38b2f8 100644 --- a/web/src/lib/stores/assets-store.svelte.ts +++ b/web/src/lib/stores/assets-store.svelte.ts @@ -439,9 +439,9 @@ export class AssetBucket { ratio: bucketAssets.ratio[i], stack: bucketAssets.stack?.[i] ? { - id: bucketAssets.stack[i]![0] as string, + id: bucketAssets.stack[i]![0], primaryAssetId: bucketAssets.id[i], - assetCount: bucketAssets.stack[i]![1] as number, + assetCount: Number.parseInt(bucketAssets.stack[i]![1]), } : null, thumbhash: bucketAssets.thumbhash[i],