likes
comments
collection
share

NestJS最佳实践--#7 软删除及恢复实现回收站功能

作者站长头像
站长
· 阅读数 16

文章发布在专栏NestJS最佳实践

代码地址:github.com/slashspaces…

学习目标

  • 软删除与恢复
  • 批量删除与批量恢复

什么是软删除

软删除是一种广泛应用于业务应用程序的模式。它允许您将一些记录标记为已删除,而无需从数据库中真正删除。因此,可以在防止软删除的记录被选中的同时,旧记录仍然可以被引用。

通过软删除,我们可以实现类似于回收站的功能,比如将文章软删除后放进回收站,后面也可以从回收站中恢复。

TypeORM软删除及恢复用法

  1. 在Entity中使用@DeleteDateColumn()装饰器

    @DeleteDateColumn()
    public deletedAt: Date;
    
  2. 软删除: 使用softRemove替代remove

    • 执行softRemovedeletedAtnull变为具体删除日期
  3. 恢复: 使用restore方法恢复数据

    • 执行restoredeletedAt由具体删除日期变为null
  4. 查询: 当我们使用find()或类似方法查询时,TypeORM会自动取查询deletedAtNULL的记录,当然我们也可以指定withDeleted字段来控制是否查询软删除数据

    const category = await this.categoriesRepository.findOne(id, {
        relations: ['posts'],
        withDeleted: true
    }
    

如下图所示, deletedAt一列为日期代表该条数据被软删除,为null则为正常数据 NestJS最佳实践--#7 软删除及恢复实现回收站功能

批量删除与恢复DTO

因为各模块都会用到软删除及恢复功能,因此我们提取出DeleteDtoRestoreDtosrc/common/dtos 目录下,作为全局公用DTO

/**
 * 批量删除
 */
export class DeleteDto {
    @IsUUID(undefined, { each: true, message: 'ID格式错误' })
    @IsDefined({ each: true, message: 'ID必须指定' })
    ids: string[] = [];

    // 是否为软删除
    @Transform(({ value }) => Boolean(value))
    @IsBoolean()
    @IsOptional()
    soft?: boolean;
}

/**
 * 批量恢复
 */
export class RestoreDto {
    @IsUUID(undefined, { each: true, message: 'ID格式错误' })
    @IsDefined({ each: true, message: 'ID必须指定' })
    ids: string[] = [];
}

软删除及数据恢复

接下来我们要实现文章模块的软删除及数据恢复 首先给QueryPostDto加上soft字段用来判断是否查询软删除数据

@DtoValidation({ groups: ['query'] })
export class QueryPostDto extends PaginationDto {
    @IsUUID(undefined, { message: '分类ID格式错误' })
    @IsOptional()
    category?: string;

    @IsEnum(SelectSoftDeleteMode)
    @IsOptional()
    soft?: SelectSoftDeleteMode;
}
  • @IsEnum: 校验soft值是否为指定枚举值

接下来修改一下PostService

  • DeleteDto中soft为true代表软删除,要执行softRemove
  • DeleteDto中soft不设置或设为false,代表物理删除,要执行remove
@Injectable()
export class PostService {
    // ...
    
    async remove({ ids, soft }: DeleteDto) {
        const posts = await this.postsRepository.find({
            where: { id: In(ids) },
            withDeleted: false, // 过滤掉已删除的
        });
        if (soft) return this.postsRepository.softRemove(posts);
        return this.postsRepository.remove(posts);
    }

    async restore({ ids }: RestoreDto) {
        const posts = await this.postsRepository.find({
            where: { id: In(ids) },
            withDeleted: true,
        });
        // 过滤掉不在回收站中的数据
        const deletedIds = posts.filter((post) => !isNil(post.deletedAt)).map((post) => post.id);
        this.postsRepository.restore(deletedIds);
    }
    
    // ...
}

最后修改下PostController

@Controller('post')
export class PostController {
    // ...
    
    @Post('delete')
    remove(@Body() data: DeleteDto) {
        return this.postService.remove(data);
    }

    @Patch('restore')
    restore(@Body() data: RestoreDto) {
        return this.postService.restore(data);
    }
    
    // ...
}

这样我们就实现了文章的批量删除,软删除与批量恢复功能啦.至于分类和评论模块的软删除与恢复,代码与文章模块类似, 只不过要注意下树形结构的级联操作,这里就不再赘述。

转载自:https://juejin.cn/post/7215422960815767613
评论
请登录