From 378bd3c993a0da5769b25540284fe1a2eda0184c Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 16 Jan 2025 09:25:03 -0600 Subject: [PATCH] refactor: migrate access repo to kysely (#15365) --- server/src/queries/access.repository.sql | 409 ++++++++--------- server/src/repositories/access.repository.ts | 439 +++++++++---------- 2 files changed, 369 insertions(+), 479 deletions(-) diff --git a/server/src/queries/access.repository.sql b/server/src/queries/access.repository.sql index ad57eac0ad90d..db69ac670e024 100644 --- a/server/src/queries/access.repository.sql +++ b/server/src/queries/access.repository.sql @@ -1,180 +1,137 @@ -- NOTE: This file is auto generated by ./sql-generator -- AccessRepository.activity.checkOwnerAccess -SELECT - "ActivityEntity"."id" AS "ActivityEntity_id" -FROM - "activity" "ActivityEntity" -WHERE - ( - ("ActivityEntity"."id" IN ($1)) - AND ("ActivityEntity"."userId" = $2) - ) +select + "activity"."id" +from + "activity" +where + "activity"."id" in ($1) + and "activity"."userId" = $2 -- AccessRepository.activity.checkAlbumOwnerAccess -SELECT - "ActivityEntity"."id" AS "ActivityEntity_id" -FROM - "activity" "ActivityEntity" - LEFT JOIN "albums" "ActivityEntity__ActivityEntity_album" ON "ActivityEntity__ActivityEntity_album"."id" = "ActivityEntity"."albumId" - AND ( - "ActivityEntity__ActivityEntity_album"."deletedAt" IS NULL - ) -WHERE - ( - ("ActivityEntity"."id" IN ($1)) - AND ( - ( - ( - "ActivityEntity__ActivityEntity_album"."ownerId" = $2 - ) - ) - ) - ) +select + "activity"."id" +from + "activity" + left join "albums" on "activity"."albumId" = "albums"."id" + and "albums"."deletedAt" is null +where + "activity"."id" in ($1) + and "albums"."ownerId" = $2::uuid -- AccessRepository.activity.checkCreateAccess -SELECT - "album"."id" AS "album_id" -FROM - "albums" "album" - LEFT JOIN "albums_shared_users_users" "album_albumUsers_users" ON "album_albumUsers_users"."albumsId" = "album"."id" - LEFT JOIN "users" "albumUsers" ON "albumUsers"."id" = "album_albumUsers_users"."usersId" - AND ("albumUsers"."deletedAt" IS NULL) -WHERE - ( - "album"."id" IN ($1) - AND "album"."isActivityEnabled" = true - AND ( - "album"."ownerId" = $2 - OR "albumUsers"."id" = $2 - ) - ) - AND ("album"."deletedAt" IS NULL) +select + "albums"."id" +from + "albums" + left join "albums_shared_users_users" as "albumUsers" on "albumUsers"."albumsId" = "albums"."id" + left join "users" on "users"."id" = "albumUsers"."usersId" + and "users"."deletedAt" is null +where + "albums"."id" in ($1) + and "albums"."isActivityEnabled" = $2 + and ( + "albums"."ownerId" = $3 + or "users"."id" = $4 + ) + and "albums"."deletedAt" is null -- AccessRepository.album.checkOwnerAccess -SELECT - "AlbumEntity"."id" AS "AlbumEntity_id" -FROM - "albums" "AlbumEntity" -WHERE - ( - ( - ("AlbumEntity"."id" IN ($1)) - AND ("AlbumEntity"."ownerId" = $2) - ) - ) - AND ("AlbumEntity"."deletedAt" IS NULL) +select + "albums"."id" +from + "albums" +where + "albums"."id" in ($1) + and "albums"."ownerId" = $2 + and "albums"."deletedAt" is null -- AccessRepository.album.checkSharedAlbumAccess -SELECT - "AlbumEntity"."id" AS "AlbumEntity_id" -FROM - "albums" "AlbumEntity" - LEFT JOIN "albums_shared_users_users" "AlbumEntity__AlbumEntity_albumUsers" ON "AlbumEntity__AlbumEntity_albumUsers"."albumsId" = "AlbumEntity"."id" - LEFT JOIN "users" "a641d58cf46d4a391ba060ac4dc337665c69ffea" ON "a641d58cf46d4a391ba060ac4dc337665c69ffea"."id" = "AlbumEntity__AlbumEntity_albumUsers"."usersId" - AND ( - "a641d58cf46d4a391ba060ac4dc337665c69ffea"."deletedAt" IS NULL - ) -WHERE - ( - ( - ("AlbumEntity"."id" IN ($1)) - AND ( - ( - ( - ( - ( - "a641d58cf46d4a391ba060ac4dc337665c69ffea"."id" = $2 - ) - ) - ) - AND ( - "AlbumEntity__AlbumEntity_albumUsers"."role" IN ($3, $4) - ) - ) - ) - ) - ) - AND ("AlbumEntity"."deletedAt" IS NULL) +select + "albums"."id" +from + "albums" + left join "albums_shared_users_users" as "albumUsers" on "albumUsers"."albumsId" = "albums"."id" + left join "users" on "users"."id" = "albumUsers"."usersId" + and "users"."deletedAt" is null +where + "albums"."id" in ($1) + and "albums"."deletedAt" is null + and "users"."id" = $2 + and "albumUsers"."role" in ($3, $4) -- AccessRepository.album.checkSharedLinkAccess -SELECT - "SharedLinkEntity"."albumId" AS "SharedLinkEntity_albumId", - "SharedLinkEntity"."id" AS "SharedLinkEntity_id" -FROM - "shared_links" "SharedLinkEntity" -WHERE - ( - ("SharedLinkEntity"."id" = $1) - AND ("SharedLinkEntity"."albumId" IN ($2)) - ) +select + "shared_links"."albumId" +from + "shared_links" +where + "shared_links"."id" = $1 + and "shared_links"."albumId" in ($2) -- AccessRepository.asset.checkAlbumAccess -SELECT - "asset"."id" AS "assetId", - "asset"."livePhotoVideoId" AS "livePhotoVideoId" -FROM - "albums" "album" - INNER JOIN "albums_assets_assets" "album_asset" ON "album_asset"."albumsId" = "album"."id" - INNER JOIN "assets" "asset" ON "asset"."id" = "album_asset"."assetsId" - AND ("asset"."deletedAt" IS NULL) - LEFT JOIN "albums_shared_users_users" "album_albumUsers_users" ON "album_albumUsers_users"."albumsId" = "album"."id" - LEFT JOIN "users" "albumUsers" ON "albumUsers"."id" = "album_albumUsers_users"."usersId" - AND ("albumUsers"."deletedAt" IS NULL) -WHERE - ( - array["asset"."id", "asset"."livePhotoVideoId"] && array[$1]::uuid [] - AND ( - "album"."ownerId" = $2 - OR "albumUsers"."id" = $2 - ) - ) - AND ("album"."deletedAt" IS NULL) +select + "assets"."id", + "assets"."livePhotoVideoId" +from + "albums" + inner join "albums_assets_assets" as "albumAssets" on "albums"."id" = "albumAssets"."albumsId" + inner join "assets" on "assets"."id" = "albumAssets"."assetsId" + and "assets"."deletedAt" is null + left join "albums_shared_users_users" as "albumUsers" on "albumUsers"."albumsId" = "albums"."id" + left join "users" on "users"."id" = "albumUsers"."usersId" + and "users"."deletedAt" is null +where + array["assets"."id", "assets"."livePhotoVideoId"] && array[$1]::uuid [] + and ( + "albums"."ownerId" = $2 + or "users"."id" = $3 + ) + and "albums"."deletedAt" is null -- AccessRepository.asset.checkOwnerAccess -SELECT - "AssetEntity"."id" AS "AssetEntity_id" -FROM - "assets" "AssetEntity" -WHERE - ( - ("AssetEntity"."id" IN ($1)) - AND ("AssetEntity"."ownerId" = $2) - ) +select + "assets"."id" +from + "assets" +where + "assets"."id" in ($1) + and "assets"."ownerId" = $2 -- AccessRepository.asset.checkPartnerAccess -SELECT - "asset"."id" AS "assetId" -FROM - "partners" "partner" - INNER JOIN "users" "sharedBy" ON "sharedBy"."id" = "partner"."sharedById" - AND ("sharedBy"."deletedAt" IS NULL) - INNER JOIN "assets" "asset" ON "asset"."ownerId" = "sharedBy"."id" - AND ("asset"."deletedAt" IS NULL) -WHERE +select + "assets"."id" +from + "partners" as "partner" + inner join "users" as "sharedBy" on "sharedBy"."id" = "partner"."sharedById" + and "sharedBy"."deletedAt" is null + inner join "assets" on "assets"."ownerId" = "sharedBy"."id" + and "assets"."deletedAt" is null +where "partner"."sharedWithId" = $1 - AND "asset"."isArchived" = false - AND "asset"."id" IN ($2) + and "assets"."isArchived" = $2 + and "assets"."id" in ($3) -- AccessRepository.asset.checkSharedLinkAccess -SELECT - "assets"."id" AS "assetId", - "assets"."livePhotoVideoId" AS "assetLivePhotoVideoId", - "albumAssets"."id" AS "albumAssetId", - "albumAssets"."livePhotoVideoId" AS "albumAssetLivePhotoVideoId" -FROM - "shared_links" "sharedLink" - LEFT JOIN "albums" "album" ON "album"."id" = "sharedLink"."albumId" - AND ("album"."deletedAt" IS NULL) - LEFT JOIN "shared_link__asset" "assets_sharedLink" ON "assets_sharedLink"."sharedLinksId" = "sharedLink"."id" - LEFT JOIN "assets" "assets" ON "assets"."id" = "assets_sharedLink"."assetsId" - AND ("assets"."deletedAt" IS NULL) - LEFT JOIN "albums_assets_assets" "album_albumAssets" ON "album_albumAssets"."albumsId" = "album"."id" - LEFT JOIN "assets" "albumAssets" ON "albumAssets"."id" = "album_albumAssets"."assetsId" - AND ("albumAssets"."deletedAt" IS NULL) -WHERE - "sharedLink"."id" = $1 - AND array[ +select + "assets"."id" as "assetId", + "assets"."livePhotoVideoId" as "assetLivePhotoVideoId", + "albumAssets"."id" as "albumAssetId", + "albumAssets"."livePhotoVideoId" as "albumAssetLivePhotoVideoId" +from + "shared_links" + left join "albums" on "albums"."id" = "shared_links"."albumId" + and "albums"."deletedAt" is null + left join "shared_link__asset" on "shared_link__asset"."sharedLinksId" = "shared_links"."id" + left join "assets" on "assets"."id" = "shared_link__asset"."assetsId" + and "assets"."deletedAt" is null + left join "albums_assets_assets" on "albums_assets_assets"."albumsId" = "albums"."id" + left join "assets" as "albumAssets" on "albumAssets"."id" = "albums_assets_assets"."assetsId" + and "albumAssets"."deletedAt" is null +where + "shared_links"."id" = $1 + and array[ "assets"."id", "assets"."livePhotoVideoId", "albumAssets"."id", @@ -182,100 +139,76 @@ WHERE ] && array[$2]::uuid [] -- AccessRepository.authDevice.checkOwnerAccess -SELECT - "SessionEntity"."id" AS "SessionEntity_id" -FROM - "sessions" "SessionEntity" -WHERE - ( - ("SessionEntity"."userId" = $1) - AND ("SessionEntity"."id" IN ($2)) - ) +select + "sessions"."id" +from + "sessions" +where + "sessions"."userId" = $1 + and "sessions"."id" in ($2) -- AccessRepository.memory.checkOwnerAccess -SELECT - "MemoryEntity"."id" AS "MemoryEntity_id" -FROM - "memories" "MemoryEntity" -WHERE - ( - ( - ("MemoryEntity"."id" IN ($1)) - AND ("MemoryEntity"."ownerId" = $2) - ) - ) - AND ("MemoryEntity"."deletedAt" IS NULL) +select + "memories"."id" +from + "memories" +where + "memories"."id" in ($1) + and "memories"."ownerId" = $2 + and "memories"."deletedAt" is null -- AccessRepository.person.checkOwnerAccess -SELECT - "PersonEntity"."id" AS "PersonEntity_id" -FROM - "person" "PersonEntity" -WHERE - ( - ("PersonEntity"."id" IN ($1)) - AND ("PersonEntity"."ownerId" = $2) - ) +select + "person"."id" +from + "person" +where + "person"."id" in ($1) + and "person"."ownerId" = $2 -- AccessRepository.person.checkFaceOwnerAccess -SELECT - "AssetFaceEntity"."id" AS "AssetFaceEntity_id" -FROM - "asset_faces" "AssetFaceEntity" - LEFT JOIN "assets" "AssetFaceEntity__AssetFaceEntity_asset" ON "AssetFaceEntity__AssetFaceEntity_asset"."id" = "AssetFaceEntity"."assetId" - AND ( - "AssetFaceEntity__AssetFaceEntity_asset"."deletedAt" IS NULL - ) -WHERE - ( - ("AssetFaceEntity"."id" IN ($1)) - AND ( - ( - ( - "AssetFaceEntity__AssetFaceEntity_asset"."ownerId" = $2 - ) - ) - ) - ) +select + "asset_faces"."id" +from + "asset_faces" + left join "assets" on "assets"."id" = "asset_faces"."assetId" + and "assets"."deletedAt" is null +where + "asset_faces"."id" in ($1) + and "assets"."ownerId" = $2 -- AccessRepository.partner.checkUpdateAccess -SELECT - "partner"."sharedById" AS "partner_sharedById", - "partner"."sharedWithId" AS "partner_sharedWithId" -FROM - "partners" "partner" -WHERE - "partner"."sharedById" IN ($1) - AND "partner"."sharedWithId" = $2 +select + "partners"."sharedById" +from + "partners" +where + "partners"."sharedById" in ($1) + and "partners"."sharedWithId" = $2 -- AccessRepository.stack.checkOwnerAccess -SELECT - "StackEntity"."id" AS "StackEntity_id" -FROM - "asset_stack" "StackEntity" -WHERE - ( - ("StackEntity"."id" IN ($1)) - AND ("StackEntity"."ownerId" = $2) - ) +select + "stacks"."id" +from + "asset_stack" as "stacks" +where + "stacks"."id" in ($1) + and "stacks"."ownerId" = $2 -- AccessRepository.tag.checkOwnerAccess -SELECT - "TagEntity"."id" AS "TagEntity_id" -FROM - "tags" "TagEntity" -WHERE - ( - ("TagEntity"."id" IN ($1)) - AND ("TagEntity"."userId" = $2) - ) +select + "tags"."id" +from + "tags" +where + "tags"."id" in ($1) + and "tags"."userId" = $2 -- AccessRepository.timeline.checkPartnerAccess -SELECT - "partner"."sharedById" AS "partner_sharedById", - "partner"."sharedWithId" AS "partner_sharedWithId" -FROM - "partners" "partner" -WHERE - "partner"."sharedById" IN ($1) - AND "partner"."sharedWithId" = $2 +select + "partners"."sharedById" +from + "partners" +where + "partners"."sharedById" in ($1) + and "partners"."sharedWithId" = $2 diff --git a/server/src/repositories/access.repository.ts b/server/src/repositories/access.repository.ts index f3cbf392db295..15288b94fa274 100644 --- a/server/src/repositories/access.repository.ts +++ b/server/src/repositories/access.repository.ts @@ -1,21 +1,12 @@ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; +import { Kysely, sql } from 'kysely'; +import { InjectKysely } from 'nestjs-kysely'; +import { DB } from 'src/db'; import { ChunkedSet, DummyValue, GenerateSql } from 'src/decorators'; -import { ActivityEntity } from 'src/entities/activity.entity'; -import { AlbumEntity } from 'src/entities/album.entity'; -import { AssetFaceEntity } from 'src/entities/asset-face.entity'; -import { AssetEntity } from 'src/entities/asset.entity'; -import { LibraryEntity } from 'src/entities/library.entity'; -import { MemoryEntity } from 'src/entities/memory.entity'; -import { PartnerEntity } from 'src/entities/partner.entity'; -import { PersonEntity } from 'src/entities/person.entity'; -import { SessionEntity } from 'src/entities/session.entity'; -import { SharedLinkEntity } from 'src/entities/shared-link.entity'; -import { StackEntity } from 'src/entities/stack.entity'; -import { TagEntity } from 'src/entities/tag.entity'; + import { AlbumUserRole } from 'src/enum'; import { IAccessRepository } from 'src/interfaces/access.interface'; -import { Brackets, In, Repository } from 'typeorm'; +import { asUuid } from 'src/utils/database'; type IActivityAccess = IAccessRepository['activity']; type IAlbumAccess = IAccessRepository['album']; @@ -30,10 +21,7 @@ type ITimelineAccess = IAccessRepository['timeline']; @Injectable() class ActivityAccess implements IActivityAccess { - constructor( - private activityRepository: Repository, - private albumRepository: Repository, - ) {} + constructor(private db: Kysely) {} @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) @ChunkedSet({ paramIndex: 1 }) @@ -42,15 +30,16 @@ class ActivityAccess implements IActivityAccess { return new Set(); } - return this.activityRepository - .find({ - select: { id: true }, - where: { - id: In([...activityIds]), - userId, - }, - }) - .then((activities) => new Set(activities.map((activity) => activity.id))); + return this.db + .selectFrom('activity') + .select('activity.id') + .where('activity.id', 'in', [...activityIds]) + .where('activity.userId', '=', userId) + .execute() + .then((activities) => { + console.log('activities', activities); + return new Set(activities.map((activity) => activity.id)); + }); } @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) @@ -60,16 +49,13 @@ class ActivityAccess implements IActivityAccess { return new Set(); } - return this.activityRepository - .find({ - select: { id: true }, - where: { - id: In([...activityIds]), - album: { - ownerId: userId, - }, - }, - }) + return this.db + .selectFrom('activity') + .select('activity.id') + .leftJoin('albums', (join) => join.onRef('activity.albumId', '=', 'albums.id').on('albums.deletedAt', 'is', null)) + .where('activity.id', 'in', [...activityIds]) + .whereRef('albums.ownerId', '=', asUuid(userId)) + .execute() .then((activities) => new Set(activities.map((activity) => activity.id))); } @@ -80,28 +66,22 @@ class ActivityAccess implements IActivityAccess { return new Set(); } - return this.albumRepository - .createQueryBuilder('album') - .select('album.id') - .leftJoin('album.albumUsers', 'album_albumUsers_users') - .leftJoin('album_albumUsers_users.user', 'albumUsers') - .where('album.id IN (:...albumIds)', { albumIds: [...albumIds] }) - .andWhere('album.isActivityEnabled = true') - .andWhere( - new Brackets((qb) => { - qb.where('album.ownerId = :userId', { userId }).orWhere('albumUsers.id = :userId', { userId }); - }), - ) - .getMany() + return this.db + .selectFrom('albums') + .select('albums.id') + .leftJoin('albums_shared_users_users as albumUsers', 'albumUsers.albumsId', 'albums.id') + .leftJoin('users', (join) => join.onRef('users.id', '=', 'albumUsers.usersId').on('users.deletedAt', 'is', null)) + .where('albums.id', 'in', [...albumIds]) + .where('albums.isActivityEnabled', '=', true) + .where((eb) => eb.or([eb('albums.ownerId', '=', userId), eb('users.id', '=', userId)])) + .where('albums.deletedAt', 'is', null) + .execute() .then((albums) => new Set(albums.map((album) => album.id))); } } class AlbumAccess implements IAlbumAccess { - constructor( - private albumRepository: Repository, - private sharedLinkRepository: Repository, - ) {} + constructor(private db: Kysely) {} @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) @ChunkedSet({ paramIndex: 1 }) @@ -110,14 +90,13 @@ class AlbumAccess implements IAlbumAccess { return new Set(); } - return this.albumRepository - .find({ - select: { id: true }, - where: { - id: In([...albumIds]), - ownerId: userId, - }, - }) + return this.db + .selectFrom('albums') + .select('albums.id') + .where('albums.id', 'in', [...albumIds]) + .where('albums.ownerId', '=', userId) + .where('albums.deletedAt', 'is', null) + .execute() .then((albums) => new Set(albums.map((album) => album.id))); } @@ -128,19 +107,19 @@ class AlbumAccess implements IAlbumAccess { return new Set(); } - return this.albumRepository - .find({ - select: { id: true }, - where: { - id: In([...albumIds]), - albumUsers: { - user: { id: userId }, - // If editor access is needed we check for it, otherwise both are accepted - role: - access === AlbumUserRole.EDITOR ? AlbumUserRole.EDITOR : In([AlbumUserRole.EDITOR, AlbumUserRole.VIEWER]), - }, - }, - }) + const accessRole = + access === AlbumUserRole.EDITOR ? [AlbumUserRole.EDITOR] : [AlbumUserRole.EDITOR, AlbumUserRole.VIEWER]; + + return this.db + .selectFrom('albums') + .select('albums.id') + .leftJoin('albums_shared_users_users as albumUsers', 'albumUsers.albumsId', 'albums.id') + .leftJoin('users', (join) => join.onRef('users.id', '=', 'albumUsers.usersId').on('users.deletedAt', 'is', null)) + .where('albums.id', 'in', [...albumIds]) + .where('albums.deletedAt', 'is', null) + .where('users.id', '=', userId) + .where('albumUsers.role', 'in', [...accessRole]) + .execute() .then((albums) => new Set(albums.map((album) => album.id))); } @@ -151,14 +130,12 @@ class AlbumAccess implements IAlbumAccess { return new Set(); } - return this.sharedLinkRepository - .find({ - select: { albumId: true }, - where: { - id: sharedLinkId, - albumId: In([...albumIds]), - }, - }) + return this.db + .selectFrom('shared_links') + .select('shared_links.albumId') + .where('shared_links.id', '=', sharedLinkId) + .where('shared_links.albumId', 'in', [...albumIds]) + .execute() .then( (sharedLinks) => new Set(sharedLinks.flatMap((sharedLink) => (sharedLink.albumId ? [sharedLink.albumId] : []))), ); @@ -166,12 +143,7 @@ class AlbumAccess implements IAlbumAccess { } class AssetAccess implements IAssetAccess { - constructor( - private albumRepository: Repository, - private assetRepository: Repository, - private partnerRepository: Repository, - private sharedLinkRepository: Repository, - ) {} + constructor(private db: Kysely) {} @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) @ChunkedSet({ paramIndex: 1 }) @@ -180,30 +152,31 @@ class AssetAccess implements IAssetAccess { return new Set(); } - return this.albumRepository - .createQueryBuilder('album') - .innerJoin('album.assets', 'asset') - .leftJoin('album.albumUsers', 'album_albumUsers_users') - .leftJoin('album_albumUsers_users.user', 'albumUsers') - .select('asset.id', 'assetId') - .addSelect('asset.livePhotoVideoId', 'livePhotoVideoId') - .where('array["asset"."id", "asset"."livePhotoVideoId"] && array[:...assetIds]::uuid[]', { - assetIds: [...assetIds], - }) - .andWhere( - new Brackets((qb) => { - qb.where('album.ownerId = :userId', { userId }).orWhere('albumUsers.id = :userId', { userId }); - }), + return this.db + .selectFrom('albums') + .innerJoin('albums_assets_assets as albumAssets', 'albums.id', 'albumAssets.albumsId') + .innerJoin('assets', (join) => + join.onRef('assets.id', '=', 'albumAssets.assetsId').on('assets.deletedAt', 'is', null), ) - .getRawMany() - .then((rows) => { + .leftJoin('albums_shared_users_users as albumUsers', 'albumUsers.albumsId', 'albums.id') + .leftJoin('users', (join) => join.onRef('users.id', '=', 'albumUsers.usersId').on('users.deletedAt', 'is', null)) + .select(['assets.id', 'assets.livePhotoVideoId']) + .where( + sql`array["assets"."id", "assets"."livePhotoVideoId"]`, + '&&', + sql`array[${sql.join([...assetIds])}]::uuid[] `, + ) + .where((eb) => eb.or([eb('albums.ownerId', '=', userId), eb('users.id', '=', userId)])) + .where('albums.deletedAt', 'is', null) + .execute() + .then((assets) => { const allowedIds = new Set(); - for (const row of rows) { - if (row.assetId && assetIds.has(row.assetId)) { - allowedIds.add(row.assetId); + for (const asset of assets) { + if (asset.id && assetIds.has(asset.id)) { + allowedIds.add(asset.id); } - if (row.livePhotoVideoId && assetIds.has(row.livePhotoVideoId)) { - allowedIds.add(row.livePhotoVideoId); + if (asset.livePhotoVideoId && assetIds.has(asset.livePhotoVideoId)) { + allowedIds.add(asset.livePhotoVideoId); } } return allowedIds; @@ -217,15 +190,12 @@ class AssetAccess implements IAssetAccess { return new Set(); } - return this.assetRepository - .find({ - select: { id: true }, - where: { - id: In([...assetIds]), - ownerId: userId, - }, - withDeleted: true, - }) + return this.db + .selectFrom('assets') + .select('assets.id') + .where('assets.id', 'in', [...assetIds]) + .where('assets.ownerId', '=', userId) + .execute() .then((assets) => new Set(assets.map((asset) => asset.id))); } @@ -236,16 +206,20 @@ class AssetAccess implements IAssetAccess { return new Set(); } - return this.partnerRepository - .createQueryBuilder('partner') - .innerJoin('partner.sharedBy', 'sharedBy') - .innerJoin('sharedBy.assets', 'asset') - .select('asset.id', 'assetId') - .where('partner.sharedWithId = :userId', { userId }) - .andWhere('asset.isArchived = false') - .andWhere('asset.id IN (:...assetIds)', { assetIds: [...assetIds] }) - .getRawMany() - .then((rows) => new Set(rows.map((row) => row.assetId))); + return this.db + .selectFrom('partners as partner') + .innerJoin('users as sharedBy', (join) => + join.onRef('sharedBy.id', '=', 'partner.sharedById').on('sharedBy.deletedAt', 'is', null), + ) + .innerJoin('assets', (join) => + join.onRef('assets.ownerId', '=', 'sharedBy.id').on('assets.deletedAt', 'is', null), + ) + .select('assets.id') + .where('partner.sharedWithId', '=', userId) + .where('assets.isArchived', '=', false) + .where('assets.id', 'in', [...assetIds]) + .execute() + .then((assets) => new Set(assets.map((asset) => asset.id))); } @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) @@ -255,23 +229,32 @@ class AssetAccess implements IAssetAccess { return new Set(); } - return this.sharedLinkRepository - .createQueryBuilder('sharedLink') - .leftJoin('sharedLink.album', 'album') - .leftJoin('sharedLink.assets', 'assets') - .leftJoin('album.assets', 'albumAssets') - .select('assets.id', 'assetId') - .addSelect('albumAssets.id', 'albumAssetId') - .addSelect('assets.livePhotoVideoId', 'assetLivePhotoVideoId') - .addSelect('albumAssets.livePhotoVideoId', 'albumAssetLivePhotoVideoId') - .where('sharedLink.id = :sharedLinkId', { sharedLinkId }) - .andWhere( - 'array["assets"."id", "assets"."livePhotoVideoId", "albumAssets"."id", "albumAssets"."livePhotoVideoId"] && array[:...assetIds]::uuid[]', - { - assetIds: [...assetIds], - }, + return this.db + .selectFrom('shared_links') + .leftJoin('albums', (join) => + join.onRef('albums.id', '=', 'shared_links.albumId').on('albums.deletedAt', 'is', null), ) - .getRawMany() + .leftJoin('shared_link__asset', 'shared_link__asset.sharedLinksId', 'shared_links.id') + .leftJoin('assets', (join) => + join.onRef('assets.id', '=', 'shared_link__asset.assetsId').on('assets.deletedAt', 'is', null), + ) + .leftJoin('albums_assets_assets', 'albums_assets_assets.albumsId', 'albums.id') + .leftJoin('assets as albumAssets', (join) => + join.onRef('albumAssets.id', '=', 'albums_assets_assets.assetsId').on('albumAssets.deletedAt', 'is', null), + ) + .select([ + 'assets.id as assetId', + 'assets.livePhotoVideoId as assetLivePhotoVideoId', + 'albumAssets.id as albumAssetId', + 'albumAssets.livePhotoVideoId as albumAssetLivePhotoVideoId', + ]) + .where('shared_links.id', '=', sharedLinkId) + .where( + sql`array["assets"."id", "assets"."livePhotoVideoId", "albumAssets"."id", "albumAssets"."livePhotoVideoId"]`, + '&&', + sql`array[${sql.join([...assetIds])}]::uuid[] `, + ) + .execute() .then((rows) => { const allowedIds = new Set(); for (const row of rows) { @@ -294,7 +277,7 @@ class AssetAccess implements IAssetAccess { } class AuthDeviceAccess implements IAuthDeviceAccess { - constructor(private sessionRepository: Repository) {} + constructor(private db: Kysely) {} @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) @ChunkedSet({ paramIndex: 1 }) @@ -303,20 +286,18 @@ class AuthDeviceAccess implements IAuthDeviceAccess { return new Set(); } - return this.sessionRepository - .find({ - select: { id: true }, - where: { - userId, - id: In([...deviceIds]), - }, - }) + return this.db + .selectFrom('sessions') + .select('sessions.id') + .where('sessions.userId', '=', userId) + .where('sessions.id', 'in', [...deviceIds]) + .execute() .then((tokens) => new Set(tokens.map((token) => token.id))); } } class StackAccess implements IStackAccess { - constructor(private stackRepository: Repository) {} + constructor(private db: Kysely) {} @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) @ChunkedSet({ paramIndex: 1 }) @@ -325,20 +306,18 @@ class StackAccess implements IStackAccess { return new Set(); } - return this.stackRepository - .find({ - select: { id: true }, - where: { - id: In([...stackIds]), - ownerId: userId, - }, - }) + return this.db + .selectFrom('asset_stack as stacks') + .select('stacks.id') + .where('stacks.id', 'in', [...stackIds]) + .where('stacks.ownerId', '=', userId) + .execute() .then((stacks) => new Set(stacks.map((stack) => stack.id))); } } class TimelineAccess implements ITimelineAccess { - constructor(private partnerRepository: Repository) {} + constructor(private db: Kysely) {} @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) @ChunkedSet({ paramIndex: 1 }) @@ -347,18 +326,18 @@ class TimelineAccess implements ITimelineAccess { return new Set(); } - return this.partnerRepository - .createQueryBuilder('partner') - .select('partner.sharedById') - .where('partner.sharedById IN (:...partnerIds)', { partnerIds: [...partnerIds] }) - .andWhere('partner.sharedWithId = :userId', { userId }) - .getMany() + return this.db + .selectFrom('partners') + .select('partners.sharedById') + .where('partners.sharedById', 'in', [...partnerIds]) + .where('partners.sharedWithId', '=', userId) + .execute() .then((partners) => new Set(partners.map((partner) => partner.sharedById))); } } class MemoryAccess implements IMemoryAccess { - constructor(private memoryRepository: Repository) {} + constructor(private db: Kysely) {} @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) @ChunkedSet({ paramIndex: 1 }) @@ -367,23 +346,19 @@ class MemoryAccess implements IMemoryAccess { return new Set(); } - return this.memoryRepository - .find({ - select: { id: true }, - where: { - id: In([...memoryIds]), - ownerId: userId, - }, - }) + return this.db + .selectFrom('memories') + .select('memories.id') + .where('memories.id', 'in', [...memoryIds]) + .where('memories.ownerId', '=', userId) + .where('memories.deletedAt', 'is', null) + .execute() .then((memories) => new Set(memories.map((memory) => memory.id))); } } class PersonAccess implements IPersonAccess { - constructor( - private assetFaceRepository: Repository, - private personRepository: Repository, - ) {} + constructor(private db: Kysely) {} @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) @ChunkedSet({ paramIndex: 1 }) @@ -392,14 +367,12 @@ class PersonAccess implements IPersonAccess { return new Set(); } - return this.personRepository - .find({ - select: { id: true }, - where: { - id: In([...personIds]), - ownerId: userId, - }, - }) + return this.db + .selectFrom('person') + .select('person.id') + .where('person.id', 'in', [...personIds]) + .where('person.ownerId', '=', userId) + .execute() .then((persons) => new Set(persons.map((person) => person.id))); } @@ -410,22 +383,21 @@ class PersonAccess implements IPersonAccess { return new Set(); } - return this.assetFaceRepository - .find({ - select: { id: true }, - where: { - id: In([...assetFaceIds]), - asset: { - ownerId: userId, - }, - }, - }) + return this.db + .selectFrom('asset_faces') + .select('asset_faces.id') + .leftJoin('assets', (join) => + join.onRef('assets.id', '=', 'asset_faces.assetId').on('assets.deletedAt', 'is', null), + ) + .where('asset_faces.id', 'in', [...assetFaceIds]) + .where('assets.ownerId', '=', userId) + .execute() .then((faces) => new Set(faces.map((face) => face.id))); } } class PartnerAccess implements IPartnerAccess { - constructor(private partnerRepository: Repository) {} + constructor(private db: Kysely) {} @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) @ChunkedSet({ paramIndex: 1 }) @@ -434,18 +406,18 @@ class PartnerAccess implements IPartnerAccess { return new Set(); } - return this.partnerRepository - .createQueryBuilder('partner') - .select('partner.sharedById') - .where('partner.sharedById IN (:...partnerIds)', { partnerIds: [...partnerIds] }) - .andWhere('partner.sharedWithId = :userId', { userId }) - .getMany() + return this.db + .selectFrom('partners') + .select('partners.sharedById') + .where('partners.sharedById', 'in', [...partnerIds]) + .where('partners.sharedWithId', '=', userId) + .execute() .then((partners) => new Set(partners.map((partner) => partner.sharedById))); } } class TagAccess implements ITagAccess { - constructor(private tagRepository: Repository) {} + constructor(private db: Kysely) {} @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) @ChunkedSet({ paramIndex: 1 }) @@ -454,14 +426,12 @@ class TagAccess implements ITagAccess { return new Set(); } - return this.tagRepository - .find({ - select: { id: true }, - where: { - id: In([...tagIds]), - userId, - }, - }) + return this.db + .selectFrom('tags') + .select('tags.id') + .where('tags.id', 'in', [...tagIds]) + .where('tags.userId', '=', userId) + .execute() .then((tags) => new Set(tags.map((tag) => tag.id))); } } @@ -478,29 +448,16 @@ export class AccessRepository implements IAccessRepository { tag: ITagAccess; timeline: ITimelineAccess; - constructor( - @InjectRepository(ActivityEntity) activityRepository: Repository, - @InjectRepository(AssetEntity) assetRepository: Repository, - @InjectRepository(AlbumEntity) albumRepository: Repository, - @InjectRepository(LibraryEntity) libraryRepository: Repository, - @InjectRepository(MemoryEntity) memoryRepository: Repository, - @InjectRepository(PartnerEntity) partnerRepository: Repository, - @InjectRepository(PersonEntity) personRepository: Repository, - @InjectRepository(AssetFaceEntity) assetFaceRepository: Repository, - @InjectRepository(SharedLinkEntity) sharedLinkRepository: Repository, - @InjectRepository(SessionEntity) sessionRepository: Repository, - @InjectRepository(StackEntity) stackRepository: Repository, - @InjectRepository(TagEntity) tagRepository: Repository, - ) { - this.activity = new ActivityAccess(activityRepository, albumRepository); - this.album = new AlbumAccess(albumRepository, sharedLinkRepository); - this.asset = new AssetAccess(albumRepository, assetRepository, partnerRepository, sharedLinkRepository); - this.authDevice = new AuthDeviceAccess(sessionRepository); - this.memory = new MemoryAccess(memoryRepository); - this.person = new PersonAccess(assetFaceRepository, personRepository); - this.partner = new PartnerAccess(partnerRepository); - this.stack = new StackAccess(stackRepository); - this.tag = new TagAccess(tagRepository); - this.timeline = new TimelineAccess(partnerRepository); + constructor(@InjectKysely() db: Kysely) { + this.activity = new ActivityAccess(db); + this.album = new AlbumAccess(db); + this.asset = new AssetAccess(db); + this.authDevice = new AuthDeviceAccess(db); + this.memory = new MemoryAccess(db); + this.person = new PersonAccess(db); + this.partner = new PartnerAccess(db); + this.stack = new StackAccess(db); + this.tag = new TagAccess(db); + this.timeline = new TimelineAccess(db); } }