mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-04 03:39:37 -05:00 
			
		
		
		
	refactor(server): bulk interface (#10889)
This commit is contained in:
		
							parent
							
								
									ac8d8d91f7
								
							
						
					
					
						commit
						cf88f4b6f8
					
				@ -28,10 +28,8 @@ export interface IAlbumRepository extends IBulkAsset {
 | 
				
			|||||||
  getById(id: string, options: AlbumInfoOptions): Promise<AlbumEntity | null>;
 | 
					  getById(id: string, options: AlbumInfoOptions): Promise<AlbumEntity | null>;
 | 
				
			||||||
  getByIds(ids: string[]): Promise<AlbumEntity[]>;
 | 
					  getByIds(ids: string[]): Promise<AlbumEntity[]>;
 | 
				
			||||||
  getByAssetId(ownerId: string, assetId: string): Promise<AlbumEntity[]>;
 | 
					  getByAssetId(ownerId: string, assetId: string): Promise<AlbumEntity[]>;
 | 
				
			||||||
  getAssetIds(albumId: string, assetIds?: string[]): Promise<Set<string>>;
 | 
					 | 
				
			||||||
  hasAsset(asset: AlbumAsset): Promise<boolean>;
 | 
					  hasAsset(asset: AlbumAsset): Promise<boolean>;
 | 
				
			||||||
  removeAsset(assetId: string): Promise<void>;
 | 
					  removeAsset(assetId: string): Promise<void>;
 | 
				
			||||||
  removeAssetIds(albumId: string, assetIds: string[]): Promise<void>;
 | 
					 | 
				
			||||||
  getMetadataForIds(ids: string[]): Promise<AlbumAssetCount[]>;
 | 
					  getMetadataForIds(ids: string[]): Promise<AlbumAssetCount[]>;
 | 
				
			||||||
  getInvalidThumbnail(): Promise<string[]>;
 | 
					  getInvalidThumbnail(): Promise<string[]>;
 | 
				
			||||||
  getOwned(ownerId: string): Promise<AlbumEntity[]>;
 | 
					  getOwned(ownerId: string): Promise<AlbumEntity[]>;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,14 +1,12 @@
 | 
				
			|||||||
import { MemoryEntity } from 'src/entities/memory.entity';
 | 
					import { MemoryEntity } from 'src/entities/memory.entity';
 | 
				
			||||||
 | 
					import { IBulkAsset } from 'src/utils/asset.util';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const IMemoryRepository = 'IMemoryRepository';
 | 
					export const IMemoryRepository = 'IMemoryRepository';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IMemoryRepository {
 | 
					export interface IMemoryRepository extends IBulkAsset {
 | 
				
			||||||
  search(ownerId: string): Promise<MemoryEntity[]>;
 | 
					  search(ownerId: string): Promise<MemoryEntity[]>;
 | 
				
			||||||
  get(id: string): Promise<MemoryEntity | null>;
 | 
					  get(id: string): Promise<MemoryEntity | null>;
 | 
				
			||||||
  create(memory: Partial<MemoryEntity>): Promise<MemoryEntity>;
 | 
					  create(memory: Partial<MemoryEntity>): Promise<MemoryEntity>;
 | 
				
			||||||
  update(memory: Partial<MemoryEntity>): Promise<MemoryEntity>;
 | 
					  update(memory: Partial<MemoryEntity>): Promise<MemoryEntity>;
 | 
				
			||||||
  delete(id: string): Promise<void>;
 | 
					  delete(id: string): Promise<void>;
 | 
				
			||||||
  getAssetIds(id: string, assetIds: string[]): Promise<Set<string>>;
 | 
					 | 
				
			||||||
  addAssetIds(id: string, assetIds: string[]): Promise<void>;
 | 
					 | 
				
			||||||
  removeAssetIds(id: string, assetIds: string[]): Promise<void>;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -585,14 +585,6 @@ WHERE
 | 
				
			|||||||
  "albums_assets"."albumsId" = $1
 | 
					  "albums_assets"."albumsId" = $1
 | 
				
			||||||
  AND "albums_assets"."assetsId" IN ($2)
 | 
					  AND "albums_assets"."assetsId" IN ($2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- AlbumRepository.getAssetIds (no assets)
 | 
					 | 
				
			||||||
SELECT
 | 
					 | 
				
			||||||
  "albums_assets"."assetsId" AS "assetId"
 | 
					 | 
				
			||||||
FROM
 | 
					 | 
				
			||||||
  "albums_assets_assets" "albums_assets"
 | 
					 | 
				
			||||||
WHERE
 | 
					 | 
				
			||||||
  "albums_assets"."albumsId" = $1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
-- AlbumRepository.hasAsset
 | 
					-- AlbumRepository.hasAsset
 | 
				
			||||||
SELECT
 | 
					SELECT
 | 
				
			||||||
  1 AS "row_exists"
 | 
					  1 AS "row_exists"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,12 +1,10 @@
 | 
				
			|||||||
import { Injectable } from '@nestjs/common';
 | 
					import { Injectable } from '@nestjs/common';
 | 
				
			||||||
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
 | 
					import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
 | 
				
			||||||
import _ from 'lodash';
 | 
					import { Chunked, ChunkedArray, ChunkedSet, DummyValue, GenerateSql } from 'src/decorators';
 | 
				
			||||||
import { Chunked, ChunkedArray, DATABASE_PARAMETER_CHUNK_SIZE, DummyValue, GenerateSql } from 'src/decorators';
 | 
					 | 
				
			||||||
import { AlbumEntity } from 'src/entities/album.entity';
 | 
					import { AlbumEntity } from 'src/entities/album.entity';
 | 
				
			||||||
import { AssetEntity } from 'src/entities/asset.entity';
 | 
					import { AssetEntity } from 'src/entities/asset.entity';
 | 
				
			||||||
import { AlbumAsset, AlbumAssetCount, AlbumInfoOptions, IAlbumRepository } from 'src/interfaces/album.interface';
 | 
					import { AlbumAsset, AlbumAssetCount, AlbumInfoOptions, IAlbumRepository } from 'src/interfaces/album.interface';
 | 
				
			||||||
import { Instrumentation } from 'src/utils/instrumentation';
 | 
					import { Instrumentation } from 'src/utils/instrumentation';
 | 
				
			||||||
import { setUnion } from 'src/utils/set';
 | 
					 | 
				
			||||||
import { DataSource, FindOptionsOrder, FindOptionsRelations, In, IsNull, Not, Repository } from 'typeorm';
 | 
					import { DataSource, FindOptionsOrder, FindOptionsRelations, In, IsNull, Not, Repository } from 'typeorm';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const withoutDeletedUsers = <T extends AlbumEntity | null>(album: T) => {
 | 
					const withoutDeletedUsers = <T extends AlbumEntity | null>(album: T) => {
 | 
				
			||||||
@ -215,6 +213,10 @@ export class AlbumRepository implements IAlbumRepository {
 | 
				
			|||||||
  @GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
 | 
					  @GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
 | 
				
			||||||
  @Chunked({ paramIndex: 1 })
 | 
					  @Chunked({ paramIndex: 1 })
 | 
				
			||||||
  async removeAssetIds(albumId: string, assetIds: string[]): Promise<void> {
 | 
					  async removeAssetIds(albumId: string, assetIds: string[]): Promise<void> {
 | 
				
			||||||
 | 
					    if (assetIds.length === 0) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await this.dataSource
 | 
					    await this.dataSource
 | 
				
			||||||
      .createQueryBuilder()
 | 
					      .createQueryBuilder()
 | 
				
			||||||
      .delete()
 | 
					      .delete()
 | 
				
			||||||
@ -233,27 +235,22 @@ export class AlbumRepository implements IAlbumRepository {
 | 
				
			|||||||
   * @param assetIds Optional list of asset IDs to filter on.
 | 
					   * @param assetIds Optional list of asset IDs to filter on.
 | 
				
			||||||
   * @returns Set of Asset IDs for the given album ID.
 | 
					   * @returns Set of Asset IDs for the given album ID.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  @GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] }, { name: 'no assets', params: [DummyValue.UUID] })
 | 
					  @GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
 | 
				
			||||||
  async getAssetIds(albumId: string, assetIds?: string[]): Promise<Set<string>> {
 | 
					  @ChunkedSet({ paramIndex: 1 })
 | 
				
			||||||
    const query = this.dataSource
 | 
					  async getAssetIds(albumId: string, assetIds: string[]): Promise<Set<string>> {
 | 
				
			||||||
 | 
					    if (assetIds.length === 0) {
 | 
				
			||||||
 | 
					      return new Set();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const results = await this.dataSource
 | 
				
			||||||
      .createQueryBuilder()
 | 
					      .createQueryBuilder()
 | 
				
			||||||
      .select('albums_assets.assetsId', 'assetId')
 | 
					      .select('albums_assets.assetsId', 'assetId')
 | 
				
			||||||
      .from('albums_assets_assets', 'albums_assets')
 | 
					      .from('albums_assets_assets', 'albums_assets')
 | 
				
			||||||
      .where('"albums_assets"."albumsId" = :albumId', { albumId });
 | 
					      .where('"albums_assets"."albumsId" = :albumId', { albumId })
 | 
				
			||||||
 | 
					      .andWhere('"albums_assets"."assetsId" IN (:...assetIds)', { assetIds })
 | 
				
			||||||
 | 
					      .getRawMany<{ assetId: string }>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!assetIds?.length) {
 | 
					    return new Set(results.map(({ assetId }) => assetId));
 | 
				
			||||||
      const result = await query.getRawMany();
 | 
					 | 
				
			||||||
      return new Set(result.map((row) => row['assetId']));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return Promise.all(
 | 
					 | 
				
			||||||
      _.chunk(assetIds, DATABASE_PARAMETER_CHUNK_SIZE).map((idChunk) =>
 | 
					 | 
				
			||||||
        query
 | 
					 | 
				
			||||||
          .andWhere('"albums_assets"."assetsId" IN (:...assetIds)', { assetIds: idChunk })
 | 
					 | 
				
			||||||
          .getRawMany()
 | 
					 | 
				
			||||||
          .then((result) => new Set(result.map((row) => row['assetId']))),
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
    ).then((results) => setUnion(...results));
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @GenerateSql({ params: [{ albumId: DummyValue.UUID, assetId: DummyValue.UUID }] })
 | 
					  @GenerateSql({ params: [{ albumId: DummyValue.UUID, assetId: DummyValue.UUID }] })
 | 
				
			||||||
 | 
				
			|||||||
@ -61,9 +61,9 @@ export class MemoryRepository implements IMemoryRepository {
 | 
				
			|||||||
      .from('memories_assets_assets', 'memories_assets')
 | 
					      .from('memories_assets_assets', 'memories_assets')
 | 
				
			||||||
      .where('"memories_assets"."memoriesId" = :memoryId', { memoryId: id })
 | 
					      .where('"memories_assets"."memoriesId" = :memoryId', { memoryId: id })
 | 
				
			||||||
      .andWhere('memories_assets.assetsId IN (:...assetIds)', { assetIds })
 | 
					      .andWhere('memories_assets.assetsId IN (:...assetIds)', { assetIds })
 | 
				
			||||||
      .getRawMany();
 | 
					      .getRawMany<{ assetId: string }>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return new Set(results.map((row) => row['assetId']));
 | 
					    return new Set(results.map(({ assetId }) => assetId));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
 | 
					  @GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user