diff --git a/src/posts/posts.controller.ts b/src/posts/posts.controller.ts index ae42f03..72c8a92 100644 --- a/src/posts/posts.controller.ts +++ b/src/posts/posts.controller.ts @@ -1,4 +1,16 @@ -import {Controller, Get, Post, Body, Patch, Param, Delete, UseGuards, Req} from '@nestjs/common'; +import { + Controller, + Get, + Post, + Body, + Patch, + Param, + Delete, + UseGuards, + Req, + Query, + ClassSerializerInterceptor, UseInterceptors +} from '@nestjs/common'; import {PostsService} from './posts.service'; import {CreatePostDto} from './dto/create-post.dto'; import {UpdatePostDto} from './dto/update-post.dto'; @@ -6,6 +18,7 @@ import JwtAuthenticationGuard from "../authentication/jwt-authentication.guard"; import RequestWithUser from "../authentication/requestWithUser.interface"; @Controller('posts') +@UseInterceptors(ClassSerializerInterceptor) export class PostsController { constructor(private readonly postsService: PostsService) { } @@ -16,6 +29,15 @@ export class PostsController { return this.postsService.createPost(post, req.user); } + + @Get() + async getPosts(@Query('search') search: string) { + if (search) { + return this.postsService.searchForPosts(search); + } + return this.postsService.getAllPosts(); + } + @Get() findAll() { return this.postsService.findAll(); diff --git a/src/posts/posts.service.ts b/src/posts/posts.service.ts index 59f3da4..f24cca1 100644 --- a/src/posts/posts.service.ts +++ b/src/posts/posts.service.ts @@ -6,12 +6,15 @@ import {InjectRepository} from "@nestjs/typeorm"; import {Repository} from "typeorm"; import Post from './entities/post.entity'; import {PostNotFoundException} from "./exception/postNotFound.exception"; +import PostsSearchService from "./postsSearch.service"; +import {In} from "typeorm"; @Injectable() export class PostsService { constructor( @InjectRepository(Post) private repo: Repository, + private postsSearchService: PostsSearchService ) { } @@ -24,6 +27,19 @@ export class PostsService { return newPost; } + async searchForPosts(text: string) { + const results = await this.postsSearchService.search(text); + const ids = results.flatMap(result => result.hits.hits.map(hit => hit._source.id)); + if (!ids.length) { + return []; + } + return this.repo + .find({ + where: {id: In(ids)} + }); + } + + getAllPosts() { return this.repo.find({relations: ['author']}); @@ -64,11 +80,26 @@ export class PostsService { return `This action returns a #${id} post`; } - update(id: number, updatePostDto: UpdatePostDto) { - return `This action updates a #${id} post`; + async update(id: number, post: UpdatePostDto) { + await this.repo.update(id, post); + const updatedPost = await this.repo.findOne({ + where: {id}, + relations: { + author: true, + } + }); + if (updatedPost) { + await this.postsSearchService.update(updatedPost); + return updatedPost; + } + throw new PostNotFoundException(id); } - remove(id: number) { - return `This action removes a #${id} post`; + async remove(id: number) { + const deleteResponse = await this.repo.delete(id); + if (!deleteResponse.affected) { + throw new PostNotFoundException(id); + } + await this.postsSearchService.remove(id); } } diff --git a/src/posts/postsSearch.service.ts b/src/posts/postsSearch.service.ts index dbc9acd..91f7940 100644 --- a/src/posts/postsSearch.service.ts +++ b/src/posts/postsSearch.service.ts @@ -1,42 +1,81 @@ -import { Injectable } from '@nestjs/common'; -import { ElasticsearchService } from '@nestjs/elasticsearch'; +import {Injectable} from '@nestjs/common'; +import {ElasticsearchService} from '@nestjs/elasticsearch'; import Post from "./entities/post.entity"; import {PostSearchResult} from "./types/postSearchResult.interface"; import {PostSearchBody} from "./types/postSearchBody.interface"; @Injectable() export default class PostsSearchService { - index = 'posts' + index = 'posts'; - constructor( - private readonly elasticsearchService: ElasticsearchService - ) {} + constructor( + private readonly elasticsearchService: ElasticsearchService + ) { + } - async indexPost(post: Post) { - return this.elasticsearchService.index({ - index: this.index, - body: { - id: post.id, - title: post.title, - content: post.content, - authorId: post.author.id - } - }) - } + async indexPost(post: Post) { + return this.elasticsearchService.index({ + index: this.index, + document: { + id: post.id, + title: post.title, + content: post.content, + authorId: post.author.id + } + }); + } + + async search(text: string) { + const result = await this.elasticsearchService.search({ + index: this.index, + query: { + multi_match: { + query: text, + fields: ['title', 'content'], + }, + }, + }); + + const hits = result.hits.hits; + return hits.map((item) => item._source); + } + + + async remove(postId: number) { + await this.elasticsearchService.deleteByQuery({ + index: this.index, + query: { + match: { + id: postId, + } + } + + }) + } + + async update(post: Post) { + const newBody: PostSearchBody = { + id: post.id, + title: post.title, + content: post.content, + authorId: post.author.id + }; + + const script = Object.entries(newBody).reduce((result, [key, value]) => { + return `${result} ctx._source.${key}='${value}';`; + }, ''); + + await this.elasticsearchService.updateByQuery({ + index: this.index, + query: { + match: { + id: post.id, + } + }, + script: { + source: script + } + }); + } - async search(text: string) { - const response = await this.elasticsearchService.search({ - index: this.index, - body: { - query: { - multi_match: { - query: text, - fields: ['title', 'content'] - } - } - } - }) - const hits = body.hits.hits; - return hits.map((item) => item._source); - } } \ No newline at end of file diff --git a/src/posts/types/postSearchResult.interface.ts b/src/posts/types/postSearchResult.interface.ts index 2a720f9..96a9afb 100644 --- a/src/posts/types/postSearchResult.interface.ts +++ b/src/posts/types/postSearchResult.interface.ts @@ -1,3 +1,4 @@ +import {PostSearchBody} from "./postSearchBody.interface"; export interface PostSearchResult { hits: {