mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 02:39:03 -04:00 
			
		
		
		
	chore(server): Use ChunkedSet in Access repository (#6943)
This change simplifies the Access repository methods, by using the `ChunkedSet` decorator. As the methods expect sets, the `chunks` util needed to be fixed, so it returns chunks of the same type it received. Now `chunks` is overloaded, to have proper typing based on the input parameter.
This commit is contained in:
		
							parent
							
								
									61768ce89e
								
							
						
					
					
						commit
						4164bcfd0d
					
				| @ -178,23 +178,25 @@ export function Optional({ nullable, ...validationOptions }: OptionalOptions = { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Chunks an array or set into smaller arrays of the specified size. |  * Chunks an array or set into smaller collections of the same type and specified size. | ||||||
|  * |  * | ||||||
|  * @param collection The collection to chunk. |  * @param collection The collection to chunk. | ||||||
|  * @param size The size of each chunk. |  * @param size The size of each chunk. | ||||||
|  */ |  */ | ||||||
| export function chunks<T>(collection: Array<T> | Set<T>, size: number): T[][] { | export function chunks<T>(collection: Array<T>, size: number): Array<Array<T>>; | ||||||
|  | export function chunks<T>(collection: Set<T>, size: number): Array<Set<T>>; | ||||||
|  | export function chunks<T>(collection: Array<T> | Set<T>, size: number): Array<Array<T>> | Array<Set<T>> { | ||||||
|   if (collection instanceof Set) { |   if (collection instanceof Set) { | ||||||
|     const result = []; |     const result = []; | ||||||
|     let chunk = []; |     let chunk = new Set<T>(); | ||||||
|     for (const element of collection) { |     for (const element of collection) { | ||||||
|       chunk.push(element); |       chunk.add(element); | ||||||
|       if (chunk.length === size) { |       if (chunk.size === size) { | ||||||
|         result.push(chunk); |         result.push(chunk); | ||||||
|         chunk = []; |         chunk = new Set<T>(); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     if (chunk.length > 0) { |     if (chunk.size > 0) { | ||||||
|       result.push(chunk); |       result.push(chunk); | ||||||
|     } |     } | ||||||
|     return result; |     return result; | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| import { IAccessRepository, chunks, setUnion } from '@app/domain'; | import { IAccessRepository } from '@app/domain'; | ||||||
| import { InjectRepository } from '@nestjs/typeorm'; | import { InjectRepository } from '@nestjs/typeorm'; | ||||||
| import { Brackets, In, Repository } from 'typeorm'; | import { Brackets, In, Repository } from 'typeorm'; | ||||||
| import { | import { | ||||||
| @ -12,7 +12,8 @@ import { | |||||||
|   SharedLinkEntity, |   SharedLinkEntity, | ||||||
|   UserTokenEntity, |   UserTokenEntity, | ||||||
| } from '../entities'; | } from '../entities'; | ||||||
| import { DATABASE_PARAMETER_CHUNK_SIZE, DummyValue, GenerateSql } from '../infra.util'; | import { DummyValue, GenerateSql } from '../infra.util'; | ||||||
|  | import { ChunkedSet } from '../infra.utils'; | ||||||
| 
 | 
 | ||||||
| type IActivityAccess = IAccessRepository['activity']; | type IActivityAccess = IAccessRepository['activity']; | ||||||
| type IAlbumAccess = IAccessRepository['album']; | type IAlbumAccess = IAccessRepository['album']; | ||||||
| @ -30,72 +31,63 @@ class ActivityAccess implements IActivityAccess { | |||||||
|   ) {} |   ) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|  |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkOwnerAccess(userId: string, activityIds: Set<string>): Promise<Set<string>> { |   async checkOwnerAccess(userId: string, activityIds: Set<string>): Promise<Set<string>> { | ||||||
|     if (activityIds.size === 0) { |     if (activityIds.size === 0) { | ||||||
|       return new Set(); |       return new Set(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return Promise.all( |     return this.activityRepository | ||||||
|       chunks(activityIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) => |       .find({ | ||||||
|         this.activityRepository |         select: { id: true }, | ||||||
|           .find({ |         where: { | ||||||
|             select: { id: true }, |           id: In([...activityIds]), | ||||||
|             where: { |           userId, | ||||||
|               id: In(idChunk), |         }, | ||||||
|               userId, |       }) | ||||||
|             }, |       .then((activities) => new Set(activities.map((activity) => activity.id))); | ||||||
|           }) |  | ||||||
|           .then((activities) => new Set(activities.map((activity) => activity.id))), |  | ||||||
|       ), |  | ||||||
|     ).then((results) => setUnion(...results)); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|  |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkAlbumOwnerAccess(userId: string, activityIds: Set<string>): Promise<Set<string>> { |   async checkAlbumOwnerAccess(userId: string, activityIds: Set<string>): Promise<Set<string>> { | ||||||
|     if (activityIds.size === 0) { |     if (activityIds.size === 0) { | ||||||
|       return new Set(); |       return new Set(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return Promise.all( |     return this.activityRepository | ||||||
|       chunks(activityIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) => |       .find({ | ||||||
|         this.activityRepository |         select: { id: true }, | ||||||
|           .find({ |         where: { | ||||||
|             select: { id: true }, |           id: In([...activityIds]), | ||||||
|             where: { |           album: { | ||||||
|               id: In(idChunk), |             ownerId: userId, | ||||||
|               album: { |           }, | ||||||
|                 ownerId: userId, |         }, | ||||||
|               }, |       }) | ||||||
|             }, |       .then((activities) => new Set(activities.map((activity) => activity.id))); | ||||||
|           }) |  | ||||||
|           .then((activities) => new Set(activities.map((activity) => activity.id))), |  | ||||||
|       ), |  | ||||||
|     ).then((results) => setUnion(...results)); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|  |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkCreateAccess(userId: string, albumIds: Set<string>): Promise<Set<string>> { |   async checkCreateAccess(userId: string, albumIds: Set<string>): Promise<Set<string>> { | ||||||
|     if (albumIds.size === 0) { |     if (albumIds.size === 0) { | ||||||
|       return new Set(); |       return new Set(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return Promise.all( |     return this.albumRepository | ||||||
|       chunks(albumIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) => |       .createQueryBuilder('album') | ||||||
|         this.albumRepository |       .select('album.id') | ||||||
|           .createQueryBuilder('album') |       .leftJoin('album.sharedUsers', 'sharedUsers') | ||||||
|           .select('album.id') |       .where('album.id IN (:...albumIds)', { albumIds: [...albumIds] }) | ||||||
|           .leftJoin('album.sharedUsers', 'sharedUsers') |       .andWhere('album.isActivityEnabled = true') | ||||||
|           .where('album.id IN (:...albumIds)', { albumIds: idChunk }) |       .andWhere( | ||||||
|           .andWhere('album.isActivityEnabled = true') |         new Brackets((qb) => { | ||||||
|           .andWhere( |           qb.where('album.ownerId = :userId', { userId }).orWhere('sharedUsers.id = :userId', { userId }); | ||||||
|             new Brackets((qb) => { |         }), | ||||||
|               qb.where('album.ownerId = :userId', { userId }).orWhere('sharedUsers.id = :userId', { userId }); |       ) | ||||||
|             }), |       .getMany() | ||||||
|           ) |       .then((albums) => new Set(albums.map((album) => album.id))); | ||||||
|           .getMany() |  | ||||||
|           .then((albums) => new Set(albums.map((album) => album.id))), |  | ||||||
|       ), |  | ||||||
|     ).then((results) => setUnion(...results)); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -106,71 +98,61 @@ class AlbumAccess implements IAlbumAccess { | |||||||
|   ) {} |   ) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|  |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkOwnerAccess(userId: string, albumIds: Set<string>): Promise<Set<string>> { |   async checkOwnerAccess(userId: string, albumIds: Set<string>): Promise<Set<string>> { | ||||||
|     if (albumIds.size === 0) { |     if (albumIds.size === 0) { | ||||||
|       return new Set(); |       return new Set(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return Promise.all( |     return this.albumRepository | ||||||
|       chunks(albumIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) => |       .find({ | ||||||
|         this.albumRepository |         select: { id: true }, | ||||||
|           .find({ |         where: { | ||||||
|             select: { id: true }, |           id: In([...albumIds]), | ||||||
|             where: { |           ownerId: userId, | ||||||
|               id: In(idChunk), |         }, | ||||||
|               ownerId: userId, |       }) | ||||||
|             }, |       .then((albums) => new Set(albums.map((album) => album.id))); | ||||||
|           }) |  | ||||||
|           .then((albums) => new Set(albums.map((album) => album.id))), |  | ||||||
|       ), |  | ||||||
|     ).then((results) => setUnion(...results)); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|  |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkSharedAlbumAccess(userId: string, albumIds: Set<string>): Promise<Set<string>> { |   async checkSharedAlbumAccess(userId: string, albumIds: Set<string>): Promise<Set<string>> { | ||||||
|     if (albumIds.size === 0) { |     if (albumIds.size === 0) { | ||||||
|       return new Set(); |       return new Set(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return Promise.all( |     return this.albumRepository | ||||||
|       chunks(albumIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) => |       .find({ | ||||||
|         this.albumRepository |         select: { id: true }, | ||||||
|           .find({ |         where: { | ||||||
|             select: { id: true }, |           id: In([...albumIds]), | ||||||
|             where: { |           sharedUsers: { | ||||||
|               id: In(idChunk), |             id: userId, | ||||||
|               sharedUsers: { |           }, | ||||||
|                 id: userId, |         }, | ||||||
|               }, |       }) | ||||||
|             }, |       .then((albums) => new Set(albums.map((album) => album.id))); | ||||||
|           }) |  | ||||||
|           .then((albums) => new Set(albums.map((album) => album.id))), |  | ||||||
|       ), |  | ||||||
|     ).then((results) => setUnion(...results)); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|  |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkSharedLinkAccess(sharedLinkId: string, albumIds: Set<string>): Promise<Set<string>> { |   async checkSharedLinkAccess(sharedLinkId: string, albumIds: Set<string>): Promise<Set<string>> { | ||||||
|     if (albumIds.size === 0) { |     if (albumIds.size === 0) { | ||||||
|       return new Set(); |       return new Set(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return Promise.all( |     return this.sharedLinkRepository | ||||||
|       chunks(albumIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) => |       .find({ | ||||||
|         this.sharedLinkRepository |         select: { albumId: true }, | ||||||
|           .find({ |         where: { | ||||||
|             select: { albumId: true }, |           id: sharedLinkId, | ||||||
|             where: { |           albumId: In([...albumIds]), | ||||||
|               id: sharedLinkId, |         }, | ||||||
|               albumId: In(idChunk), |       }) | ||||||
|             }, |       .then( | ||||||
|           }) |         (sharedLinks) => new Set(sharedLinks.flatMap((sharedLink) => (sharedLink.albumId ? [sharedLink.albumId] : []))), | ||||||
|           .then( |       ); | ||||||
|             (sharedLinks) => |  | ||||||
|               new Set(sharedLinks.flatMap((sharedLink) => (sharedLink.albumId ? [sharedLink.albumId] : []))), |  | ||||||
|           ), |  | ||||||
|       ), |  | ||||||
|     ).then((results) => setUnion(...results)); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -183,132 +165,120 @@ class AssetAccess implements IAssetAccess { | |||||||
|   ) {} |   ) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|  |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkAlbumAccess(userId: string, assetIds: Set<string>): Promise<Set<string>> { |   async checkAlbumAccess(userId: string, assetIds: Set<string>): Promise<Set<string>> { | ||||||
|     if (assetIds.size === 0) { |     if (assetIds.size === 0) { | ||||||
|       return new Set(); |       return new Set(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return Promise.all( |     return this.albumRepository | ||||||
|       chunks(assetIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) => |       .createQueryBuilder('album') | ||||||
|         this.albumRepository |       .innerJoin('album.assets', 'asset') | ||||||
|           .createQueryBuilder('album') |       .leftJoin('album.sharedUsers', 'sharedUsers') | ||||||
|           .innerJoin('album.assets', 'asset') |       .select('asset.id', 'assetId') | ||||||
|           .leftJoin('album.sharedUsers', 'sharedUsers') |       .addSelect('asset.livePhotoVideoId', 'livePhotoVideoId') | ||||||
|           .select('asset.id', 'assetId') |       .where('array["asset"."id", "asset"."livePhotoVideoId"] && array[:...assetIds]::uuid[]', { | ||||||
|           .addSelect('asset.livePhotoVideoId', 'livePhotoVideoId') |         assetIds: [...assetIds], | ||||||
|           .where('array["asset"."id", "asset"."livePhotoVideoId"] && array[:...assetIds]::uuid[]', { |       }) | ||||||
|             assetIds: idChunk, |       .andWhere( | ||||||
|           }) |         new Brackets((qb) => { | ||||||
|           .andWhere( |           qb.where('album.ownerId = :userId', { userId }).orWhere('sharedUsers.id = :userId', { userId }); | ||||||
|             new Brackets((qb) => { |         }), | ||||||
|               qb.where('album.ownerId = :userId', { userId }).orWhere('sharedUsers.id = :userId', { userId }); |       ) | ||||||
|             }), |       .getRawMany() | ||||||
|           ) |       .then((rows) => { | ||||||
|           .getRawMany() |         const allowedIds = new Set<string>(); | ||||||
|           .then((rows) => { |         for (const row of rows) { | ||||||
|             const allowedIds = new Set<string>(); |           if (row.assetId && assetIds.has(row.assetId)) { | ||||||
|             for (const row of rows) { |             allowedIds.add(row.assetId); | ||||||
|               if (row.assetId && assetIds.has(row.assetId)) { |           } | ||||||
|                 allowedIds.add(row.assetId); |           if (row.livePhotoVideoId && assetIds.has(row.livePhotoVideoId)) { | ||||||
|               } |             allowedIds.add(row.livePhotoVideoId); | ||||||
|               if (row.livePhotoVideoId && assetIds.has(row.livePhotoVideoId)) { |           } | ||||||
|                 allowedIds.add(row.livePhotoVideoId); |         } | ||||||
|               } |         return allowedIds; | ||||||
|             } |       }); | ||||||
|             return allowedIds; |  | ||||||
|           }), |  | ||||||
|       ), |  | ||||||
|     ).then((results) => setUnion(...results)); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|  |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkOwnerAccess(userId: string, assetIds: Set<string>): Promise<Set<string>> { |   async checkOwnerAccess(userId: string, assetIds: Set<string>): Promise<Set<string>> { | ||||||
|     if (assetIds.size === 0) { |     if (assetIds.size === 0) { | ||||||
|       return new Set(); |       return new Set(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return Promise.all( |     return this.assetRepository | ||||||
|       chunks(assetIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) => |       .find({ | ||||||
|         this.assetRepository |         select: { id: true }, | ||||||
|           .find({ |         where: { | ||||||
|             select: { id: true }, |           id: In([...assetIds]), | ||||||
|             where: { |           ownerId: userId, | ||||||
|               id: In(idChunk), |         }, | ||||||
|               ownerId: userId, |         withDeleted: true, | ||||||
|             }, |       }) | ||||||
|             withDeleted: true, |       .then((assets) => new Set(assets.map((asset) => asset.id))); | ||||||
|           }) |  | ||||||
|           .then((assets) => new Set(assets.map((asset) => asset.id))), |  | ||||||
|       ), |  | ||||||
|     ).then((results) => setUnion(...results)); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|  |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkPartnerAccess(userId: string, assetIds: Set<string>): Promise<Set<string>> { |   async checkPartnerAccess(userId: string, assetIds: Set<string>): Promise<Set<string>> { | ||||||
|     if (assetIds.size === 0) { |     if (assetIds.size === 0) { | ||||||
|       return new Set(); |       return new Set(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return Promise.all( |     return this.partnerRepository | ||||||
|       chunks(assetIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) => |       .createQueryBuilder('partner') | ||||||
|         this.partnerRepository |       .innerJoin('partner.sharedBy', 'sharedBy') | ||||||
|           .createQueryBuilder('partner') |       .innerJoin('sharedBy.assets', 'asset') | ||||||
|           .innerJoin('partner.sharedBy', 'sharedBy') |       .select('asset.id', 'assetId') | ||||||
|           .innerJoin('sharedBy.assets', 'asset') |       .where('partner.sharedWithId = :userId', { userId }) | ||||||
|           .select('asset.id', 'assetId') |       .andWhere('asset.id IN (:...assetIds)', { assetIds: [...assetIds] }) | ||||||
|           .where('partner.sharedWithId = :userId', { userId }) |       .getRawMany() | ||||||
|           .andWhere('asset.id IN (:...assetIds)', { assetIds: idChunk }) |       .then((rows) => new Set(rows.map((row) => row.assetId))); | ||||||
|           .getRawMany() |  | ||||||
|           .then((rows) => new Set(rows.map((row) => row.assetId))), |  | ||||||
|       ), |  | ||||||
|     ).then((results) => setUnion(...results)); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|  |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkSharedLinkAccess(sharedLinkId: string, assetIds: Set<string>): Promise<Set<string>> { |   async checkSharedLinkAccess(sharedLinkId: string, assetIds: Set<string>): Promise<Set<string>> { | ||||||
|     if (assetIds.size === 0) { |     if (assetIds.size === 0) { | ||||||
|       return new Set(); |       return new Set(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return Promise.all( |     return this.sharedLinkRepository | ||||||
|       chunks(assetIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) => |       .createQueryBuilder('sharedLink') | ||||||
|         this.sharedLinkRepository |       .leftJoin('sharedLink.album', 'album') | ||||||
|           .createQueryBuilder('sharedLink') |       .leftJoin('sharedLink.assets', 'assets') | ||||||
|           .leftJoin('sharedLink.album', 'album') |       .leftJoin('album.assets', 'albumAssets') | ||||||
|           .leftJoin('sharedLink.assets', 'assets') |       .select('assets.id', 'assetId') | ||||||
|           .leftJoin('album.assets', 'albumAssets') |       .addSelect('albumAssets.id', 'albumAssetId') | ||||||
|           .select('assets.id', 'assetId') |       .addSelect('assets.livePhotoVideoId', 'assetLivePhotoVideoId') | ||||||
|           .addSelect('albumAssets.id', 'albumAssetId') |       .addSelect('albumAssets.livePhotoVideoId', 'albumAssetLivePhotoVideoId') | ||||||
|           .addSelect('assets.livePhotoVideoId', 'assetLivePhotoVideoId') |       .where('sharedLink.id = :sharedLinkId', { sharedLinkId }) | ||||||
|           .addSelect('albumAssets.livePhotoVideoId', 'albumAssetLivePhotoVideoId') |       .andWhere( | ||||||
|           .where('sharedLink.id = :sharedLinkId', { sharedLinkId }) |         'array["assets"."id", "assets"."livePhotoVideoId", "albumAssets"."id", "albumAssets"."livePhotoVideoId"] && array[:...assetIds]::uuid[]', | ||||||
|           .andWhere( |         { | ||||||
|             'array["assets"."id", "assets"."livePhotoVideoId", "albumAssets"."id", "albumAssets"."livePhotoVideoId"] && array[:...assetIds]::uuid[]', |           assetIds: [...assetIds], | ||||||
|             { |         }, | ||||||
|               assetIds: idChunk, |       ) | ||||||
|             }, |       .getRawMany() | ||||||
|           ) |       .then((rows) => { | ||||||
|           .getRawMany() |         const allowedIds = new Set<string>(); | ||||||
|           .then((rows) => { |         for (const row of rows) { | ||||||
|             const allowedIds = new Set<string>(); |           if (row.assetId && assetIds.has(row.assetId)) { | ||||||
|             for (const row of rows) { |             allowedIds.add(row.assetId); | ||||||
|               if (row.assetId && assetIds.has(row.assetId)) { |           } | ||||||
|                 allowedIds.add(row.assetId); |           if (row.assetLivePhotoVideoId && assetIds.has(row.assetLivePhotoVideoId)) { | ||||||
|               } |             allowedIds.add(row.assetLivePhotoVideoId); | ||||||
|               if (row.assetLivePhotoVideoId && assetIds.has(row.assetLivePhotoVideoId)) { |           } | ||||||
|                 allowedIds.add(row.assetLivePhotoVideoId); |           if (row.albumAssetId && assetIds.has(row.albumAssetId)) { | ||||||
|               } |             allowedIds.add(row.albumAssetId); | ||||||
|               if (row.albumAssetId && assetIds.has(row.albumAssetId)) { |           } | ||||||
|                 allowedIds.add(row.albumAssetId); |           if (row.albumAssetLivePhotoVideoId && assetIds.has(row.albumAssetLivePhotoVideoId)) { | ||||||
|               } |             allowedIds.add(row.albumAssetLivePhotoVideoId); | ||||||
|               if (row.albumAssetLivePhotoVideoId && assetIds.has(row.albumAssetLivePhotoVideoId)) { |           } | ||||||
|                 allowedIds.add(row.albumAssetLivePhotoVideoId); |         } | ||||||
|               } |         return allowedIds; | ||||||
|             } |       }); | ||||||
|             return allowedIds; |  | ||||||
|           }), |  | ||||||
|       ), |  | ||||||
|     ).then((results) => setUnion(...results)); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -316,24 +286,21 @@ class AuthDeviceAccess implements IAuthDeviceAccess { | |||||||
|   constructor(private tokenRepository: Repository<UserTokenEntity>) {} |   constructor(private tokenRepository: Repository<UserTokenEntity>) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|  |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkOwnerAccess(userId: string, deviceIds: Set<string>): Promise<Set<string>> { |   async checkOwnerAccess(userId: string, deviceIds: Set<string>): Promise<Set<string>> { | ||||||
|     if (deviceIds.size === 0) { |     if (deviceIds.size === 0) { | ||||||
|       return new Set(); |       return new Set(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return Promise.all( |     return this.tokenRepository | ||||||
|       chunks(deviceIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) => |       .find({ | ||||||
|         this.tokenRepository |         select: { id: true }, | ||||||
|           .find({ |         where: { | ||||||
|             select: { id: true }, |           userId, | ||||||
|             where: { |           id: In([...deviceIds]), | ||||||
|               userId, |         }, | ||||||
|               id: In(idChunk), |       }) | ||||||
|             }, |       .then((tokens) => new Set(tokens.map((token) => token.id))); | ||||||
|           }) |  | ||||||
|           .then((tokens) => new Set(tokens.map((token) => token.id))), |  | ||||||
|       ), |  | ||||||
|     ).then((results) => setUnion(...results)); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -344,43 +311,37 @@ class LibraryAccess implements ILibraryAccess { | |||||||
|   ) {} |   ) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|  |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkOwnerAccess(userId: string, libraryIds: Set<string>): Promise<Set<string>> { |   async checkOwnerAccess(userId: string, libraryIds: Set<string>): Promise<Set<string>> { | ||||||
|     if (libraryIds.size === 0) { |     if (libraryIds.size === 0) { | ||||||
|       return new Set(); |       return new Set(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return Promise.all( |     return this.libraryRepository | ||||||
|       chunks(libraryIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) => |       .find({ | ||||||
|         this.libraryRepository |         select: { id: true }, | ||||||
|           .find({ |         where: { | ||||||
|             select: { id: true }, |           id: In([...libraryIds]), | ||||||
|             where: { |           ownerId: userId, | ||||||
|               id: In(idChunk), |         }, | ||||||
|               ownerId: userId, |       }) | ||||||
|             }, |       .then((libraries) => new Set(libraries.map((library) => library.id))); | ||||||
|           }) |  | ||||||
|           .then((libraries) => new Set(libraries.map((library) => library.id))), |  | ||||||
|       ), |  | ||||||
|     ).then((results) => setUnion(...results)); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|  |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkPartnerAccess(userId: string, partnerIds: Set<string>): Promise<Set<string>> { |   async checkPartnerAccess(userId: string, partnerIds: Set<string>): Promise<Set<string>> { | ||||||
|     if (partnerIds.size === 0) { |     if (partnerIds.size === 0) { | ||||||
|       return new Set(); |       return new Set(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return Promise.all( |     return this.partnerRepository | ||||||
|       chunks(partnerIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) => |       .createQueryBuilder('partner') | ||||||
|         this.partnerRepository |       .select('partner.sharedById') | ||||||
|           .createQueryBuilder('partner') |       .where('partner.sharedById IN (:...partnerIds)', { partnerIds: [...partnerIds] }) | ||||||
|           .select('partner.sharedById') |       .andWhere('partner.sharedWithId = :userId', { userId }) | ||||||
|           .where('partner.sharedById IN (:...partnerIds)', { partnerIds: idChunk }) |       .getMany() | ||||||
|           .andWhere('partner.sharedWithId = :userId', { userId }) |       .then((partners) => new Set(partners.map((partner) => partner.sharedById))); | ||||||
|           .getMany() |  | ||||||
|           .then((partners) => new Set(partners.map((partner) => partner.sharedById))), |  | ||||||
|       ), |  | ||||||
|     ).then((results) => setUnion(...results)); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -388,22 +349,19 @@ class TimelineAccess implements ITimelineAccess { | |||||||
|   constructor(private partnerRepository: Repository<PartnerEntity>) {} |   constructor(private partnerRepository: Repository<PartnerEntity>) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|  |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkPartnerAccess(userId: string, partnerIds: Set<string>): Promise<Set<string>> { |   async checkPartnerAccess(userId: string, partnerIds: Set<string>): Promise<Set<string>> { | ||||||
|     if (partnerIds.size === 0) { |     if (partnerIds.size === 0) { | ||||||
|       return new Set(); |       return new Set(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return Promise.all( |     return this.partnerRepository | ||||||
|       chunks(partnerIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) => |       .createQueryBuilder('partner') | ||||||
|         this.partnerRepository |       .select('partner.sharedById') | ||||||
|           .createQueryBuilder('partner') |       .where('partner.sharedById IN (:...partnerIds)', { partnerIds: [...partnerIds] }) | ||||||
|           .select('partner.sharedById') |       .andWhere('partner.sharedWithId = :userId', { userId }) | ||||||
|           .where('partner.sharedById IN (:...partnerIds)', { partnerIds: idChunk }) |       .getMany() | ||||||
|           .andWhere('partner.sharedWithId = :userId', { userId }) |       .then((partners) => new Set(partners.map((partner) => partner.sharedById))); | ||||||
|           .getMany() |  | ||||||
|           .then((partners) => new Set(partners.map((partner) => partner.sharedById))), |  | ||||||
|       ), |  | ||||||
|     ).then((results) => setUnion(...results)); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -414,47 +372,41 @@ class PersonAccess implements IPersonAccess { | |||||||
|   ) {} |   ) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|  |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkOwnerAccess(userId: string, personIds: Set<string>): Promise<Set<string>> { |   async checkOwnerAccess(userId: string, personIds: Set<string>): Promise<Set<string>> { | ||||||
|     if (personIds.size === 0) { |     if (personIds.size === 0) { | ||||||
|       return new Set(); |       return new Set(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return Promise.all( |     return this.personRepository | ||||||
|       chunks(personIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) => |       .find({ | ||||||
|         this.personRepository |         select: { id: true }, | ||||||
|           .find({ |         where: { | ||||||
|             select: { id: true }, |           id: In([...personIds]), | ||||||
|             where: { |           ownerId: userId, | ||||||
|               id: In(idChunk), |         }, | ||||||
|               ownerId: userId, |       }) | ||||||
|             }, |       .then((persons) => new Set(persons.map((person) => person.id))); | ||||||
|           }) |  | ||||||
|           .then((persons) => new Set(persons.map((person) => person.id))), |  | ||||||
|       ), |  | ||||||
|     ).then((results) => setUnion(...results)); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|  |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkFaceOwnerAccess(userId: string, assetFaceIds: Set<string>): Promise<Set<string>> { |   async checkFaceOwnerAccess(userId: string, assetFaceIds: Set<string>): Promise<Set<string>> { | ||||||
|     if (assetFaceIds.size === 0) { |     if (assetFaceIds.size === 0) { | ||||||
|       return new Set(); |       return new Set(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return Promise.all( |     return this.assetFaceRepository | ||||||
|       chunks(assetFaceIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) => |       .find({ | ||||||
|         this.assetFaceRepository |         select: { id: true }, | ||||||
|           .find({ |         where: { | ||||||
|             select: { id: true }, |           id: In([...assetFaceIds]), | ||||||
|             where: { |           asset: { | ||||||
|               id: In(idChunk), |             ownerId: userId, | ||||||
|               asset: { |           }, | ||||||
|                 ownerId: userId, |         }, | ||||||
|               }, |       }) | ||||||
|             }, |       .then((faces) => new Set(faces.map((face) => face.id))); | ||||||
|           }) |  | ||||||
|           .then((faces) => new Set(faces.map((face) => face.id))), |  | ||||||
|       ), |  | ||||||
|     ).then((results) => setUnion(...results)); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -462,22 +414,19 @@ class PartnerAccess implements IPartnerAccess { | |||||||
|   constructor(private partnerRepository: Repository<PartnerEntity>) {} |   constructor(private partnerRepository: Repository<PartnerEntity>) {} | ||||||
| 
 | 
 | ||||||
|   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) |   @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) | ||||||
|  |   @ChunkedSet({ paramIndex: 1 }) | ||||||
|   async checkUpdateAccess(userId: string, partnerIds: Set<string>): Promise<Set<string>> { |   async checkUpdateAccess(userId: string, partnerIds: Set<string>): Promise<Set<string>> { | ||||||
|     if (partnerIds.size === 0) { |     if (partnerIds.size === 0) { | ||||||
|       return new Set(); |       return new Set(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return Promise.all( |     return this.partnerRepository | ||||||
|       chunks(partnerIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) => |       .createQueryBuilder('partner') | ||||||
|         this.partnerRepository |       .select('partner.sharedById') | ||||||
|           .createQueryBuilder('partner') |       .where('partner.sharedById IN (:...partnerIds)', { partnerIds: [...partnerIds] }) | ||||||
|           .select('partner.sharedById') |       .andWhere('partner.sharedWithId = :userId', { userId }) | ||||||
|           .where('partner.sharedById IN (:...partnerIds)', { partnerIds: idChunk }) |       .getMany() | ||||||
|           .andWhere('partner.sharedWithId = :userId', { userId }) |       .then((partners) => new Set(partners.map((partner) => partner.sharedById))); | ||||||
|           .getMany() |  | ||||||
|           .then((partners) => new Set(partners.map((partner) => partner.sharedById))), |  | ||||||
|       ), |  | ||||||
|     ).then((results) => setUnion(...results)); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user