refactor: migrate trash to kysely (#15233)

This commit is contained in:
Jason Rasmussen
2025-01-10 18:48:21 -05:00
committed by GitHub
parent cc6a8b0c74
commit e51091b6e5
5 changed files with 100 additions and 59 deletions

View File

@@ -7,6 +7,13 @@ import { IAccessRepositoryMock } from 'test/repositories/access.repository.mock'
import { newTestService } from 'test/utils';
import { Mocked } from 'vitest';
async function* makeAssetIdStream(count: number): AsyncIterableIterator<{ id: string }> {
for (let i = 0; i < count; i++) {
await Promise.resolve();
yield { id: `asset-${i + 1}` };
}
}
describe(TrashService.name, () => {
let sut: TrashService;
@@ -48,14 +55,14 @@ describe(TrashService.name, () => {
describe('restore', () => {
it('should handle an empty trash', async () => {
trashMock.getDeletedIds.mockResolvedValue({ items: [], hasNextPage: false });
trashMock.getDeletedIds.mockResolvedValue(makeAssetIdStream(0));
trashMock.restore.mockResolvedValue(0);
await expect(sut.restore(authStub.user1)).resolves.toEqual({ count: 0 });
expect(trashMock.restore).toHaveBeenCalledWith('user-id');
});
it('should restore', async () => {
trashMock.getDeletedIds.mockResolvedValue({ items: ['asset-1'], hasNextPage: false });
trashMock.getDeletedIds.mockResolvedValue(makeAssetIdStream(1));
trashMock.restore.mockResolvedValue(1);
await expect(sut.restore(authStub.user1)).resolves.toEqual({ count: 1 });
expect(trashMock.restore).toHaveBeenCalledWith('user-id');
@@ -64,14 +71,14 @@ describe(TrashService.name, () => {
describe('empty', () => {
it('should handle an empty trash', async () => {
trashMock.getDeletedIds.mockResolvedValue({ items: [], hasNextPage: false });
trashMock.getDeletedIds.mockResolvedValue(makeAssetIdStream(0));
trashMock.empty.mockResolvedValue(0);
await expect(sut.empty(authStub.user1)).resolves.toEqual({ count: 0 });
expect(jobMock.queue).not.toHaveBeenCalled();
});
it('should empty the trash', async () => {
trashMock.getDeletedIds.mockResolvedValue({ items: ['asset-1'], hasNextPage: false });
trashMock.getDeletedIds.mockResolvedValue(makeAssetIdStream(1));
trashMock.empty.mockResolvedValue(1);
await expect(sut.empty(authStub.user1)).resolves.toEqual({ count: 1 });
expect(trashMock.empty).toHaveBeenCalledWith('user-id');
@@ -88,7 +95,7 @@ describe(TrashService.name, () => {
describe('handleQueueEmptyTrash', () => {
it('should queue asset delete jobs', async () => {
trashMock.getDeletedIds.mockResolvedValue({ items: ['asset-1'], hasNextPage: false });
trashMock.getDeletedIds.mockReturnValue(makeAssetIdStream(1));
await expect(sut.handleQueueEmptyTrash()).resolves.toEqual(JobStatus.SUCCESS);
expect(jobMock.queueAll).toHaveBeenCalledWith([
{

View File

@@ -5,7 +5,6 @@ import { TrashResponseDto } from 'src/dtos/trash.dto';
import { Permission } from 'src/enum';
import { JOBS_ASSET_PAGINATION_SIZE, JobName, JobStatus, QueueName } from 'src/interfaces/job.interface';
import { BaseService } from 'src/services/base.service';
import { usePagination } from 'src/utils/pagination';
export class TrashService extends BaseService {
async restoreAssets(auth: AuthDto, dto: BulkIdsDto): Promise<TrashResponseDto> {
@@ -46,27 +45,39 @@ export class TrashService extends BaseService {
@OnJob({ name: JobName.QUEUE_TRASH_EMPTY, queue: QueueName.BACKGROUND_TASK })
async handleQueueEmptyTrash() {
let count = 0;
const assetPagination = usePagination(JOBS_ASSET_PAGINATION_SIZE, (pagination) =>
this.trashRepository.getDeletedIds(pagination),
);
const assets = this.trashRepository.getDeletedIds();
for await (const assetIds of assetPagination) {
this.logger.debug(`Queueing ${assetIds.length} asset(s) for deletion from the trash`);
count += assetIds.length;
await this.jobRepository.queueAll(
assetIds.map((assetId) => ({
name: JobName.ASSET_DELETION,
data: {
id: assetId,
deleteOnDisk: true,
},
})),
);
let count = 0;
const batch: string[] = [];
for await (const { id } of assets) {
batch.push(id);
if (batch.length === JOBS_ASSET_PAGINATION_SIZE) {
await this.handleBatch(batch);
count += batch.length;
batch.length = 0;
}
}
await this.handleBatch(batch);
count += batch.length;
batch.length = 0;
this.logger.log(`Queued ${count} asset(s) for deletion from the trash`);
return JobStatus.SUCCESS;
}
private async handleBatch(ids: string[]) {
this.logger.debug(`Queueing ${ids.length} asset(s) for deletion from the trash`);
await this.jobRepository.queueAll(
ids.map((assetId) => ({
name: JobName.ASSET_DELETION,
data: {
id: assetId,
deleteOnDisk: true,
},
})),
);
}
}