From 8e7be25088f97c63917c5f4a25cb66f2cacf8700 Mon Sep 17 00:00:00 2001 From: hknsh Date: Fri, 25 Oct 2024 00:11:08 +0100 Subject: [PATCH] feat: improved queries, removed unnecessary imports --- README.md | 1 + src/kweeks/comments.service.ts | 31 +++----- src/kweeks/kweeks.module.ts | 2 - src/kweeks/kweeks.service.ts | 21 ++---- src/kweeks/repository/comments.repository.ts | 69 +++++++++++------ src/kweeks/repository/kweeks.repository.ts | 79 +++++++++++++++----- src/main.ts | 4 - src/services/prisma/prisma.module.ts | 8 -- src/services/prisma/prisma.service.ts | 18 ----- 9 files changed, 123 insertions(+), 110 deletions(-) delete mode 100644 src/services/prisma/prisma.module.ts delete mode 100644 src/services/prisma/prisma.service.ts diff --git a/README.md b/README.md index 26bbe2c..b84cc80 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ This back-end uses the following stack: - **NestJS** - **Fastify** - **Prisma** +- **Kysely** - **MinIO** - **PostgreSQL** - **Redis** diff --git a/src/kweeks/comments.service.ts b/src/kweeks/comments.service.ts index c7eb03f..ae0d62d 100644 --- a/src/kweeks/comments.service.ts +++ b/src/kweeks/comments.service.ts @@ -5,18 +5,15 @@ import { NotFoundException, UnauthorizedException, } from "@nestjs/common"; -import { PrismaService } from "src/services/prisma/prisma.service"; import { S3Service } from "src/services/s3/s3.service"; import { CommentsRepository } from "./repository/comments.repository"; import { KweeksRepository } from "./repository/kweeks.repository"; -import { selectCommentsWithReplies } from "./schemas/prisma_queries.schema"; @Injectable() export class CommentsService { constructor( private readonly commentsRepository: CommentsRepository, private readonly kweeksRepository: KweeksRepository, - private readonly prisma: PrismaService, private readonly s3: S3Service, ) {} @@ -33,12 +30,15 @@ export class CommentsService { } // Verifies if the kweek_id is a kweek or a comment - const parentComment = await this.commentsRepository.findOne(kweek_id); + const parentComment = await this.commentsRepository.findOne( + kweek_id, + false, + ); let kweek = undefined; if (parentComment === undefined) { - kweek = await this.kweeksRepository.findOne(kweek_id); + kweek = await this.kweeksRepository.findOne(kweek_id, false); if (kweek === undefined) { throw new NotFoundException("Kweek/Comment not found"); @@ -60,30 +60,21 @@ export class CommentsService { await this.commentsRepository.addAttachments(id, attachments); - return await this.commentsRepository.findOne(id); + return await this.commentsRepository.findOne(id, false); } async info(comment_id: string) { - const comment = await this.commentsRepository.findOne(comment_id); + const comment = await this.commentsRepository.findOne(comment_id, false); if (comment === undefined) { throw new NotFoundException("Comment not found"); } - const likes = await this.commentsRepository.countLikes(comment.id); - const comments = await this.commentsRepository.countComments(comment.id); - - return { - ...comment, - count: { - likes, - comments, - }, - }; + return comment; } async update(comment_id: string, user_id: string, content: string) { - const comment = await this.commentsRepository.findOne(comment_id); + const comment = await this.commentsRepository.findOne(comment_id, true); if (comment === undefined) { throw new NotFoundException("Comment not found"); @@ -100,7 +91,7 @@ export class CommentsService { } async delete(comment_id: string, user_id: string) { - const comment = await this.commentsRepository.findOne(comment_id); + const comment = await this.commentsRepository.findOne(comment_id, true); if (comment === undefined) { throw new NotFoundException("Comment not found"); @@ -118,7 +109,7 @@ export class CommentsService { } async like(comment_id: string, user_id: string) { - const comment = await this.commentsRepository.findOne(comment_id); + const comment = await this.commentsRepository.findOne(comment_id, true); if (comment === undefined) { throw new NotFoundException("Comment not found"); diff --git a/src/kweeks/kweeks.module.ts b/src/kweeks/kweeks.module.ts index 4e54662..9f4d8d7 100644 --- a/src/kweeks/kweeks.module.ts +++ b/src/kweeks/kweeks.module.ts @@ -1,5 +1,4 @@ import { Module } from "@nestjs/common"; -import { PrismaService } from "src/services/prisma/prisma.service"; import { S3Service } from "src/services/s3/s3.service"; import { UsersRepository } from "src/users/repository/users.repository"; import { CommentsController } from "./comments.controller"; @@ -12,7 +11,6 @@ import { KweeksRepository } from "./repository/kweeks.repository"; @Module({ controllers: [KweeksController, CommentsController], providers: [ - PrismaService, KweeksService, S3Service, CommentsService, diff --git a/src/kweeks/kweeks.service.ts b/src/kweeks/kweeks.service.ts index 87e7f47..947e256 100644 --- a/src/kweeks/kweeks.service.ts +++ b/src/kweeks/kweeks.service.ts @@ -31,30 +31,21 @@ export class KweeksService { await this.kweekRepository.addAttachments(id, attachments); - return await this.kweekRepository.findOne(id); + return await this.kweekRepository.findOne(id, false); } async findOne(id: string) { - const post = await this.kweekRepository.findOne(id); + const post = await this.kweekRepository.findOne(id, false); if (post === undefined) { throw new NotFoundException("Post not found"); } - const likes = await this.kweekRepository.countLikes(post.id); - const comments = await this.kweekRepository.countComments(post.id); - - return { - ...post, - count: { - likes, - comments, - }, - }; + return post; } async update(user_id: string, post_id: string, content: string) { - const post = await this.kweekRepository.findOne(post_id); + const post = await this.kweekRepository.findOne(post_id, true); if (post === undefined) { throw new NotFoundException("Post not found"); @@ -71,7 +62,7 @@ export class KweeksService { } async remove(user_id: string, id: string) { - const post = await this.kweekRepository.findOne(id); + const post = await this.kweekRepository.findOne(id, true); if (post === undefined) { throw new NotFoundException("Post not found"); @@ -89,7 +80,7 @@ export class KweeksService { } async like(user_id: string, kweek_id: string) { - const kweek = await this.kweekRepository.findOne(kweek_id); + const kweek = await this.kweekRepository.findOne(kweek_id, true); if (kweek === undefined) { throw new NotFoundException("Post not found"); diff --git a/src/kweeks/repository/comments.repository.ts b/src/kweeks/repository/comments.repository.ts index 6cb6bd7..8a24d68 100644 --- a/src/kweeks/repository/comments.repository.ts +++ b/src/kweeks/repository/comments.repository.ts @@ -1,4 +1,9 @@ import { Injectable } from "@nestjs/common"; +import { + jsonArrayFrom, + jsonBuildObject, + jsonObjectFrom, +} from "kysely/helpers/postgres"; import { Database } from "src/services/kysely/kysely.service"; import { v4 as uuid } from "uuid"; @@ -38,19 +43,57 @@ export class CommentsRepository { .executeTakeFirst(); } - async findOne(id: string) { + async findOne(id: string, withUserId: boolean) { return await this.database .selectFrom("Comments") - .select([ + .select((eq) => [ "id", "content", "attachments", "createdAt", - "userId", "updatedAt", + jsonObjectFrom( + eq + .selectFrom("User") + .select(["displayName", "username", "profileImage"]) + .whereRef("id", "=", "Comments.userId"), + ).as("author"), + jsonBuildObject({ + likes: eq + .selectFrom("CommentLike") + .whereRef("commentId", "=", "Comments.id") + .select(eq.fn.countAll().as("likes")), + replies: eq + .selectFrom("Comments") + .where((qb) => + qb("Comments.kweekId", "=", id).or("parentId", "=", id), + ) + .select(eq.fn.countAll().as("replies")), + }).as("count"), + jsonArrayFrom( + eq + .selectFrom("Comments") + .select((qb) => [ + "id", + "content", + "attachments", + "createdAt", + "updatedAt", + jsonObjectFrom( + qb + .selectFrom("User") + .select(["displayName", "username", "profileImage"]) + .whereRef("id", "=", "Comments.userId"), + ).as("author"), + "kweekId", + "parentId", + ]) + .where("Comments.parentId", "=", id), + ).as("replies"), "kweekId", "parentId", ]) + .$if(withUserId, (qb) => qb.select("userId")) .where("id", "=", id) .executeTakeFirst(); } @@ -94,24 +137,4 @@ export class CommentsRepository { .returningAll() .executeTakeFirst(); } - - async countLikes(id: string) { - const count = await this.database - .selectFrom("CommentLike") - .where("commentId", "=", id) - .select(this.database.fn.countAll().as("count")) - .executeTakeFirstOrThrow(); - - return count.count ?? 0; - } - - async countComments(id: string) { - const count = await this.database - .selectFrom("Comments") - .where((qb) => qb("kweekId", "=", id).or("parentId", "=", id)) - .select(this.database.fn.countAll().as("count")) - .executeTakeFirstOrThrow(); - - return count.count ?? 0; - } } diff --git a/src/kweeks/repository/kweeks.repository.ts b/src/kweeks/repository/kweeks.repository.ts index 31cd276..7a8e281 100644 --- a/src/kweeks/repository/kweeks.repository.ts +++ b/src/kweeks/repository/kweeks.repository.ts @@ -1,4 +1,10 @@ import { Injectable } from "@nestjs/common"; +import { Expression } from "kysely"; +import { + jsonArrayFrom, + jsonBuildObject, + jsonObjectFrom, +} from "kysely/helpers/postgres"; import { Database } from "src/services/kysely/kysely.service"; import { v4 as uuid } from "uuid"; @@ -31,10 +37,61 @@ export class KweeksRepository { .executeTakeFirst(); } - async findOne(id: string) { + async findOne(id: string, withUserId: boolean) { return await this.database .selectFrom("Kweek") - .selectAll() + .select((eq) => [ + "id", + "content", + "attachments", + "createdAt", + "updatedAt", + jsonBuildObject({ + likes: eq + .selectFrom("KweekLike") + .whereRef("kweekId", "=", "Kweek.id") + .select(eq.fn.countAll().as("likes")), + comments: eq + .selectFrom("Comments") + .where("kweekId", "=", id) + .select(eq.fn.countAll().as("comments")), + }).as("count"), + jsonObjectFrom( + eq + .selectFrom("User") + .select(["displayName", "username", "profileImage"]) + .whereRef("id", "=", "authorId"), + ).as("author"), + jsonArrayFrom( + eq + .selectFrom("Comments") + .select((qb) => [ + "id", + "content", + "attachments", + "createdAt", + "updatedAt", + jsonBuildObject({ + likes: qb + .selectFrom("CommentLike") + .whereRef("commentId", "=", "Comments.id") + .select(qb.fn.countAll().as("likes")), + replies: qb + .selectFrom("Comments as Reply") + .whereRef("Reply.parentId", "=", "Comments.id") + .select(qb.fn.countAll().as("replies")), + }).as("count"), + jsonObjectFrom( + qb + .selectFrom("User") + .select(["displayName", "username", "profileImage"]) + .whereRef("id", "=", "Comments.userId"), + ).as("author"), + ]) + .whereRef("Comments.kweekId", "=", "Kweek.id"), + ).as("comments"), + ]) + .$if(withUserId, (qb) => qb.select("authorId")) .where("id", "=", id) .executeTakeFirst(); } @@ -78,22 +135,4 @@ export class KweeksRepository { .returningAll() .executeTakeFirst(); } - - async countLikes(id: string) { - const count = await this.database - .selectFrom("KweekLike") - .where("kweekId", "=", id) - .select(this.database.fn.countAll().as("count")) - .executeTakeFirstOrThrow(); - return count.count ?? 0; - } - - async countComments(id: string) { - const count = await this.database - .selectFrom("Comments") - .where("kweekId", "=", id) - .select(this.database.fn.countAll().as("count")) - .executeTakeFirstOrThrow(); - return count.count ?? 0; - } } diff --git a/src/main.ts b/src/main.ts index 7549bed..5258f5a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -12,15 +12,11 @@ import { Configuration } from "./configuration"; /* --- Present --- - TODO: Finish some routes. - -> Delete User service needs more protection. - TODO: Add `user` type to @nestjs/common ---> Request. TODO: Add a authorization system. TODO: Send e-mails to the user when something happens to his account. TODO: Create the chat system. -> Initialize the websocket system first. TODO: Create a TOS. - TODO: Improve Kysely Queries. TODO: Fix Docker Image. */ diff --git a/src/services/prisma/prisma.module.ts b/src/services/prisma/prisma.module.ts deleted file mode 100644 index e3bfba9..0000000 --- a/src/services/prisma/prisma.module.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Module } from "@nestjs/common"; -import { PrismaService } from "./prisma.service"; - -@Module({ - providers: [PrismaService], - exports: [PrismaService], -}) -export class PrismaModule {} diff --git a/src/services/prisma/prisma.service.ts b/src/services/prisma/prisma.service.ts deleted file mode 100644 index c2cfd4d..0000000 --- a/src/services/prisma/prisma.service.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { INestApplication, Injectable, OnModuleInit } from "@nestjs/common"; -import { Prisma, PrismaClient } from "@prisma/client"; - -@Injectable() -export class PrismaService - extends PrismaClient - implements OnModuleInit -{ - async onModuleInit() { - await this.$connect(); - } - - async enableShutdownHooks(app: INestApplication) { - this.$on("beforeExit", async () => { - await app.close(); - }); - } -}