diff --git a/e2e/src/api/specs/shared-link.e2e-spec.ts b/e2e/src/api/specs/shared-link.e2e-spec.ts index e62d18b72d12c..45c906578d303 100644 --- a/e2e/src/api/specs/shared-link.e2e-spec.ts +++ b/e2e/src/api/specs/shared-link.e2e-spec.ts @@ -170,7 +170,7 @@ describe('/shared-links', () => { expect(status).toBe(200); expect(body).toEqual( expect.objectContaining({ - album, + album: expect.objectContaining({ id: album.id }), userId: user1.userId, type: SharedLinkType.Album, }), @@ -208,7 +208,7 @@ describe('/shared-links', () => { expect(status).toBe(200); expect(body).toEqual( expect.objectContaining({ - album, + album: expect.objectContaining({ id: album.id }), userId: user1.userId, type: SharedLinkType.Album, }), @@ -262,7 +262,7 @@ describe('/shared-links', () => { expect(status).toBe(200); expect(body).toEqual( expect.objectContaining({ - album, + album: expect.objectContaining({ id: album.id }), userId: user1.userId, type: SharedLinkType.Album, }), diff --git a/server/src/interfaces/shared-link.interface.ts b/server/src/interfaces/shared-link.interface.ts index fe08a629419fa..25b7237f00558 100644 --- a/server/src/interfaces/shared-link.interface.ts +++ b/server/src/interfaces/shared-link.interface.ts @@ -1,12 +1,14 @@ +import { Insertable, Updateable } from 'kysely'; +import { SharedLinks } from 'src/db'; import { SharedLinkEntity } from 'src/entities/shared-link.entity'; export const ISharedLinkRepository = 'ISharedLinkRepository'; export interface ISharedLinkRepository { getAll(userId: string): Promise; - get(userId: string, id: string): Promise; - getByKey(key: Buffer): Promise; - create(entity: Partial): Promise; - update(entity: Partial): Promise; + get(userId: string, id: string): Promise; + getByKey(key: Buffer): Promise; + create(entity: Insertable & { assetIds?: string[] }): Promise; + update(entity: Updateable & { id: string; assetIds?: string[] }): Promise; remove(entity: SharedLinkEntity): Promise; } diff --git a/server/src/queries/shared.link.repository.sql b/server/src/queries/shared.link.repository.sql index a19b698f765a4..1861ed86e472c 100644 --- a/server/src/queries/shared.link.repository.sql +++ b/server/src/queries/shared.link.repository.sql @@ -1,331 +1,197 @@ -- NOTE: This file is auto generated by ./sql-generator -- SharedLinkRepository.get -SELECT DISTINCT - "distinctAlias"."SharedLinkEntity_id" AS "ids_SharedLinkEntity_id", - "distinctAlias"."SharedLinkEntity_createdAt", - "distinctAlias"."SharedLinkEntity__SharedLinkEntity_assets_fileCreatedAt", - "distinctAlias"."4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_fileCreatedAt" -FROM - ( - SELECT - "SharedLinkEntity"."id" AS "SharedLinkEntity_id", - "SharedLinkEntity"."description" AS "SharedLinkEntity_description", - "SharedLinkEntity"."password" AS "SharedLinkEntity_password", - "SharedLinkEntity"."userId" AS "SharedLinkEntity_userId", - "SharedLinkEntity"."key" AS "SharedLinkEntity_key", - "SharedLinkEntity"."type" AS "SharedLinkEntity_type", - "SharedLinkEntity"."createdAt" AS "SharedLinkEntity_createdAt", - "SharedLinkEntity"."expiresAt" AS "SharedLinkEntity_expiresAt", - "SharedLinkEntity"."allowUpload" AS "SharedLinkEntity_allowUpload", - "SharedLinkEntity"."allowDownload" AS "SharedLinkEntity_allowDownload", - "SharedLinkEntity"."showExif" AS "SharedLinkEntity_showExif", - "SharedLinkEntity"."albumId" AS "SharedLinkEntity_albumId", - "SharedLinkEntity__SharedLinkEntity_assets"."id" AS "SharedLinkEntity__SharedLinkEntity_assets_id", - "SharedLinkEntity__SharedLinkEntity_assets"."deviceAssetId" AS "SharedLinkEntity__SharedLinkEntity_assets_deviceAssetId", - "SharedLinkEntity__SharedLinkEntity_assets"."ownerId" AS "SharedLinkEntity__SharedLinkEntity_assets_ownerId", - "SharedLinkEntity__SharedLinkEntity_assets"."libraryId" AS "SharedLinkEntity__SharedLinkEntity_assets_libraryId", - "SharedLinkEntity__SharedLinkEntity_assets"."deviceId" AS "SharedLinkEntity__SharedLinkEntity_assets_deviceId", - "SharedLinkEntity__SharedLinkEntity_assets"."type" AS "SharedLinkEntity__SharedLinkEntity_assets_type", - "SharedLinkEntity__SharedLinkEntity_assets"."status" AS "SharedLinkEntity__SharedLinkEntity_assets_status", - "SharedLinkEntity__SharedLinkEntity_assets"."originalPath" AS "SharedLinkEntity__SharedLinkEntity_assets_originalPath", - "SharedLinkEntity__SharedLinkEntity_assets"."thumbhash" AS "SharedLinkEntity__SharedLinkEntity_assets_thumbhash", - "SharedLinkEntity__SharedLinkEntity_assets"."encodedVideoPath" AS "SharedLinkEntity__SharedLinkEntity_assets_encodedVideoPath", - "SharedLinkEntity__SharedLinkEntity_assets"."createdAt" AS "SharedLinkEntity__SharedLinkEntity_assets_createdAt", - "SharedLinkEntity__SharedLinkEntity_assets"."updatedAt" AS "SharedLinkEntity__SharedLinkEntity_assets_updatedAt", - "SharedLinkEntity__SharedLinkEntity_assets"."deletedAt" AS "SharedLinkEntity__SharedLinkEntity_assets_deletedAt", - "SharedLinkEntity__SharedLinkEntity_assets"."fileCreatedAt" AS "SharedLinkEntity__SharedLinkEntity_assets_fileCreatedAt", - "SharedLinkEntity__SharedLinkEntity_assets"."localDateTime" AS "SharedLinkEntity__SharedLinkEntity_assets_localDateTime", - "SharedLinkEntity__SharedLinkEntity_assets"."fileModifiedAt" AS "SharedLinkEntity__SharedLinkEntity_assets_fileModifiedAt", - "SharedLinkEntity__SharedLinkEntity_assets"."isFavorite" AS "SharedLinkEntity__SharedLinkEntity_assets_isFavorite", - "SharedLinkEntity__SharedLinkEntity_assets"."isArchived" AS "SharedLinkEntity__SharedLinkEntity_assets_isArchived", - "SharedLinkEntity__SharedLinkEntity_assets"."isExternal" AS "SharedLinkEntity__SharedLinkEntity_assets_isExternal", - "SharedLinkEntity__SharedLinkEntity_assets"."isOffline" AS "SharedLinkEntity__SharedLinkEntity_assets_isOffline", - "SharedLinkEntity__SharedLinkEntity_assets"."checksum" AS "SharedLinkEntity__SharedLinkEntity_assets_checksum", - "SharedLinkEntity__SharedLinkEntity_assets"."duration" AS "SharedLinkEntity__SharedLinkEntity_assets_duration", - "SharedLinkEntity__SharedLinkEntity_assets"."isVisible" AS "SharedLinkEntity__SharedLinkEntity_assets_isVisible", - "SharedLinkEntity__SharedLinkEntity_assets"."livePhotoVideoId" AS "SharedLinkEntity__SharedLinkEntity_assets_livePhotoVideoId", - "SharedLinkEntity__SharedLinkEntity_assets"."originalFileName" AS "SharedLinkEntity__SharedLinkEntity_assets_originalFileName", - "SharedLinkEntity__SharedLinkEntity_assets"."sidecarPath" AS "SharedLinkEntity__SharedLinkEntity_assets_sidecarPath", - "SharedLinkEntity__SharedLinkEntity_assets"."stackId" AS "SharedLinkEntity__SharedLinkEntity_assets_stackId", - "SharedLinkEntity__SharedLinkEntity_assets"."duplicateId" AS "SharedLinkEntity__SharedLinkEntity_assets_duplicateId", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."assetId" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_assetId", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."description" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_description", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."exifImageWidth" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_exifImageWidth", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."exifImageHeight" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_exifImageHeight", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."fileSizeInByte" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_fileSizeInByte", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."orientation" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_orientation", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."dateTimeOriginal" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_dateTimeOriginal", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."modifyDate" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_modifyDate", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."timeZone" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_timeZone", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."latitude" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_latitude", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."longitude" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_longitude", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."projectionType" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_projectionType", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."city" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_city", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."livePhotoCID" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_livePhotoCID", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."autoStackId" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_autoStackId", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."state" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_state", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."country" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_country", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."make" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_make", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."model" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_model", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."lensModel" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_lensModel", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."fNumber" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_fNumber", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."focalLength" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_focalLength", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."iso" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_iso", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."exposureTime" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_exposureTime", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."profileDescription" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_profileDescription", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."colorspace" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_colorspace", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."bitsPerSample" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_bitsPerSample", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."rating" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_rating", - "9b1d35b344d838023994a3233afd6ffe098be6d8"."fps" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_fps", - "SharedLinkEntity__SharedLinkEntity_album"."id" AS "SharedLinkEntity__SharedLinkEntity_album_id", - "SharedLinkEntity__SharedLinkEntity_album"."ownerId" AS "SharedLinkEntity__SharedLinkEntity_album_ownerId", - "SharedLinkEntity__SharedLinkEntity_album"."albumName" AS "SharedLinkEntity__SharedLinkEntity_album_albumName", - "SharedLinkEntity__SharedLinkEntity_album"."description" AS "SharedLinkEntity__SharedLinkEntity_album_description", - "SharedLinkEntity__SharedLinkEntity_album"."createdAt" AS "SharedLinkEntity__SharedLinkEntity_album_createdAt", - "SharedLinkEntity__SharedLinkEntity_album"."updatedAt" AS "SharedLinkEntity__SharedLinkEntity_album_updatedAt", - "SharedLinkEntity__SharedLinkEntity_album"."deletedAt" AS "SharedLinkEntity__SharedLinkEntity_album_deletedAt", - "SharedLinkEntity__SharedLinkEntity_album"."albumThumbnailAssetId" AS "SharedLinkEntity__SharedLinkEntity_album_albumThumbnailAssetId", - "SharedLinkEntity__SharedLinkEntity_album"."isActivityEnabled" AS "SharedLinkEntity__SharedLinkEntity_album_isActivityEnabled", - "SharedLinkEntity__SharedLinkEntity_album"."order" AS "SharedLinkEntity__SharedLinkEntity_album_order", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."id" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_id", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."deviceAssetId" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_deviceAssetId", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."ownerId" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_ownerId", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."libraryId" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_libraryId", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."deviceId" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_deviceId", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."type" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_type", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."status" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_status", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."originalPath" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_originalPath", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."thumbhash" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_thumbhash", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."encodedVideoPath" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_encodedVideoPath", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."createdAt" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_createdAt", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."updatedAt" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_updatedAt", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."deletedAt" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_deletedAt", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."fileCreatedAt" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_fileCreatedAt", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."localDateTime" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_localDateTime", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."fileModifiedAt" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_fileModifiedAt", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."isFavorite" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_isFavorite", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."isArchived" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_isArchived", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."isExternal" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_isExternal", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."isOffline" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_isOffline", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."checksum" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_checksum", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."duration" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_duration", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."isVisible" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_isVisible", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."livePhotoVideoId" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_livePhotoVideoId", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."originalFileName" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_originalFileName", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."sidecarPath" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_sidecarPath", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."stackId" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_stackId", - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."duplicateId" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_duplicateId", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."assetId" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_assetId", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."description" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_description", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."exifImageWidth" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_exifImageWidth", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."exifImageHeight" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_exifImageHeight", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."fileSizeInByte" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_fileSizeInByte", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."orientation" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_orientation", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."dateTimeOriginal" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_dateTimeOriginal", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."modifyDate" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_modifyDate", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."timeZone" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_timeZone", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."latitude" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_latitude", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."longitude" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_longitude", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."projectionType" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_projectionType", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."city" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_city", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."livePhotoCID" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_livePhotoCID", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."autoStackId" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_autoStackId", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."state" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_state", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."country" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_country", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."make" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_make", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."model" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_model", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."lensModel" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_lensModel", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."fNumber" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_fNumber", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."focalLength" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_focalLength", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."iso" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_iso", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."exposureTime" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_exposureTime", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."profileDescription" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_profileDescription", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."colorspace" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_colorspace", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."bitsPerSample" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_bitsPerSample", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."rating" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_rating", - "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."fps" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_fps", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."id" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_id", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."name" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_name", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."isAdmin" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_isAdmin", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."email" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_email", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."storageLabel" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_storageLabel", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."oauthId" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_oauthId", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."profileImagePath" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_profileImagePath", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."shouldChangePassword" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_shouldChangePassword", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."createdAt" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_createdAt", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."deletedAt" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_deletedAt", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."status" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_status", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."updatedAt" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_updatedAt", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."quotaSizeInBytes" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_quotaSizeInBytes", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."quotaUsageInBytes" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_quotaUsageInBytes", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."profileChangedAt" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_profileChangedAt" - FROM - "shared_links" "SharedLinkEntity" - LEFT JOIN "shared_link__asset" "SharedLinkEntity__SharedLinkEntity_assets_SharedLinkEntity" ON "SharedLinkEntity__SharedLinkEntity_assets_SharedLinkEntity"."sharedLinksId" = "SharedLinkEntity"."id" - LEFT JOIN "assets" "SharedLinkEntity__SharedLinkEntity_assets" ON "SharedLinkEntity__SharedLinkEntity_assets"."id" = "SharedLinkEntity__SharedLinkEntity_assets_SharedLinkEntity"."assetsId" - AND ( - "SharedLinkEntity__SharedLinkEntity_assets"."deletedAt" IS NULL - ) - LEFT JOIN "exif" "9b1d35b344d838023994a3233afd6ffe098be6d8" ON "9b1d35b344d838023994a3233afd6ffe098be6d8"."assetId" = "SharedLinkEntity__SharedLinkEntity_assets"."id" - LEFT JOIN "albums" "SharedLinkEntity__SharedLinkEntity_album" ON "SharedLinkEntity__SharedLinkEntity_album"."id" = "SharedLinkEntity"."albumId" - AND ( - "SharedLinkEntity__SharedLinkEntity_album"."deletedAt" IS NULL - ) - LEFT JOIN "albums_assets_assets" "760f12c00d97bdcec1ce224d1e3bf449859942b6" ON "760f12c00d97bdcec1ce224d1e3bf449859942b6"."albumsId" = "SharedLinkEntity__SharedLinkEntity_album"."id" - LEFT JOIN "assets" "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6" ON "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."id" = "760f12c00d97bdcec1ce224d1e3bf449859942b6"."assetsId" - AND ( - "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."deletedAt" IS NULL - ) - LEFT JOIN "exif" "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f" ON "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."assetId" = "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."id" - LEFT JOIN "users" "6d7fd45329a05fd86b3dbcacde87fe76e33a422d" ON "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."id" = "SharedLinkEntity__SharedLinkEntity_album"."ownerId" - AND ( - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."deletedAt" IS NULL - ) - WHERE - ( - ("SharedLinkEntity"."id" = $1) - AND ("SharedLinkEntity"."userId" = $2) - ) - ) "distinctAlias" -ORDER BY - "distinctAlias"."SharedLinkEntity_createdAt" DESC, - "distinctAlias"."SharedLinkEntity__SharedLinkEntity_assets_fileCreatedAt" ASC, - "distinctAlias"."4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_fileCreatedAt" ASC, - "SharedLinkEntity_id" ASC -LIMIT - 1 +select + "shared_links".*, + coalesce( + json_agg("a") filter ( + where + "a"."id" is not null + ), + '[]' + ) as "assets", + to_json("album") as "album" +from + "shared_links" + left join lateral ( + select + "assets".*, + to_json("exifInfo") as "exifInfo" + from + "shared_link__asset" + inner join "assets" on "assets"."id" = "shared_link__asset"."assetsId" + inner join lateral ( + select + "exif".* + from + "exif" + where + "exif"."assetId" = "assets"."id" + ) as "exifInfo" on true + where + "shared_links"."id" = "shared_link__asset"."sharedLinksId" + and "assets"."deletedAt" is null + order by + "assets"."fileCreatedAt" asc + ) as "a" on true + left join lateral ( + select + "albums".*, + coalesce( + json_agg("assets") filter ( + where + "assets"."id" is not null + ), + '[]' + ) as "assets", + to_json("owner") as "owner" + from + "albums" + left join "albums_assets_assets" on "albums_assets_assets"."albumsId" = "albums"."id" + left join lateral ( + select + "assets".*, + to_json("assets_exifInfo") as "exifInfo" + from + "assets" + inner join lateral ( + select + "exif".* + from + "exif" + where + "exif"."assetId" = "assets"."id" + ) as "assets_exifInfo" on true + where + "albums_assets_assets"."assetsId" = "assets"."id" + and "assets"."deletedAt" is null + order by + "assets"."fileCreatedAt" asc + ) as "assets" on true + inner join lateral ( + select + "users".* + from + "users" + where + "users"."id" = "albums"."ownerId" + and "users"."deletedAt" is null + ) as "owner" on true + where + "albums"."id" = "shared_links"."albumId" + and "albums"."deletedAt" is null + group by + "albums"."id", + "owner".* + ) as "album" on true +where + "shared_links"."id" = $1 + and "shared_links"."userId" = $2 + and ( + "shared_links"."type" = $3 + or "album"."id" is not null + ) +group by + "shared_links"."id", + "album".* +order by + "shared_links"."createdAt" desc -- SharedLinkRepository.getAll -SELECT - "SharedLinkEntity"."id" AS "SharedLinkEntity_id", - "SharedLinkEntity"."description" AS "SharedLinkEntity_description", - "SharedLinkEntity"."password" AS "SharedLinkEntity_password", - "SharedLinkEntity"."userId" AS "SharedLinkEntity_userId", - "SharedLinkEntity"."key" AS "SharedLinkEntity_key", - "SharedLinkEntity"."type" AS "SharedLinkEntity_type", - "SharedLinkEntity"."createdAt" AS "SharedLinkEntity_createdAt", - "SharedLinkEntity"."expiresAt" AS "SharedLinkEntity_expiresAt", - "SharedLinkEntity"."allowUpload" AS "SharedLinkEntity_allowUpload", - "SharedLinkEntity"."allowDownload" AS "SharedLinkEntity_allowDownload", - "SharedLinkEntity"."showExif" AS "SharedLinkEntity_showExif", - "SharedLinkEntity"."albumId" AS "SharedLinkEntity_albumId", - "SharedLinkEntity__SharedLinkEntity_assets"."id" AS "SharedLinkEntity__SharedLinkEntity_assets_id", - "SharedLinkEntity__SharedLinkEntity_assets"."deviceAssetId" AS "SharedLinkEntity__SharedLinkEntity_assets_deviceAssetId", - "SharedLinkEntity__SharedLinkEntity_assets"."ownerId" AS "SharedLinkEntity__SharedLinkEntity_assets_ownerId", - "SharedLinkEntity__SharedLinkEntity_assets"."libraryId" AS "SharedLinkEntity__SharedLinkEntity_assets_libraryId", - "SharedLinkEntity__SharedLinkEntity_assets"."deviceId" AS "SharedLinkEntity__SharedLinkEntity_assets_deviceId", - "SharedLinkEntity__SharedLinkEntity_assets"."type" AS "SharedLinkEntity__SharedLinkEntity_assets_type", - "SharedLinkEntity__SharedLinkEntity_assets"."status" AS "SharedLinkEntity__SharedLinkEntity_assets_status", - "SharedLinkEntity__SharedLinkEntity_assets"."originalPath" AS "SharedLinkEntity__SharedLinkEntity_assets_originalPath", - "SharedLinkEntity__SharedLinkEntity_assets"."thumbhash" AS "SharedLinkEntity__SharedLinkEntity_assets_thumbhash", - "SharedLinkEntity__SharedLinkEntity_assets"."encodedVideoPath" AS "SharedLinkEntity__SharedLinkEntity_assets_encodedVideoPath", - "SharedLinkEntity__SharedLinkEntity_assets"."createdAt" AS "SharedLinkEntity__SharedLinkEntity_assets_createdAt", - "SharedLinkEntity__SharedLinkEntity_assets"."updatedAt" AS "SharedLinkEntity__SharedLinkEntity_assets_updatedAt", - "SharedLinkEntity__SharedLinkEntity_assets"."deletedAt" AS "SharedLinkEntity__SharedLinkEntity_assets_deletedAt", - "SharedLinkEntity__SharedLinkEntity_assets"."fileCreatedAt" AS "SharedLinkEntity__SharedLinkEntity_assets_fileCreatedAt", - "SharedLinkEntity__SharedLinkEntity_assets"."localDateTime" AS "SharedLinkEntity__SharedLinkEntity_assets_localDateTime", - "SharedLinkEntity__SharedLinkEntity_assets"."fileModifiedAt" AS "SharedLinkEntity__SharedLinkEntity_assets_fileModifiedAt", - "SharedLinkEntity__SharedLinkEntity_assets"."isFavorite" AS "SharedLinkEntity__SharedLinkEntity_assets_isFavorite", - "SharedLinkEntity__SharedLinkEntity_assets"."isArchived" AS "SharedLinkEntity__SharedLinkEntity_assets_isArchived", - "SharedLinkEntity__SharedLinkEntity_assets"."isExternal" AS "SharedLinkEntity__SharedLinkEntity_assets_isExternal", - "SharedLinkEntity__SharedLinkEntity_assets"."isOffline" AS "SharedLinkEntity__SharedLinkEntity_assets_isOffline", - "SharedLinkEntity__SharedLinkEntity_assets"."checksum" AS "SharedLinkEntity__SharedLinkEntity_assets_checksum", - "SharedLinkEntity__SharedLinkEntity_assets"."duration" AS "SharedLinkEntity__SharedLinkEntity_assets_duration", - "SharedLinkEntity__SharedLinkEntity_assets"."isVisible" AS "SharedLinkEntity__SharedLinkEntity_assets_isVisible", - "SharedLinkEntity__SharedLinkEntity_assets"."livePhotoVideoId" AS "SharedLinkEntity__SharedLinkEntity_assets_livePhotoVideoId", - "SharedLinkEntity__SharedLinkEntity_assets"."originalFileName" AS "SharedLinkEntity__SharedLinkEntity_assets_originalFileName", - "SharedLinkEntity__SharedLinkEntity_assets"."sidecarPath" AS "SharedLinkEntity__SharedLinkEntity_assets_sidecarPath", - "SharedLinkEntity__SharedLinkEntity_assets"."stackId" AS "SharedLinkEntity__SharedLinkEntity_assets_stackId", - "SharedLinkEntity__SharedLinkEntity_assets"."duplicateId" AS "SharedLinkEntity__SharedLinkEntity_assets_duplicateId", - "SharedLinkEntity__SharedLinkEntity_album"."id" AS "SharedLinkEntity__SharedLinkEntity_album_id", - "SharedLinkEntity__SharedLinkEntity_album"."ownerId" AS "SharedLinkEntity__SharedLinkEntity_album_ownerId", - "SharedLinkEntity__SharedLinkEntity_album"."albumName" AS "SharedLinkEntity__SharedLinkEntity_album_albumName", - "SharedLinkEntity__SharedLinkEntity_album"."description" AS "SharedLinkEntity__SharedLinkEntity_album_description", - "SharedLinkEntity__SharedLinkEntity_album"."createdAt" AS "SharedLinkEntity__SharedLinkEntity_album_createdAt", - "SharedLinkEntity__SharedLinkEntity_album"."updatedAt" AS "SharedLinkEntity__SharedLinkEntity_album_updatedAt", - "SharedLinkEntity__SharedLinkEntity_album"."deletedAt" AS "SharedLinkEntity__SharedLinkEntity_album_deletedAt", - "SharedLinkEntity__SharedLinkEntity_album"."albumThumbnailAssetId" AS "SharedLinkEntity__SharedLinkEntity_album_albumThumbnailAssetId", - "SharedLinkEntity__SharedLinkEntity_album"."isActivityEnabled" AS "SharedLinkEntity__SharedLinkEntity_album_isActivityEnabled", - "SharedLinkEntity__SharedLinkEntity_album"."order" AS "SharedLinkEntity__SharedLinkEntity_album_order", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."id" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_id", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."name" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_name", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."isAdmin" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_isAdmin", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."email" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_email", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."storageLabel" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_storageLabel", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."oauthId" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_oauthId", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."profileImagePath" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_profileImagePath", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."shouldChangePassword" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_shouldChangePassword", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."createdAt" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_createdAt", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."deletedAt" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_deletedAt", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."status" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_status", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."updatedAt" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_updatedAt", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."quotaSizeInBytes" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_quotaSizeInBytes", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."quotaUsageInBytes" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_quotaUsageInBytes", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."profileChangedAt" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_profileChangedAt" -FROM - "shared_links" "SharedLinkEntity" - LEFT JOIN "shared_link__asset" "SharedLinkEntity__SharedLinkEntity_assets_SharedLinkEntity" ON "SharedLinkEntity__SharedLinkEntity_assets_SharedLinkEntity"."sharedLinksId" = "SharedLinkEntity"."id" - LEFT JOIN "assets" "SharedLinkEntity__SharedLinkEntity_assets" ON "SharedLinkEntity__SharedLinkEntity_assets"."id" = "SharedLinkEntity__SharedLinkEntity_assets_SharedLinkEntity"."assetsId" - AND ( - "SharedLinkEntity__SharedLinkEntity_assets"."deletedAt" IS NULL - ) - LEFT JOIN "albums" "SharedLinkEntity__SharedLinkEntity_album" ON "SharedLinkEntity__SharedLinkEntity_album"."id" = "SharedLinkEntity"."albumId" - AND ( - "SharedLinkEntity__SharedLinkEntity_album"."deletedAt" IS NULL +select distinct + on ("shared_links"."createdAt") "shared_links".*, + to_json("album") as "album" +from + "shared_links" + left join "shared_link__asset" on "shared_link__asset"."sharedLinksId" = "shared_links"."id" + left join lateral ( + select + "assets".* + from + "assets" + where + "assets"."id" = "shared_link__asset"."assetsId" + and "assets"."deletedAt" is null + ) as "assets" on true + left join lateral ( + select + "albums".*, + to_json("owner") as "owner" + from + "albums" + inner join lateral ( + select + "users"."id", + "users"."email", + "users"."createdAt", + "users"."profileImagePath", + "users"."isAdmin", + "users"."shouldChangePassword", + "users"."deletedAt", + "users"."oauthId", + "users"."updatedAt", + "users"."storageLabel", + "users"."name", + "users"."quotaSizeInBytes", + "users"."quotaUsageInBytes", + "users"."status", + "users"."profileChangedAt" + from + "users" + where + "users"."id" = "albums"."ownerId" + and "users"."deletedAt" is null + ) as "owner" on true + where + "albums"."id" = "shared_links"."albumId" + and "albums"."deletedAt" is null + ) as "album" on true +where + "shared_links"."userId" = $1 + and ( + "shared_links"."type" = $2 + or "album"."id" is not null ) - LEFT JOIN "users" "6d7fd45329a05fd86b3dbcacde87fe76e33a422d" ON "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."id" = "SharedLinkEntity__SharedLinkEntity_album"."ownerId" - AND ( - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."deletedAt" IS NULL - ) -WHERE - (("SharedLinkEntity"."userId" = $1)) -ORDER BY - "SharedLinkEntity"."createdAt" DESC +order by + "shared_links"."createdAt" desc -- SharedLinkRepository.getByKey -SELECT DISTINCT - "distinctAlias"."SharedLinkEntity_id" AS "ids_SharedLinkEntity_id" -FROM +select + "shared_links".*, ( - SELECT - "SharedLinkEntity"."id" AS "SharedLinkEntity_id", - "SharedLinkEntity"."description" AS "SharedLinkEntity_description", - "SharedLinkEntity"."password" AS "SharedLinkEntity_password", - "SharedLinkEntity"."userId" AS "SharedLinkEntity_userId", - "SharedLinkEntity"."key" AS "SharedLinkEntity_key", - "SharedLinkEntity"."type" AS "SharedLinkEntity_type", - "SharedLinkEntity"."createdAt" AS "SharedLinkEntity_createdAt", - "SharedLinkEntity"."expiresAt" AS "SharedLinkEntity_expiresAt", - "SharedLinkEntity"."allowUpload" AS "SharedLinkEntity_allowUpload", - "SharedLinkEntity"."allowDownload" AS "SharedLinkEntity_allowDownload", - "SharedLinkEntity"."showExif" AS "SharedLinkEntity_showExif", - "SharedLinkEntity"."albumId" AS "SharedLinkEntity_albumId", - "SharedLinkEntity__SharedLinkEntity_user"."id" AS "SharedLinkEntity__SharedLinkEntity_user_id", - "SharedLinkEntity__SharedLinkEntity_user"."name" AS "SharedLinkEntity__SharedLinkEntity_user_name", - "SharedLinkEntity__SharedLinkEntity_user"."isAdmin" AS "SharedLinkEntity__SharedLinkEntity_user_isAdmin", - "SharedLinkEntity__SharedLinkEntity_user"."email" AS "SharedLinkEntity__SharedLinkEntity_user_email", - "SharedLinkEntity__SharedLinkEntity_user"."storageLabel" AS "SharedLinkEntity__SharedLinkEntity_user_storageLabel", - "SharedLinkEntity__SharedLinkEntity_user"."oauthId" AS "SharedLinkEntity__SharedLinkEntity_user_oauthId", - "SharedLinkEntity__SharedLinkEntity_user"."profileImagePath" AS "SharedLinkEntity__SharedLinkEntity_user_profileImagePath", - "SharedLinkEntity__SharedLinkEntity_user"."shouldChangePassword" AS "SharedLinkEntity__SharedLinkEntity_user_shouldChangePassword", - "SharedLinkEntity__SharedLinkEntity_user"."createdAt" AS "SharedLinkEntity__SharedLinkEntity_user_createdAt", - "SharedLinkEntity__SharedLinkEntity_user"."deletedAt" AS "SharedLinkEntity__SharedLinkEntity_user_deletedAt", - "SharedLinkEntity__SharedLinkEntity_user"."status" AS "SharedLinkEntity__SharedLinkEntity_user_status", - "SharedLinkEntity__SharedLinkEntity_user"."updatedAt" AS "SharedLinkEntity__SharedLinkEntity_user_updatedAt", - "SharedLinkEntity__SharedLinkEntity_user"."quotaSizeInBytes" AS "SharedLinkEntity__SharedLinkEntity_user_quotaSizeInBytes", - "SharedLinkEntity__SharedLinkEntity_user"."quotaUsageInBytes" AS "SharedLinkEntity__SharedLinkEntity_user_quotaUsageInBytes", - "SharedLinkEntity__SharedLinkEntity_user"."profileChangedAt" AS "SharedLinkEntity__SharedLinkEntity_user_profileChangedAt" - FROM - "shared_links" "SharedLinkEntity" - LEFT JOIN "users" "SharedLinkEntity__SharedLinkEntity_user" ON "SharedLinkEntity__SharedLinkEntity_user"."id" = "SharedLinkEntity"."userId" - AND ( - "SharedLinkEntity__SharedLinkEntity_user"."deletedAt" IS NULL - ) - WHERE - (("SharedLinkEntity"."key" = $1)) - ) "distinctAlias" -ORDER BY - "SharedLinkEntity_id" ASC -LIMIT - 1 + select + to_json(obj) + from + ( + select + "users"."id", + "users"."email", + "users"."createdAt", + "users"."profileImagePath", + "users"."isAdmin", + "users"."shouldChangePassword", + "users"."deletedAt", + "users"."oauthId", + "users"."updatedAt", + "users"."storageLabel", + "users"."name", + "users"."quotaSizeInBytes", + "users"."quotaUsageInBytes", + "users"."status", + "users"."profileChangedAt" + from + "users" + where + "users"."id" = "shared_links"."userId" + ) as obj + ) as "user" +from + "shared_links" + left join "albums" on "albums"."id" = "shared_links"."albumId" +where + "shared_links"."key" = $1 + and "albums"."deletedAt" is null + and ( + "shared_links"."type" = $2 + or "albums"."id" is not null + ) diff --git a/server/src/repositories/shared-link.repository.ts b/server/src/repositories/shared-link.repository.ts index 1dfde99a75022..6473100387e8c 100644 --- a/server/src/repositories/shared-link.repository.ts +++ b/server/src/repositories/shared-link.repository.ts @@ -1,90 +1,256 @@ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; +import { Insertable, Kysely, sql, Updateable } from 'kysely'; +import { jsonObjectFrom } from 'kysely/helpers/postgres'; +import _ from 'lodash'; +import { InjectKysely } from 'nestjs-kysely'; +import { DB, SharedLinks } from 'src/db'; import { DummyValue, GenerateSql } from 'src/decorators'; import { SharedLinkEntity } from 'src/entities/shared-link.entity'; +import { SharedLinkType } from 'src/enum'; import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface'; -import { Repository } from 'typeorm'; @Injectable() export class SharedLinkRepository implements ISharedLinkRepository { - constructor(@InjectRepository(SharedLinkEntity) private repository: Repository) {} + constructor(@InjectKysely() private db: Kysely) {} @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] }) - get(userId: string, id: string): Promise { - return this.repository.findOne({ - where: { - id, - userId, - }, - relations: { - assets: { - exifInfo: true, - }, - album: { - assets: { - exifInfo: true, - }, - owner: true, - }, - }, - order: { - createdAt: 'DESC', - assets: { - fileCreatedAt: 'ASC', - }, - album: { - assets: { - fileCreatedAt: 'ASC', - }, - }, - }, - }); + get(userId: string, id: string): Promise { + return this.db + .selectFrom('shared_links') + .selectAll('shared_links') + .leftJoinLateral( + (eb) => + eb + .selectFrom('shared_link__asset') + .whereRef('shared_links.id', '=', 'shared_link__asset.sharedLinksId') + .innerJoin('assets', 'assets.id', 'shared_link__asset.assetsId') + .where('assets.deletedAt', 'is', null) + .selectAll('assets') + .innerJoinLateral( + (eb) => eb.selectFrom('exif').selectAll('exif').whereRef('exif.assetId', '=', 'assets.id').as('exifInfo'), + (join) => join.onTrue(), + ) + .select((eb) => eb.fn.toJson('exifInfo').as('exifInfo')) + .orderBy('assets.fileCreatedAt', 'asc') + .as('a'), + (join) => join.onTrue(), + ) + .leftJoinLateral( + (eb) => + eb + .selectFrom('albums') + .selectAll('albums') + .whereRef('albums.id', '=', 'shared_links.albumId') + .where('albums.deletedAt', 'is', null) + .leftJoin('albums_assets_assets', 'albums_assets_assets.albumsId', 'albums.id') + .leftJoinLateral( + (eb) => + eb + .selectFrom('assets') + .selectAll('assets') + .whereRef('albums_assets_assets.assetsId', '=', 'assets.id') + .where('assets.deletedAt', 'is', null) + .innerJoinLateral( + (eb) => + eb + .selectFrom('exif') + .selectAll('exif') + .whereRef('exif.assetId', '=', 'assets.id') + .as('assets_exifInfo'), + (join) => join.onTrue(), + ) + .select((eb) => eb.fn.toJson(eb.table('assets_exifInfo')).as('exifInfo')) + .orderBy('assets.fileCreatedAt', 'asc') + .as('assets'), + (join) => join.onTrue(), + ) + .innerJoinLateral( + (eb) => + eb + .selectFrom('users') + .selectAll('users') + .whereRef('users.id', '=', 'albums.ownerId') + .where('users.deletedAt', 'is', null) + .as('owner'), + (join) => join.onTrue(), + ) + .select((eb) => + eb.fn.coalesce(eb.fn.jsonAgg('assets').filterWhere('assets.id', 'is not', null), sql`'[]'`).as('assets'), + ) + .select((eb) => eb.fn.toJson('owner').as('owner')) + .groupBy(['albums.id', sql`"owner".*`]) + .as('album'), + (join) => join.onTrue(), + ) + .select((eb) => eb.fn.coalesce(eb.fn.jsonAgg('a').filterWhere('a.id', 'is not', null), sql`'[]'`).as('assets')) + .groupBy(['shared_links.id', sql`"album".*`]) + .select((eb) => eb.fn.toJson('album').as('album')) + .where('shared_links.id', '=', id) + .where('shared_links.userId', '=', userId) + .where((eb) => eb.or([eb('shared_links.type', '=', SharedLinkType.INDIVIDUAL), eb('album.id', 'is not', null)])) + .orderBy('shared_links.createdAt', 'desc') + .executeTakeFirst() as Promise; } @GenerateSql({ params: [DummyValue.UUID] }) getAll(userId: string): Promise { - return this.repository.find({ - where: { - userId, - }, - relations: { - assets: true, - album: { - owner: true, - }, - }, - order: { - createdAt: 'DESC', - }, - }); + return this.db + .selectFrom('shared_links') + .selectAll('shared_links') + .where('shared_links.userId', '=', userId) + .leftJoin('shared_link__asset', 'shared_link__asset.sharedLinksId', 'shared_links.id') + .leftJoinLateral( + (eb) => + eb + .selectFrom('assets') + .whereRef('assets.id', '=', 'shared_link__asset.assetsId') + .where('assets.deletedAt', 'is', null) + .selectAll('assets') + .as('assets'), + (join) => join.onTrue(), + ) + .leftJoinLateral( + (eb) => + eb + .selectFrom('albums') + .selectAll('albums') + .whereRef('albums.id', '=', 'shared_links.albumId') + .innerJoinLateral( + (eb) => + eb + .selectFrom('users') + .select([ + 'users.id', + 'users.email', + 'users.createdAt', + 'users.profileImagePath', + 'users.isAdmin', + 'users.shouldChangePassword', + 'users.deletedAt', + 'users.oauthId', + 'users.updatedAt', + 'users.storageLabel', + 'users.name', + 'users.quotaSizeInBytes', + 'users.quotaUsageInBytes', + 'users.status', + 'users.profileChangedAt', + ]) + .whereRef('users.id', '=', 'albums.ownerId') + .where('users.deletedAt', 'is', null) + .as('owner'), + (join) => join.onTrue(), + ) + .select((eb) => eb.fn.toJson('owner').as('owner')) + .where('albums.deletedAt', 'is', null) + .as('album'), + (join) => join.onTrue(), + ) + .select((eb) => eb.fn.toJson('album').as('album')) + .where((eb) => eb.or([eb('shared_links.type', '=', SharedLinkType.INDIVIDUAL), eb('album.id', 'is not', null)])) + .orderBy('shared_links.createdAt', 'desc') + .distinctOn(['shared_links.createdAt']) + .execute() as unknown as Promise; } @GenerateSql({ params: [DummyValue.BUFFER] }) - async getByKey(key: Buffer): Promise { - return await this.repository.findOne({ - where: { - key, - }, - relations: { - user: true, - }, - }); + async getByKey(key: Buffer): Promise { + return this.db + .selectFrom('shared_links') + .selectAll('shared_links') + .where('shared_links.key', '=', key) + .leftJoin('albums', 'albums.id', 'shared_links.albumId') + .where('albums.deletedAt', 'is', null) + .select((eb) => + jsonObjectFrom( + eb + .selectFrom('users') + .select([ + 'users.id', + 'users.email', + 'users.createdAt', + 'users.profileImagePath', + 'users.isAdmin', + 'users.shouldChangePassword', + 'users.deletedAt', + 'users.oauthId', + 'users.updatedAt', + 'users.storageLabel', + 'users.name', + 'users.quotaSizeInBytes', + 'users.quotaUsageInBytes', + 'users.status', + 'users.profileChangedAt', + ]) + .whereRef('users.id', '=', 'shared_links.userId'), + ).as('user'), + ) + .where((eb) => eb.or([eb('shared_links.type', '=', SharedLinkType.INDIVIDUAL), eb('albums.id', 'is not', null)])) + .executeTakeFirst() as Promise; } - create(entity: Partial): Promise { - return this.save(entity); + async create(entity: Insertable & { assetIds?: string[] }): Promise { + const { id } = await this.db + .insertInto('shared_links') + .values(_.omit(entity, 'assetIds')) + .returningAll() + .executeTakeFirstOrThrow(); + + if (entity.assetIds && entity.assetIds.length > 0) { + await this.db + .insertInto('shared_link__asset') + .values(entity.assetIds!.map((assetsId) => ({ assetsId, sharedLinksId: id }))) + .execute(); + } + + return this.getSharedLinks(id); } - update(entity: Partial): Promise { - return this.save(entity); + async update(entity: Updateable & { id: string; assetIds?: string[] }): Promise { + const { id } = await this.db + .updateTable('shared_links') + .set(_.omit(entity, 'assets', 'album', 'assetIds')) + .where('shared_links.id', '=', entity.id) + .returningAll() + .executeTakeFirstOrThrow(); + + if (entity.assetIds && entity.assetIds.length > 0) { + await this.db + .insertInto('shared_link__asset') + .values(entity.assetIds!.map((assetsId) => ({ assetsId, sharedLinksId: id }))) + .execute(); + } + + return this.getSharedLinks(id); } async remove(entity: SharedLinkEntity): Promise { - await this.repository.remove(entity); + await this.db.deleteFrom('shared_links').where('shared_links.id', '=', entity.id).execute(); } - private async save(entity: Partial): Promise { - await this.repository.save(entity); - return this.repository.findOneOrFail({ where: { id: entity.id } }); + private getSharedLinks(id: string) { + return this.db + .selectFrom('shared_links') + .selectAll('shared_links') + .where('shared_links.id', '=', id) + .leftJoin('shared_link__asset', 'shared_link__asset.sharedLinksId', 'shared_links.id') + .leftJoinLateral( + (eb) => + eb + .selectFrom('assets') + .whereRef('assets.id', '=', 'shared_link__asset.assetsId') + .selectAll('assets') + .innerJoinLateral( + (eb) => eb.selectFrom('exif').whereRef('exif.assetId', '=', 'assets.id').selectAll().as('exif'), + (join) => join.onTrue(), + ) + .as('assets'), + (join) => join.onTrue(), + ) + .select((eb) => + eb.fn.coalesce(eb.fn.jsonAgg('assets').filterWhere('assets.id', 'is not', null), sql`'[]'`).as('assets'), + ) + .groupBy('shared_links.id') + .executeTakeFirstOrThrow() as Promise; } } diff --git a/server/src/services/auth.service.spec.ts b/server/src/services/auth.service.spec.ts index da25663f38750..917f3681bdac3 100644 --- a/server/src/services/auth.service.spec.ts +++ b/server/src/services/auth.service.spec.ts @@ -275,7 +275,6 @@ describe('AuthService', () => { describe('validate - shared key', () => { it('should not accept a non-existent key', async () => { - sharedLinkMock.getByKey.mockResolvedValue(null); await expect( sut.authenticate({ headers: { 'x-immich-share-key': 'key' }, diff --git a/server/src/services/shared-link.service.spec.ts b/server/src/services/shared-link.service.spec.ts index 6554421418dec..2d673eb7ca945 100644 --- a/server/src/services/shared-link.service.spec.ts +++ b/server/src/services/shared-link.service.spec.ts @@ -76,7 +76,6 @@ describe(SharedLinkService.name, () => { describe('get', () => { it('should throw an error for an invalid shared link', async () => { - sharedLinkMock.get.mockResolvedValue(null); await expect(sut.get(authStub.user1, 'missing-id')).rejects.toBeInstanceOf(BadRequestException); expect(sharedLinkMock.get).toHaveBeenCalledWith(authStub.user1.user.id, 'missing-id'); expect(sharedLinkMock.update).not.toHaveBeenCalled(); @@ -130,7 +129,6 @@ describe(SharedLinkService.name, () => { albumId: albumStub.oneAsset.id, allowDownload: true, allowUpload: true, - assets: [], description: null, expiresAt: null, showExif: true, @@ -160,7 +158,7 @@ describe(SharedLinkService.name, () => { albumId: null, allowDownload: true, allowUpload: true, - assets: [{ id: assetStub.image.id }], + assetIds: [assetStub.image.id], description: null, expiresAt: null, showExif: true, @@ -190,7 +188,7 @@ describe(SharedLinkService.name, () => { albumId: null, allowDownload: false, allowUpload: true, - assets: [{ id: assetStub.image.id }], + assetIds: [assetStub.image.id], description: null, expiresAt: null, showExif: false, @@ -201,7 +199,6 @@ describe(SharedLinkService.name, () => { describe('update', () => { it('should throw an error for an invalid shared link', async () => { - sharedLinkMock.get.mockResolvedValue(null); await expect(sut.update(authStub.user1, 'missing-id', {})).rejects.toBeInstanceOf(BadRequestException); expect(sharedLinkMock.get).toHaveBeenCalledWith(authStub.user1.user.id, 'missing-id'); expect(sharedLinkMock.update).not.toHaveBeenCalled(); @@ -222,7 +219,6 @@ describe(SharedLinkService.name, () => { describe('remove', () => { it('should throw an error for an invalid shared link', async () => { - sharedLinkMock.get.mockResolvedValue(null); await expect(sut.remove(authStub.user1, 'missing-id')).rejects.toBeInstanceOf(BadRequestException); expect(sharedLinkMock.get).toHaveBeenCalledWith(authStub.user1.user.id, 'missing-id'); expect(sharedLinkMock.update).not.toHaveBeenCalled(); @@ -258,9 +254,10 @@ describe(SharedLinkService.name, () => { ]); expect(accessMock.asset.checkOwnerAccess).toHaveBeenCalledTimes(1); + expect(sharedLinkMock.update).toHaveBeenCalled(); expect(sharedLinkMock.update).toHaveBeenCalledWith({ ...sharedLinkStub.individual, - assets: [assetStub.image, { id: 'asset-3' }], + assetIds: ['asset-3'], }); }); }); diff --git a/server/src/services/shared-link.service.ts b/server/src/services/shared-link.service.ts index 5ef140d26dbb5..a015bbe3f31fc 100644 --- a/server/src/services/shared-link.service.ts +++ b/server/src/services/shared-link.service.ts @@ -10,7 +10,6 @@ import { SharedLinkPasswordDto, SharedLinkResponseDto, } from 'src/dtos/shared-link.dto'; -import { AssetEntity } from 'src/entities/asset.entity'; import { SharedLinkEntity } from 'src/entities/shared-link.entity'; import { Permission, SharedLinkType } from 'src/enum'; import { BaseService } from 'src/services/base.service'; @@ -67,7 +66,7 @@ export class SharedLinkService extends BaseService { userId: auth.user.id, type: dto.type, albumId: dto.albumId || null, - assets: (dto.assetIds || []).map((id) => ({ id }) as AssetEntity), + assetIds: dto.assetIds, description: dto.description || null, password: dto.password, expiresAt: dto.expiresAt || null, @@ -138,10 +137,12 @@ export class SharedLinkService extends BaseService { } results.push({ assetId, success: true }); - sharedLink.assets.push({ id: assetId } as AssetEntity); } - await this.sharedLinkRepository.update(sharedLink); + await this.sharedLinkRepository.update({ + ...sharedLink, + assetIds: results.filter(({ success }) => success).map(({ assetId }) => assetId), + }); return results; }