fix: empty and restore over 1,000 items (#12751)

This commit is contained in:
Jason Rasmussen
2024-09-18 09:57:52 -04:00
committed by GitHub
parent 4f25cec6df
commit 6740c67ed8
39 changed files with 540 additions and 145 deletions

View File

@@ -6,7 +6,7 @@ import { AssetJobStatusEntity } from 'src/entities/asset-job-status.entity';
import { AssetEntity } from 'src/entities/asset.entity';
import { ExifEntity } from 'src/entities/exif.entity';
import { SmartInfoEntity } from 'src/entities/smart-info.entity';
import { AssetFileType, AssetOrder, AssetType } from 'src/enum';
import { AssetFileType, AssetOrder, AssetStatus, AssetType } from 'src/enum';
import {
AssetBuilderOptions,
AssetCreate,
@@ -295,16 +295,6 @@ export class AssetRepository implements IAssetRepository {
.execute();
}
@Chunked()
async softDeleteAll(ids: string[]): Promise<void> {
await this.repository.softDelete({ id: In(ids) });
}
@Chunked()
async restoreAll(ids: string[]): Promise<void> {
await this.repository.restore({ id: In(ids) });
}
async update(asset: AssetUpdateOptions): Promise<void> {
await this.repository.update(asset.id, asset);
}
@@ -597,7 +587,10 @@ export class AssetRepository implements IAssetRepository {
}
if (isTrashed !== undefined) {
builder.withDeleted().andWhere(`asset.deletedAt is not null`);
builder
.withDeleted()
.andWhere(`asset.deletedAt is not null`)
.andWhere('asset.status = :status', { status: AssetStatus.TRASHED });
}
const items = await builder.getRawMany();
@@ -755,6 +748,10 @@ export class AssetRepository implements IAssetRepository {
if (options.isTrashed !== undefined) {
builder.andWhere(`asset.deletedAt ${options.isTrashed ? 'IS NOT NULL' : 'IS NULL'}`).withDeleted();
if (options.isTrashed) {
builder.andWhere('asset.status = :status', { status: AssetStatus.TRASHED });
}
}
if (options.isDuplicate !== undefined) {

View File

@@ -29,6 +29,7 @@ import { IStackRepository } from 'src/interfaces/stack.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { ITagRepository } from 'src/interfaces/tag.interface';
import { ITrashRepository } from 'src/interfaces/trash.interface';
import { IUserRepository } from 'src/interfaces/user.interface';
import { IViewRepository } from 'src/interfaces/view.interface';
import { AccessRepository } from 'src/repositories/access.repository';
@@ -62,6 +63,7 @@ import { StackRepository } from 'src/repositories/stack.repository';
import { StorageRepository } from 'src/repositories/storage.repository';
import { SystemMetadataRepository } from 'src/repositories/system-metadata.repository';
import { TagRepository } from 'src/repositories/tag.repository';
import { TrashRepository } from 'src/repositories/trash.repository';
import { UserRepository } from 'src/repositories/user.repository';
import { ViewRepository } from 'src/repositories/view-repository';
@@ -97,6 +99,7 @@ export const repositories = [
{ provide: IStorageRepository, useClass: StorageRepository },
{ provide: ISystemMetadataRepository, useClass: SystemMetadataRepository },
{ provide: ITagRepository, useClass: TagRepository },
{ provide: ITrashRepository, useClass: TrashRepository },
{ provide: IUserRepository, useClass: UserRepository },
{ provide: IViewRepository, useClass: ViewRepository },
];

View File

@@ -95,6 +95,9 @@ export const JOBS_TO_QUEUE: Record<JobName, QueueName> = {
// Version check
[JobName.VERSION_CHECK]: QueueName.BACKGROUND_TASK,
// Trash
[JobName.QUEUE_TRASH_EMPTY]: QueueName.BACKGROUND_TASK,
};
@Instrumentation()

View File

@@ -0,0 +1,49 @@
import { InjectRepository } from '@nestjs/typeorm';
import { AssetEntity } from 'src/entities/asset.entity';
import { AssetStatus } from 'src/enum';
import { ITrashRepository } from 'src/interfaces/trash.interface';
import { Paginated, paginatedBuilder, PaginationOptions } from 'src/utils/pagination';
import { In, IsNull, Not, Repository } from 'typeorm';
export class TrashRepository implements ITrashRepository {
constructor(@InjectRepository(AssetEntity) private assetRepository: Repository<AssetEntity>) {}
async getDeletedIds(pagination: PaginationOptions): Paginated<string> {
const { hasNextPage, items } = await paginatedBuilder(
this.assetRepository
.createQueryBuilder('asset')
.select('asset.id')
.where({ status: AssetStatus.DELETED })
.withDeleted(),
pagination,
);
return {
hasNextPage,
items: items.map((asset) => asset.id),
};
}
async restore(userId: string): Promise<number> {
const result = await this.assetRepository.update(
{ ownerId: userId, deletedAt: Not(IsNull()) },
{ status: AssetStatus.ACTIVE, deletedAt: null },
);
return result.affected || 0;
}
async empty(userId: string): Promise<number> {
const result = await this.assetRepository.update(
{ ownerId: userId, deletedAt: Not(IsNull()), status: AssetStatus.TRASHED },
{ status: AssetStatus.DELETED },
);
return result.affected || 0;
}
async restoreAll(ids: string[]): Promise<number> {
const result = await this.assetRepository.update({ id: In(ids) }, { status: AssetStatus.ACTIVE, deletedAt: null });
return result.affected ?? 0;
}
}