add base service

This commit is contained in:
liuyi 2025-06-04 11:14:19 +08:00
parent 6f581ad383
commit 3fa9ecc33a
7 changed files with 61 additions and 60 deletions

View File

@ -60,6 +60,6 @@ export class CategoryController {
@Delete(':id')
@SerializeOptions({ groups: ['category-detail'] })
async delete(@Param('id', new ParseUUIDPipe()) id: string) {
return this.service.delete(id);
return this.service.delete([id]);
}
}

View File

@ -2,33 +2,23 @@ import { Injectable } from '@nestjs/common';
import { isNil, omit } from 'lodash';
import { EntityNotFoundError } from 'typeorm';
import {
CreateCategoryDto,
QueryCategoryDto,
UpdateCategoryDto,
} from '@/modules/content/dtos/category.dto';
import { CreateCategoryDto, UpdateCategoryDto } from '@/modules/content/dtos/category.dto';
import { CategoryEntity } from '@/modules/content/entities/category.entity';
import { CategoryRepository } from '@/modules/content/repositories/category.repository';
import { treePaginate } from '@/modules/database/utils';
import { BaseService } from '@/modules/database/base/service';
@Injectable()
export class CategoryService {
constructor(protected repository: CategoryRepository) {}
export class CategoryService extends BaseService<CategoryEntity, CategoryRepository> {
protected enableTrash = true;
constructor(protected repository: CategoryRepository) {
super(repository);
}
async findTrees() {
return this.repository.findTrees();
}
async paginate(options?: QueryCategoryDto) {
const tree = await this.findTrees();
const data = await this.repository.toFlatTrees(tree);
return treePaginate(options, data);
}
async detail(id: string) {
return this.repository.findOneOrFail({ where: { id }, relations: ['parent', 'children'] });
}
async create(data: CreateCategoryDto) {
const item = await this.repository.save({
...data,
@ -56,21 +46,6 @@ export class CategoryService {
return item;
}
async delete(id: string) {
const item = await this.repository.findOneOrFail({
where: { id },
relations: ['parent', 'children'],
});
if (!isNil(item.children) && item.children.length > 0) {
const childrenCategories = [...item.children].map((c) => {
c.parent = item.parent;
return item;
});
await this.repository.save(childrenCategories, { reload: true });
}
return this.repository.remove(item);
}
async getParent(current?: string, parentId?: string) {
if (current === parentId) {
return undefined;

View File

@ -11,14 +11,14 @@ import {
} from '@/modules/content/dtos/comment.dto';
import { CommentEntity } from '@/modules/content/entities/comment.entity';
import { CommentRepository, PostRepository } from '@/modules/content/repositories';
import { BaseService } from '@/modules/database/base/service';
import { treePaginate } from '@/modules/database/utils';
@Injectable()
export class CommentService {
constructor(
protected repository: CommentRepository,
protected postRepository: PostRepository,
) {}
export class CommentService extends BaseService<CommentEntity, CommentRepository> {
constructor(protected repository: CommentRepository, protected postRepository: PostRepository) {
super(repository);
}
async findTrees(options: QueryCommentTreeDto = {}) {
return this.repository.findTrees({
@ -91,4 +91,8 @@ export class CommentService {
}
return parent;
}
update(data: any, ...others: any[]): Promise<CommentEntity> {
throw new Error('Method not implemented.');
}
}

View File

@ -11,6 +11,7 @@ import { CategoryRepository } from '@/modules/content/repositories';
import { PostRepository } from '@/modules/content/repositories/post.repository';
import { SearchService } from '@/modules/content/services/search.service';
import { SearchType } from '@/modules/content/types';
import { BaseService } from '@/modules/database/base/service';
import { SelectTrashMode } from '@/modules/database/constants';
import { QueryHook } from '@/modules/database/types';
import { paginate } from '@/modules/database/utils';
@ -24,7 +25,9 @@ type FindParams = {
};
@Injectable()
export class PostService {
export class PostService extends BaseService<PostEntity, PostRepository, FindParams> {
protected enableTrash = true;
constructor(
protected repository: PostRepository,
protected categoryRepository: CategoryRepository,
@ -32,13 +35,15 @@ export class PostService {
protected tagRepository: TagRepository,
protected searchService?: SearchService,
protected searchType: SearchType = 'mysql',
) {}
) {
super(repository);
}
async paginate(options: QueryPostDto, callback?: QueryHook<PostEntity>) {
if (!isNil(this.searchService) && !isNil(options.search) && this.searchType === 'meili') {
return this.searchService.search(
options.search,
pick(options, ['trashed', 'page', 'limit']),
pick(options, ['trashed', 'page', 'limit', 'isPublished']),
);
}
const qb = await this.buildListQuery(this.repository.buildBaseQB(), options, callback);

View File

@ -47,7 +47,7 @@ export class SearchService implements OnModuleInit {
return this.client;
}
async search(text: string, param: SearchOption = {}) {
async search(text: string, param: SearchOption = {}): Promise<any> {
const option = { page: 1, limit: 10, trashed: SelectTrashMode.ONLY, ...param };
const limit = isNil(option.limit) || option.limit < 1 ? 1 : option.limit;
const page = isNil(option.page) || option.page < 1 ? 1 : option.page;

View File

@ -1,19 +1,18 @@
import { Injectable } from '@nestjs/common';
import { omit } from 'lodash';
import { In } from 'typeorm';
import { CreateTagDto, QueryTagDto, UpdateTagDto } from '@/modules/content/dtos/tag.dto';
import { CreateTagDto, UpdateTagDto } from '@/modules/content/dtos/tag.dto';
import { TagRepository } from '@/modules/content/repositories/tag.repository';
import { paginate } from '@/modules/database/utils';
import { BaseService } from '@/modules/database/base/service';
import { TagEntity } from '../entities';
@Injectable()
export class TagService {
constructor(protected repository: TagRepository) {}
export class TagService extends BaseService<TagEntity, TagRepository> {
protected enableTrash = true;
async paginate(options: QueryTagDto) {
const qb = this.repository.buildBaseQB();
return paginate(qb, options);
constructor(protected repository: TagRepository) {
super(repository);
}
async detail(id: string) {
@ -31,11 +30,4 @@ export class TagService {
await this.repository.update(data.id, omit(data, ['id']));
return this.detail(data.id);
}
async delete(ids: string[]) {
const items = await this.repository.find({
where: { id: In(ids) },
});
return this.repository.remove(items);
}
}

View File

@ -1,4 +1,4 @@
import { NotFoundException } from '@nestjs/common';
import { ForbiddenException, NotFoundException } from '@nestjs/common';
import { isNil } from 'lodash';
import { In, ObjectLiteral, SelectQueryBuilder } from 'typeorm';
@ -127,4 +127,29 @@ export abstract class BaseService<
}
return this.repository.remove(items);
}
async restore(ids: string[]) {
if (!this.enableTrash) {
throw new ForbiddenException(
`Can not to retore ${this.repository.qbName},because trash not enabled!`,
);
}
const items = await this.repository.find({
where: { id: In(ids) as any },
withDeleted: true,
});
const trashIds = items.filter((o) => !isNil(o.deletedAt)).map((o) => o.id);
if (trashIds.length < 1) {
return [];
}
await this.repository.restore(trashIds);
const qb = await this.buildListQB(this.repository.buildBaseQB(), undefined, async (_) =>
_.andWhereInIds(trashIds),
);
return qb.getMany();
}
abstract create(data: any, ...others: any[]): Promise<T>;
abstract update(data: any, ...others: any[]): Promise<T>;
}