mirror of
https://github.com/immich-app/immich
synced 2025-10-17 18:19:27 +00:00
feat: duplicate delete groups api (#19142)
This commit is contained in:
parent
bddb43e1d4
commit
c9bcae813b
10 changed files with 235 additions and 13 deletions
|
|
@ -1,9 +1,11 @@
|
|||
import { Controller, Get } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, Param } from '@nestjs/common';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
import { BulkIdsDto } from 'src/dtos/asset-ids.response.dto';
|
||||
import { AuthDto } from 'src/dtos/auth.dto';
|
||||
import { DuplicateResponseDto } from 'src/dtos/duplicate.dto';
|
||||
import { Auth, Authenticated } from 'src/middleware/auth.guard';
|
||||
import { DuplicateService } from 'src/services/duplicate.service';
|
||||
import { UUIDParamDto } from 'src/validation';
|
||||
|
||||
@ApiTags('Duplicates')
|
||||
@Controller('duplicates')
|
||||
|
|
@ -15,4 +17,16 @@ export class DuplicateController {
|
|||
getAssetDuplicates(@Auth() auth: AuthDto): Promise<DuplicateResponseDto[]> {
|
||||
return this.service.getDuplicates(auth);
|
||||
}
|
||||
|
||||
@Delete()
|
||||
@Authenticated()
|
||||
deleteDuplicates(@Auth() auth: AuthDto, @Body() dto: BulkIdsDto): Promise<void> {
|
||||
return this.service.deleteAll(auth, dto);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@Authenticated()
|
||||
deleteDuplicate(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise<void> {
|
||||
return this.service.delete(auth, id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,6 @@
|
|||
import { IsNotEmpty } from 'class-validator';
|
||||
import { AssetResponseDto } from 'src/dtos/asset-response.dto';
|
||||
import { ValidateUUID } from 'src/validation';
|
||||
|
||||
export class DuplicateResponseDto {
|
||||
duplicateId!: string;
|
||||
assets!: AssetResponseDto[];
|
||||
}
|
||||
|
||||
export class ResolveDuplicatesDto {
|
||||
@IsNotEmpty()
|
||||
@ValidateUUID({ each: true })
|
||||
assetIds!: string[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,22 @@ where
|
|||
"unique"."duplicateId" = "duplicates"."duplicateId"
|
||||
)
|
||||
|
||||
-- DuplicateRepository.delete
|
||||
update "assets"
|
||||
set
|
||||
"duplicateId" = $1
|
||||
where
|
||||
"ownerId" = $2
|
||||
and "duplicateId" = $3
|
||||
|
||||
-- DuplicateRepository.deleteAll
|
||||
update "assets"
|
||||
set
|
||||
"duplicateId" = $1
|
||||
where
|
||||
"ownerId" = $2
|
||||
and "duplicateId" in ($3)
|
||||
|
||||
-- DuplicateRepository.search
|
||||
begin
|
||||
set
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
|||
import { Kysely, NotNull, sql } from 'kysely';
|
||||
import { InjectKysely } from 'nestjs-kysely';
|
||||
import { DB } from 'src/db';
|
||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { Chunked, DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { MapAsset } from 'src/dtos/asset-response.dto';
|
||||
import { AssetType, VectorIndex } from 'src/enum';
|
||||
import { probes } from 'src/repositories/database.repository';
|
||||
|
|
@ -78,6 +78,31 @@ export class DuplicateRepository {
|
|||
);
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] })
|
||||
async delete(userId: string, id: string): Promise<void> {
|
||||
await this.db
|
||||
.updateTable('assets')
|
||||
.set({ duplicateId: null })
|
||||
.where('ownerId', '=', userId)
|
||||
.where('duplicateId', '=', id)
|
||||
.execute();
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
|
||||
@Chunked({ paramIndex: 1 })
|
||||
async deleteAll(userId: string, ids: string[]): Promise<void> {
|
||||
if (ids.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.db
|
||||
.updateTable('assets')
|
||||
.set({ duplicateId: null })
|
||||
.where('ownerId', '=', userId)
|
||||
.where('duplicateId', 'in', ids)
|
||||
.execute();
|
||||
}
|
||||
|
||||
@GenerateSql({
|
||||
params: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { JOBS_ASSET_PAGINATION_SIZE } from 'src/constants';
|
||||
import { OnJob } from 'src/decorators';
|
||||
import { BulkIdsDto } from 'src/dtos/asset-ids.response.dto';
|
||||
import { mapAsset } from 'src/dtos/asset-response.dto';
|
||||
import { AuthDto } from 'src/dtos/auth.dto';
|
||||
import { DuplicateResponseDto } from 'src/dtos/duplicate.dto';
|
||||
|
|
@ -20,6 +21,14 @@ export class DuplicateService extends BaseService {
|
|||
}));
|
||||
}
|
||||
|
||||
async delete(auth: AuthDto, id: string): Promise<void> {
|
||||
await this.duplicateRepository.delete(auth.user.id, id);
|
||||
}
|
||||
|
||||
async deleteAll(auth: AuthDto, dto: BulkIdsDto) {
|
||||
await this.duplicateRepository.deleteAll(auth.user.id, dto.ids);
|
||||
}
|
||||
|
||||
@OnJob({ name: JobName.QUEUE_DUPLICATE_DETECTION, queue: QueueName.DUPLICATE_DETECTION })
|
||||
async handleQueueSearchDuplicates({ force }: JobOf<JobName.QUEUE_DUPLICATE_DETECTION>): Promise<JobStatus> {
|
||||
const { machineLearning } = await this.getConfig({ withCache: false });
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue