目录
批量操作与软删除
视频地址:https://www.bilibili.com/video/BV1DP411G75n/
学习目标
- 实现数据的批量操作
- 实现软删除和数据恢复
- 使用软删除实现回收站功能
核心模块
常量
添加一个枚举常量用于定义软删除的查询类型,以便实现回收站功能
// src/modules/core/constants.ts
export enum QueryTrashMode {
ALL = 'all', // 包含已软删除和未软删除的数据
ONLY = 'only', // 只包含软删除的数据
NONE = 'none', // 只包含未软删除的数据
}
类型
更改原来的查询和观察者设置类型以支持软删除
// src/modules/core/types.ts
/**
* 软删除DTO接口
*/
export interface TrashedDto {
trashed?: QueryTrashMode;
}
export interface QueryParams<E extends ObjectLiteral> {
addQuery?: (query: SelectQueryBuilder<E>) => SelectQueryBuilder<E>;
orderBy?: OrderQueryType;
withTrashed?: boolean;
}
export type TreeQueryParams<E extends ObjectLiteral> = FindTreeOptions & QueryParams<E>;
export type QueryListParams<E extends ObjectLiteral> = Omit<TreeQueryParams<E>, 'withTrashed'> & {
trashed?: `${QueryTrashMode}`;
};
export type SubcriberSetting = {
// 监听的模型是否为树模型
tree?: boolean;
// 是否支持软删除
trash?: boolean;
};
存储类
更改树形存储基类BaseTreeRepository
中的一些查询方法以支持软删除
// src/modules/core/crud/tree.repository.ts
export class BaseTreeRepository<E extends ObjectLiteral> extends TreeRepository<E> {
async findTrees(params: TreeQueryParams<E> = {}): Promise<E[]> {
params.withTrashed = params.withTrashed ?? false;
// ...
}
findRoots(params: TreeQueryParams<E> = {}): Promise<E[]> {
// ...
if (withTrashed) qb.withDeleted();
return qb.getMany();
}
createDtsQueryBuilder(
closureTableAlias: string,
entity: E,
params: TreeQueryParams<E> = {},
): SelectQueryBuilder<E> {
// ...
return withTrashed ? qb.withDeleted() : qb;
}
createAtsQueryBuilder(
closureTableAlias: string,
entity: E,
params: TreeQueryParams<E> = {},
): SelectQueryBuilder<E> {
// ...
return withTrashed ? qb.withDeleted() : qb;
}
}
订阅者
修改BaseSubscriber
的afterLoad
方法,为每个支持软删除的模型的trashed
只是值为前端作为判断是否处于回收站状态的依据
// src/modules/core/crud/subscriber.ts
@EventSubscriber()
export abstract class BaseSubscriber<E extends ObjectLiteral>
implements EntitySubscriberInterface<E>
{
// ...
async afterLoad(entity: any) {
// 是否启用树形
if (this.setting.tree && isNil(entity.level)) entity.level = 0;
// 是否启用软删除
if (this.setting.trash) entity.trashed = !!entity.deletedAt;
}
}
DTO
添加几个公共的DTO用于支持控制器的批量删除,批量恢复,单个删除和单个查询实现软删除功能
// src/modules/core/crud/dtos
@Injectable()
export class QueryDetailDto {
@Transform(({ value }) => tBoolean(value))
@IsBoolean()
@IsOptional()
trashed?: boolean; // 在查询单个数据时,是否包含软删除后的数据
}
@DtoValidation()
export class DeleteDto {
@Transform(({ value }) => tBoolean(value))
@IsBoolean()
@IsOptional()
trash?: boolean; // 在删除数据时是否软删除
}
export class DeleteMultiDto extends DeleteDto {
@IsUUID(undefined, {
each: true,
message: 'ID格式错误',
})
@IsDefined({
each: true,
message: 'ID必须指定',
})
items: string[] = []; // 批量删除数据的ID列表
}
export class DeleteRestoreDto {
@IsUUID(undefined, {
each: true,
message: 'ID格式错误',
})
@IsDefined({
each: true,
message: 'ID必须指定',
})
items: string[] = []; // 批量恢复数据的ID列表
}
内容模块
模型
为需要支持软删除的模型(CategoryEntity
和PostEntity
)添加上deletedAt
和trashed
字段以支持软删除
以CategoryEntity
为例
// src/modules/content/entities/category.entity.ts
@Exclude()
@Tree('materialized-path')
@Entity('content_categories')
export class CategoryEntity extends BaseEntity {
// ...
@Expose()
@Type(() => Date)
@DeleteDateColumn({
comment: '创建时间',
})
deletedAt!: Date;
@Expose()
trashed!: boolean;
}