From cbb3a6e7de629169010967799b90762315c465dd Mon Sep 17 00:00:00 2001 From: liuyi Date: Tue, 20 May 2025 23:30:22 +0800 Subject: [PATCH] add relations --- src/modules/content/dtos/category.dto.ts | 60 ++++++++++++++++++++++++ src/modules/content/dtos/comment.dto.ts | 51 ++++++++++++++++++++ src/modules/content/dtos/post.dto.ts | 23 +++++++++ src/modules/content/dtos/tag.dto.ts | 49 +++++++++++++++++++ src/modules/database/utils.ts | 28 +++++++++++ 5 files changed, 211 insertions(+) create mode 100644 src/modules/content/dtos/category.dto.ts create mode 100644 src/modules/content/dtos/comment.dto.ts create mode 100644 src/modules/content/dtos/tag.dto.ts diff --git a/src/modules/content/dtos/category.dto.ts b/src/modules/content/dtos/category.dto.ts new file mode 100644 index 0000000..88e6e91 --- /dev/null +++ b/src/modules/content/dtos/category.dto.ts @@ -0,0 +1,60 @@ +import { PartialType } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; +import { + IsDefined, + IsNotEmpty, + IsNumber, + IsOptional, + IsUUID, + MaxLength, + Min, + ValidateIf, +} from 'class-validator'; +import { toNumber } from 'lodash'; + +import { PaginateOptions } from '@/modules/database/types'; + +export class QueryCategoryDto implements PaginateOptions { + @Transform(({ value }) => toNumber(value)) + @Min(1, { message: 'The current page must be greater than 1.' }) + @IsNumber() + @IsOptional() + page = 1; + + @Transform(({ value }) => toNumber(value)) + @Min(1, { message: 'The number of data displayed per page must be greater than 1.' }) + @IsNumber() + @IsOptional() + limit = 10; +} + +export class CreateCategoryDto { + @MaxLength(25, { + always: true, + message: 'The length of the category name shall not exceed $constraint1', + }) + @IsNotEmpty({ groups: ['create'], message: 'The classification name cannot be empty' }) + @IsOptional({ groups: ['update'] }) + name: string; + + @IsUUID(undefined, { + always: true, + message: 'The format of the parent category ID is incorrect.', + }) + @ValidateIf((value) => value.parent !== null && value.parent) + @IsOptional({ always: true }) + @Transform((value) => (value === 'null' ? null : value)) + parent?: string; + + @Transform(({ value }) => toNumber(value)) + @Min(0, { always: true, message: 'The sorted value must be greater than 0.' }) + @IsNumber(undefined, { always: true }) + @IsOptional({ always: true }) + customOrder?: number = 0; +} + +export class UpdateCategoryDto extends PartialType(CreateCategoryDto) { + @IsUUID(undefined, { message: 'The ID format is incorrect', groups: ['update'] }) + @IsDefined({ groups: ['update'], message: 'The ID must be specified' }) + id: string; +} diff --git a/src/modules/content/dtos/comment.dto.ts b/src/modules/content/dtos/comment.dto.ts new file mode 100644 index 0000000..daeafa8 --- /dev/null +++ b/src/modules/content/dtos/comment.dto.ts @@ -0,0 +1,51 @@ +import { PickType } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; +import { + IsDefined, + IsNotEmpty, + IsNumber, + IsOptional, + IsUUID, + MaxLength, + Min, + ValidateIf, +} from 'class-validator'; +import { toNumber } from 'lodash'; + +import { PaginateOptions } from '@/modules/database/types'; + +export class QueryCommentDto implements PaginateOptions { + @Transform(({ value }) => toNumber(value)) + @Min(1, { message: 'The current page must be greater than 1.' }) + @IsNumber() + @IsOptional() + page = 1; + + @Transform(({ value }) => toNumber(value)) + @Min(1, { message: 'The number of data displayed per page must be greater than 1.' }) + @IsNumber() + @IsOptional() + limit = 10; + + @IsUUID(undefined, { message: 'The ID format is incorrect' }) + @IsOptional() + post?: string; +} + +export class QueryCommentTreeDto extends PickType(QueryCommentDto, ['post']) {} + +export class CreateCommentDto { + @MaxLength(1000, { message: '' }) + @IsNotEmpty({ message: '' }) + body: string; + + @IsUUID(undefined, { message: 'The ID format is incorrect' }) + @IsDefined({ message: 'The ID must be specified' }) + post: string; + + @IsUUID(undefined, { message: 'The ID format is incorrect', always: true }) + @ValidateIf((value) => value.parent !== null && value.parent) + @IsOptional({ always: true }) + @Transform(({ value }) => (value === 'null' ? null : value)) + parent?: string; +} diff --git a/src/modules/content/dtos/post.dto.ts b/src/modules/content/dtos/post.dto.ts index 07ae320..66cb838 100644 --- a/src/modules/content/dtos/post.dto.ts +++ b/src/modules/content/dtos/post.dto.ts @@ -43,6 +43,14 @@ export class QueryPostDto implements PaginateOptions { @IsNumber() @IsOptional() limit = 10; + + @IsUUID(undefined, { message: 'The ID format is incorrect' }) + @IsOptional() + category?: string; + + @IsUUID(undefined, { message: 'The ID format is incorrect' }) + @IsOptional() + tag?: string; } export class CreatePostDto { @@ -84,6 +92,21 @@ export class CreatePostDto { @IsNumber(undefined, { always: true }) @IsOptional({ always: true }) customOrder?: number; + + @IsUUID(undefined, { + always: true, + message: 'The ID format is incorrect', + }) + @IsOptional({ always: true }) + category?: string; + + @IsUUID(undefined, { + always: true, + each: true, + message: 'The ID format is incorrect', + }) + @IsOptional({ always: true }) + tags?: string[]; } export class UpdatePostDto extends PartialType(CreatePostDto) { diff --git a/src/modules/content/dtos/tag.dto.ts b/src/modules/content/dtos/tag.dto.ts new file mode 100644 index 0000000..7a56d96 --- /dev/null +++ b/src/modules/content/dtos/tag.dto.ts @@ -0,0 +1,49 @@ +import { PartialType } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; +import { + IsDefined, + IsNotEmpty, + IsNumber, + IsOptional, + IsUUID, + MaxLength, + Min, +} from 'class-validator'; +import { toNumber } from 'lodash'; + +export class QueryTagDto implements PaginateOptions { + @Transform(({ value }) => toNumber(value)) + @Min(1, { message: 'The current page must be greater than 1.' }) + @IsNumber() + @IsOptional() + page = 1; + + @Transform(({ value }) => toNumber(value)) + @Min(1, { message: 'The number of data displayed per page must be greater than 1.' }) + @IsNumber() + @IsOptional() + limit = 10; +} + +export class CreateTagDto { + @MaxLength(255, { + always: true, + message: 'The maximum length of the label name is $constraint1', + }) + @IsNotEmpty({ groups: ['create'], message: 'The classification name cannot be empty' }) + @IsOptional({ groups: ['update'] }) + name: string; + + @MaxLength(500, { + always: true, + message: 'The maximum length of the label description is $constraint1', + }) + @IsOptional({ always: true }) + desc?: string; +} + +export class UpdateTagDto extends PartialType(CreateTagDto) { + @IsUUID(undefined, { message: 'The ID format is incorrect', groups: ['update'] }) + @IsDefined({ groups: ['update'], message: 'The ID must be specified' }) + id: string; +} diff --git a/src/modules/database/utils.ts b/src/modules/database/utils.ts index 8bad240..365201c 100644 --- a/src/modules/database/utils.ts +++ b/src/modules/database/utils.ts @@ -30,3 +30,31 @@ export const paginate = async ( }, }; }; + +export function treePaginate( + options: PaginateOptions, + data: T[], +): PaginateReturn { + const { page, limit } = options; + let items: T[] = []; + const totalItems = data.length; + const totalRst = totalItems / limit; + const totalPages = + totalRst > Math.floor(totalRst) ? Math.floor(totalRst) + 1 : Math.floor(totalRst); + let itemCount = 0; + if (page <= totalPages) { + itemCount = page === totalPages ? totalItems - (totalPages - 1) * limit : limit; + const start = (page - 1) * limit; + items = data.slice(start, start + itemCount); + } + return { + meta: { + itemCount, + totalItems, + perPage: limit, + totalPages, + currentPage: page, + }, + items, + }; +}