add service
This commit is contained in:
parent
8ab109ce26
commit
4c063515ba
@ -7,5 +7,6 @@ export enum PostOrder {
|
||||
CREATED = 'createdAt',
|
||||
UPDATED = 'updatedAt',
|
||||
PUBLISHED = 'publishedAt',
|
||||
COMMENTCOUNT = 'commentCount',
|
||||
CUSTOM = 'custom',
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ export class CreateCategoryDto {
|
||||
})
|
||||
@ValidateIf((value) => value.parent !== null && value.parent)
|
||||
@IsOptional({ always: true })
|
||||
@Transform((value) => (value === 'null' ? null : value))
|
||||
@Transform(({ value }) => (value === 'null' ? null : value))
|
||||
parent?: string;
|
||||
|
||||
@Transform(({ value }) => toNumber(value))
|
||||
|
@ -11,6 +11,8 @@ import {
|
||||
} from 'class-validator';
|
||||
import { toNumber } from 'lodash';
|
||||
|
||||
import { PaginateOptions } from '@/modules/database/types';
|
||||
|
||||
export class QueryTagDto implements PaginateOptions {
|
||||
@Transform(({ value }) => toNumber(value))
|
||||
@Min(1, { message: 'The current page must be greater than 1.' })
|
||||
|
@ -2,7 +2,11 @@ import { Injectable } from '@nestjs/common';
|
||||
import { isNil, omit } from 'lodash';
|
||||
import { EntityNotFoundError } from 'typeorm';
|
||||
|
||||
import { CreateCategoryDto, QueryCategoryDto } from '@/modules/content/dtos/category.dto';
|
||||
import {
|
||||
CreateCategoryDto,
|
||||
QueryCategoryDto,
|
||||
UpdateCategoryDto,
|
||||
} from '@/modules/content/dtos/category.dto';
|
||||
import { CategoryEntity } from '@/modules/content/entities/CategoryEntity';
|
||||
import { CategoryRepository } from '@/modules/content/repositories/category.repository';
|
||||
import { treePaginate } from '@/modules/database/utils';
|
||||
@ -22,7 +26,7 @@ export class CategoryService {
|
||||
}
|
||||
|
||||
async detail(id: string) {
|
||||
return this.repository.findOneByOrFail({ where: { id }, relations: ['parent'] });
|
||||
return this.repository.findOneOrFail({ where: { id }, relations: ['parent'] });
|
||||
}
|
||||
|
||||
async create(data: CreateCategoryDto) {
|
||||
@ -35,7 +39,7 @@ export class CategoryService {
|
||||
|
||||
async update(data: UpdateCategoryDto) {
|
||||
await this.repository.update(data.id, omit(data, ['id', 'parent']));
|
||||
const item = await this.repository.findOneByOrFail({
|
||||
const item = await this.repository.findOneOrFail({
|
||||
where: { id: data.id },
|
||||
relations: ['parent'],
|
||||
});
|
||||
@ -53,7 +57,7 @@ export class CategoryService {
|
||||
}
|
||||
|
||||
async delete(id: string) {
|
||||
const item = await this.repository.findOneByOrFail({
|
||||
const item = await this.repository.findOneOrFail({
|
||||
where: { id },
|
||||
relations: ['parent', 'children'],
|
||||
});
|
||||
|
@ -4,10 +4,17 @@ import { isNil } from 'lodash';
|
||||
|
||||
import { EntityNotFoundError, SelectQueryBuilder } from 'typeorm';
|
||||
|
||||
import { QueryCommentTreeDto } from '@/modules/content/dtos/comment.dto';
|
||||
import {
|
||||
CreateCommentDto,
|
||||
QueryCommentDto,
|
||||
QueryCommentTreeDto,
|
||||
} from '@/modules/content/dtos/comment.dto';
|
||||
import { CommentEntity } from '@/modules/content/entities/comment.entity';
|
||||
import { treePaginate } from '@/modules/database/utils';
|
||||
|
||||
import { CommentRepository } from '../repositories/comment.repository';
|
||||
import { PostRepository } from '../repositories/post.repository';
|
||||
|
||||
@Injectable()
|
||||
export class CommentService {
|
||||
constructor(
|
||||
@ -44,7 +51,7 @@ export class CommentService {
|
||||
|
||||
async create(data: CreateCommentDto) {
|
||||
const parent = await this.getParent(undefined, data.parent);
|
||||
if (!isNil(parent) && parent.post.id !== data.post.id) {
|
||||
if (!isNil(parent) && parent.post.id !== data.post) {
|
||||
throw new ForbiddenException('Parent comment and child comment must belong same post!');
|
||||
}
|
||||
const item = await this.repository.save({
|
||||
|
4
src/modules/content/services/index.ts
Normal file
4
src/modules/content/services/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './category.service';
|
||||
export * from './tag.service';
|
||||
export * from './post.service';
|
||||
export * from './comment.service';
|
@ -1,21 +1,35 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { isNil } from '@nestjs/common/utils/shared.utils';
|
||||
|
||||
import { isFunction, omit } from 'lodash';
|
||||
import { EntityNotFoundError, IsNull, Not, SelectQueryBuilder } from 'typeorm';
|
||||
import { isArray, isFunction, omit } from 'lodash';
|
||||
import { EntityNotFoundError, In, IsNull, Not, SelectQueryBuilder } from 'typeorm';
|
||||
|
||||
import { PostOrder } from '@/modules/content/constants';
|
||||
import { CreatePostDto, UpdatePostDto } from '@/modules/content/dtos/post.dto';
|
||||
import { CreatePostDto, QueryPostDto, UpdatePostDto } from '@/modules/content/dtos/post.dto';
|
||||
import { PostEntity } from '@/modules/content/entities/post.entity';
|
||||
import { PostRepository } from '@/modules/content/repositories/post.repository';
|
||||
import { PaginateOptions, QueryHook } from '@/modules/database/types';
|
||||
import { QueryHook } from '@/modules/database/types';
|
||||
import { paginate } from '@/modules/database/utils';
|
||||
|
||||
import { CategoryRepository } from '../repositories/category.repository';
|
||||
import { TagRepository } from '../repositories/tag.repository';
|
||||
|
||||
import { CategoryService } from './category.service';
|
||||
|
||||
type FindParams = {
|
||||
[key in keyof Omit<QueryPostDto, 'limit' | 'page'>]: QueryPostDto[key];
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class PostService {
|
||||
constructor(protected repository: PostRepository) {}
|
||||
constructor(
|
||||
protected repository: PostRepository,
|
||||
protected categoryRepository: CategoryRepository,
|
||||
protected categoryService: CategoryService,
|
||||
protected tagRepository: TagRepository,
|
||||
) {}
|
||||
|
||||
async paginate(options: PaginateOptions, callback?: QueryHook<PostEntity>) {
|
||||
async paginate(options: QueryPostDto, callback?: QueryHook<PostEntity>) {
|
||||
const qb = await this.buildListQuery(this.repository.buildBaseQB(), options, callback);
|
||||
return paginate(qb, options);
|
||||
}
|
||||
@ -36,7 +50,15 @@ export class PostService {
|
||||
if (!isNil(data.publish)) {
|
||||
publishedAt = data.publish ? new Date() : null;
|
||||
}
|
||||
const item = await this.repository.save({ ...omit(data, ['publish']), publishedAt });
|
||||
const createPostDto = {
|
||||
...omit(data, ['publish']),
|
||||
category: isNil(data.category)
|
||||
? null
|
||||
: await this.categoryRepository.findOneOrFail({ where: { id: data.category } }),
|
||||
tags: isArray(data.tags) ? await this.tagRepository.findBy({ id: In(data.tags) }) : [],
|
||||
publishedAt,
|
||||
};
|
||||
const item = await this.repository.save(createPostDto);
|
||||
return this.detail(item.id);
|
||||
}
|
||||
|
||||
@ -45,8 +67,22 @@ export class PostService {
|
||||
if (!isNil(data.publish)) {
|
||||
publishedAt = data.publish ? new Date() : null;
|
||||
}
|
||||
const post = await this.detail(data.id);
|
||||
if (data.category !== undefined) {
|
||||
post.category = isNil(data.category)
|
||||
? null
|
||||
: await this.categoryRepository.findOneByOrFail({ id: data.category });
|
||||
await this.repository.save(post, { reload: true });
|
||||
}
|
||||
if (isArray(data.tags)) {
|
||||
await this.repository
|
||||
.createQueryBuilder('post')
|
||||
.relation(PostEntity, 'tags')
|
||||
.of(post)
|
||||
.addAndRemove(data.tags, post.tags ?? []);
|
||||
}
|
||||
await this.repository.update(data.id, {
|
||||
...omit(data, ['id', 'publish']),
|
||||
...omit(data, ['id', 'publish', 'tags', 'category']),
|
||||
publishedAt,
|
||||
});
|
||||
return this.detail(data.id);
|
||||
@ -59,16 +95,22 @@ export class PostService {
|
||||
|
||||
protected async buildListQuery(
|
||||
qb: SelectQueryBuilder<PostEntity>,
|
||||
options: RecordAny,
|
||||
options: FindParams,
|
||||
callback?: QueryHook<PostEntity>,
|
||||
) {
|
||||
const { orderBy, isPublished } = options;
|
||||
const { orderBy, isPublished, category, tag } = options;
|
||||
if (typeof isPublished === 'boolean') {
|
||||
isPublished
|
||||
? qb.where({ publishedAt: Not(IsNull()) })
|
||||
: qb.where({ publishedAt: IsNull() });
|
||||
}
|
||||
this.queryOrderBy(qb, orderBy);
|
||||
if (category) {
|
||||
await this.queryByCategory(category, qb);
|
||||
}
|
||||
if (tag) {
|
||||
qb.where('tags.id = :id', { id: tag });
|
||||
}
|
||||
if (callback) {
|
||||
return callback(qb);
|
||||
}
|
||||
@ -85,6 +127,8 @@ export class PostService {
|
||||
return qb.orderBy('post.publishedAt', 'DESC');
|
||||
case PostOrder.CUSTOM:
|
||||
return qb.orderBy('post.customOrder', 'DESC');
|
||||
case PostOrder.COMMENTCOUNT:
|
||||
return qb.orderBy('post.commentCount', 'DESC');
|
||||
default:
|
||||
return qb
|
||||
.orderBy('post.createdAt', 'DESC')
|
||||
@ -92,4 +136,12 @@ export class PostService {
|
||||
.addOrderBy('post.publishedAt', 'DESC');
|
||||
}
|
||||
}
|
||||
|
||||
protected async queryByCategory(id: string, qb: SelectQueryBuilder<PostEntity>) {
|
||||
const root = await this.categoryService.detail(id);
|
||||
const tree = await this.categoryRepository.findDescendantsTree(root);
|
||||
const flatDes = await this.categoryRepository.toFlatTrees(tree.children);
|
||||
const ids = [tree.id, ...flatDes.map((item) => item.id)];
|
||||
return qb.where('categoryRepository.id IN (:...ids)', { ids });
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { omit } from 'lodash';
|
||||
|
||||
import { CreateTagDto, QueryTagDto } from '@/modules/content/dtos/tag.dto';
|
||||
import { CreateTagDto, QueryTagDto, UpdateTagDto } from '@/modules/content/dtos/tag.dto';
|
||||
import { TagRepository } from '@/modules/content/repositories/tag.repository';
|
||||
import { paginate } from '@/modules/database/utils';
|
||||
|
||||
@ -31,7 +31,7 @@ export class TagService {
|
||||
}
|
||||
|
||||
async delete(id: string) {
|
||||
const item = this.repository.findOneByOrFail({ id });
|
||||
const item = await this.repository.findOneByOrFail({ id });
|
||||
return this.repository.remove(item);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user