diff --git a/src/posts/dto/create-post.dto.ts b/src/posts/dto/create-post.dto.ts index 1a2b3c5..9af05b1 100644 --- a/src/posts/dto/create-post.dto.ts +++ b/src/posts/dto/create-post.dto.ts @@ -1 +1,7 @@ -export class CreatePostDto {} +import {IsNotEmpty, IsString} from "class-validator"; + +export class CreatePostDto { + @IsString({ each: true }) + @IsNotEmpty() + paragraphs: string[]; +} diff --git a/src/posts/entities/post.entity.ts b/src/posts/entities/post.entity.ts index eaa5bdc..a80187a 100644 --- a/src/posts/entities/post.entity.ts +++ b/src/posts/entities/post.entity.ts @@ -13,6 +13,9 @@ class Post { @Column() public content: string; + @Column('text', { array: true }) + public paragraphs: string[]; + @Column({nullable: true}) public category?: string; diff --git a/src/posts/posts.controller.ts b/src/posts/posts.controller.ts index 72c8a92..dfd0c83 100644 --- a/src/posts/posts.controller.ts +++ b/src/posts/posts.controller.ts @@ -16,6 +16,7 @@ import {CreatePostDto} from './dto/create-post.dto'; import {UpdatePostDto} from './dto/update-post.dto'; import JwtAuthenticationGuard from "../authentication/jwt-authentication.guard"; import RequestWithUser from "../authentication/requestWithUser.interface"; +import {PaginationParams} from "../utils/types/paginationParams"; @Controller('posts') @UseInterceptors(ClassSerializerInterceptor) @@ -31,11 +32,14 @@ export class PostsController { @Get() - async getPosts(@Query('search') search: string) { + async getPosts( + @Query('search') search: string, + @Query() { offset, limit }: PaginationParams + ) { if (search) { - return this.postsService.searchForPosts(search); + return this.postsService.searchForPosts(search, offset, limit); } - return this.postsService.getAllPosts(); + return this.postsService.getAllPosts(offset, limit); } @Get() diff --git a/src/posts/posts.service.ts b/src/posts/posts.service.ts index f24cca1..05ffc4c 100644 --- a/src/posts/posts.service.ts +++ b/src/posts/posts.service.ts @@ -3,7 +3,7 @@ import {CreatePostDto} from './dto/create-post.dto'; import {UpdatePostDto} from './dto/update-post.dto'; import User from "../users/entities/user.entity"; import {InjectRepository} from "@nestjs/typeorm"; -import {Repository} from "typeorm"; +import {FindManyOptions, MoreThan, Repository} from "typeorm"; import Post from './entities/post.entity'; import {PostNotFoundException} from "./exception/postNotFound.exception"; import PostsSearchService from "./postsSearch.service"; @@ -27,7 +27,7 @@ export class PostsService { return newPost; } - async searchForPosts(text: string) { + async searchForPosts(text: string, offset?: number, limit?: number) { const results = await this.postsSearchService.search(text); const ids = results.flatMap(result => result.hits.hits.map(hit => hit._source.id)); if (!ids.length) { @@ -39,10 +39,34 @@ export class PostsService { }); } + + + async getAllPosts(offset?: number, limit?: number, startId = 0) { + + const where: FindManyOptions['where'] = {}; + let separateCount = 0; + if (startId) { + where.id = MoreThan(startId); + separateCount = await this.repo.count(); + } - getAllPosts() { - return this.repo.find({relations: ['author']}); + const [items, count] = await this.repo.findAndCount({ + where, + relations: { + author: true + }, + order: { + id: 'ASC' + }, + skip: offset, + take: limit + }); + + return { + items, + count: startId ? separateCount : count + } } async getPostById(id: number) { diff --git a/src/posts/postsSearch.service.ts b/src/posts/postsSearch.service.ts index 91f7940..4d765b8 100644 --- a/src/posts/postsSearch.service.ts +++ b/src/posts/postsSearch.service.ts @@ -3,6 +3,7 @@ import {ElasticsearchService} from '@nestjs/elasticsearch'; import Post from "./entities/post.entity"; import {PostSearchResult} from "./types/postSearchResult.interface"; import {PostSearchBody} from "./types/postSearchBody.interface"; +import PostCountResult from "./types/postCountBody.interface"; @Injectable() export default class PostsSearchService { @@ -25,6 +26,22 @@ export default class PostsSearchService { }); } + async count(query: string, fields: string[]) { + const result = await this.elasticsearchService.count({ + index: this.index, + query: { + multi_match: { + query, + fields, + }, + }, + }); + + return result.count; + } + + + async search(text: string) { const result = await this.elasticsearchService.search({ index: this.index, diff --git a/src/posts/types/postCountBody.interface.ts b/src/posts/types/postCountBody.interface.ts new file mode 100644 index 0000000..19e322f --- /dev/null +++ b/src/posts/types/postCountBody.interface.ts @@ -0,0 +1,5 @@ +interface PostCountResult { + count: number; +} + +export default PostCountResult; \ No newline at end of file diff --git a/src/utils/types/paginationParams.ts b/src/utils/types/paginationParams.ts new file mode 100644 index 0000000..39600b5 --- /dev/null +++ b/src/utils/types/paginationParams.ts @@ -0,0 +1,23 @@ +import { IsNumber, Min, IsOptional } from 'class-validator'; +import { Type } from 'class-transformer'; + +export class PaginationParams { + + @IsOptional() + @Type(() => Number) + @IsNumber() + @Min(1) + startId?: number; + + @IsOptional() + @Type(() => Number) + @IsNumber() + @Min(0) + offset?: number; + + @IsOptional() + @Type(() => Number) + @IsNumber() + @Min(1) + limit?: number; +} \ No newline at end of file