mirror of
https://github.com/hknsh/project-knedita.git
synced 2024-12-01 02:41:17 +00:00
feat: improved queries, removed unnecessary imports
This commit is contained in:
parent
e1b244e92b
commit
8e7be25088
9 changed files with 123 additions and 110 deletions
|
@ -65,6 +65,7 @@ This back-end uses the following stack:
|
||||||
- **NestJS**
|
- **NestJS**
|
||||||
- **Fastify**
|
- **Fastify**
|
||||||
- **Prisma**
|
- **Prisma**
|
||||||
|
- **Kysely**
|
||||||
- **MinIO**
|
- **MinIO**
|
||||||
- **PostgreSQL**
|
- **PostgreSQL**
|
||||||
- **Redis**
|
- **Redis**
|
||||||
|
|
|
@ -5,18 +5,15 @@ import {
|
||||||
NotFoundException,
|
NotFoundException,
|
||||||
UnauthorizedException,
|
UnauthorizedException,
|
||||||
} from "@nestjs/common";
|
} from "@nestjs/common";
|
||||||
import { PrismaService } from "src/services/prisma/prisma.service";
|
|
||||||
import { S3Service } from "src/services/s3/s3.service";
|
import { S3Service } from "src/services/s3/s3.service";
|
||||||
import { CommentsRepository } from "./repository/comments.repository";
|
import { CommentsRepository } from "./repository/comments.repository";
|
||||||
import { KweeksRepository } from "./repository/kweeks.repository";
|
import { KweeksRepository } from "./repository/kweeks.repository";
|
||||||
import { selectCommentsWithReplies } from "./schemas/prisma_queries.schema";
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CommentsService {
|
export class CommentsService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly commentsRepository: CommentsRepository,
|
private readonly commentsRepository: CommentsRepository,
|
||||||
private readonly kweeksRepository: KweeksRepository,
|
private readonly kweeksRepository: KweeksRepository,
|
||||||
private readonly prisma: PrismaService,
|
|
||||||
private readonly s3: S3Service,
|
private readonly s3: S3Service,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
@ -33,12 +30,15 @@ export class CommentsService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifies if the kweek_id is a kweek or a comment
|
// 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;
|
let kweek = undefined;
|
||||||
|
|
||||||
if (parentComment === undefined) {
|
if (parentComment === undefined) {
|
||||||
kweek = await this.kweeksRepository.findOne(kweek_id);
|
kweek = await this.kweeksRepository.findOne(kweek_id, false);
|
||||||
|
|
||||||
if (kweek === undefined) {
|
if (kweek === undefined) {
|
||||||
throw new NotFoundException("Kweek/Comment not found");
|
throw new NotFoundException("Kweek/Comment not found");
|
||||||
|
@ -60,30 +60,21 @@ export class CommentsService {
|
||||||
|
|
||||||
await this.commentsRepository.addAttachments(id, attachments);
|
await this.commentsRepository.addAttachments(id, attachments);
|
||||||
|
|
||||||
return await this.commentsRepository.findOne(id);
|
return await this.commentsRepository.findOne(id, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async info(comment_id: string) {
|
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) {
|
if (comment === undefined) {
|
||||||
throw new NotFoundException("Comment not found");
|
throw new NotFoundException("Comment not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const likes = await this.commentsRepository.countLikes(comment.id);
|
return comment;
|
||||||
const comments = await this.commentsRepository.countComments(comment.id);
|
|
||||||
|
|
||||||
return {
|
|
||||||
...comment,
|
|
||||||
count: {
|
|
||||||
likes,
|
|
||||||
comments,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(comment_id: string, user_id: string, content: string) {
|
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) {
|
if (comment === undefined) {
|
||||||
throw new NotFoundException("Comment not found");
|
throw new NotFoundException("Comment not found");
|
||||||
|
@ -100,7 +91,7 @@ export class CommentsService {
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(comment_id: string, user_id: string) {
|
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) {
|
if (comment === undefined) {
|
||||||
throw new NotFoundException("Comment not found");
|
throw new NotFoundException("Comment not found");
|
||||||
|
@ -118,7 +109,7 @@ export class CommentsService {
|
||||||
}
|
}
|
||||||
|
|
||||||
async like(comment_id: string, user_id: string) {
|
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) {
|
if (comment === undefined) {
|
||||||
throw new NotFoundException("Comment not found");
|
throw new NotFoundException("Comment not found");
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { Module } from "@nestjs/common";
|
import { Module } from "@nestjs/common";
|
||||||
import { PrismaService } from "src/services/prisma/prisma.service";
|
|
||||||
import { S3Service } from "src/services/s3/s3.service";
|
import { S3Service } from "src/services/s3/s3.service";
|
||||||
import { UsersRepository } from "src/users/repository/users.repository";
|
import { UsersRepository } from "src/users/repository/users.repository";
|
||||||
import { CommentsController } from "./comments.controller";
|
import { CommentsController } from "./comments.controller";
|
||||||
|
@ -12,7 +11,6 @@ import { KweeksRepository } from "./repository/kweeks.repository";
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [KweeksController, CommentsController],
|
controllers: [KweeksController, CommentsController],
|
||||||
providers: [
|
providers: [
|
||||||
PrismaService,
|
|
||||||
KweeksService,
|
KweeksService,
|
||||||
S3Service,
|
S3Service,
|
||||||
CommentsService,
|
CommentsService,
|
||||||
|
|
|
@ -31,30 +31,21 @@ export class KweeksService {
|
||||||
|
|
||||||
await this.kweekRepository.addAttachments(id, attachments);
|
await this.kweekRepository.addAttachments(id, attachments);
|
||||||
|
|
||||||
return await this.kweekRepository.findOne(id);
|
return await this.kweekRepository.findOne(id, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async findOne(id: string) {
|
async findOne(id: string) {
|
||||||
const post = await this.kweekRepository.findOne(id);
|
const post = await this.kweekRepository.findOne(id, false);
|
||||||
|
|
||||||
if (post === undefined) {
|
if (post === undefined) {
|
||||||
throw new NotFoundException("Post not found");
|
throw new NotFoundException("Post not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const likes = await this.kweekRepository.countLikes(post.id);
|
return post;
|
||||||
const comments = await this.kweekRepository.countComments(post.id);
|
|
||||||
|
|
||||||
return {
|
|
||||||
...post,
|
|
||||||
count: {
|
|
||||||
likes,
|
|
||||||
comments,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(user_id: string, post_id: string, content: string) {
|
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) {
|
if (post === undefined) {
|
||||||
throw new NotFoundException("Post not found");
|
throw new NotFoundException("Post not found");
|
||||||
|
@ -71,7 +62,7 @@ export class KweeksService {
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(user_id: string, id: string) {
|
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) {
|
if (post === undefined) {
|
||||||
throw new NotFoundException("Post not found");
|
throw new NotFoundException("Post not found");
|
||||||
|
@ -89,7 +80,7 @@ export class KweeksService {
|
||||||
}
|
}
|
||||||
|
|
||||||
async like(user_id: string, kweek_id: string) {
|
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) {
|
if (kweek === undefined) {
|
||||||
throw new NotFoundException("Post not found");
|
throw new NotFoundException("Post not found");
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
import { Injectable } from "@nestjs/common";
|
import { Injectable } from "@nestjs/common";
|
||||||
|
import {
|
||||||
|
jsonArrayFrom,
|
||||||
|
jsonBuildObject,
|
||||||
|
jsonObjectFrom,
|
||||||
|
} from "kysely/helpers/postgres";
|
||||||
import { Database } from "src/services/kysely/kysely.service";
|
import { Database } from "src/services/kysely/kysely.service";
|
||||||
import { v4 as uuid } from "uuid";
|
import { v4 as uuid } from "uuid";
|
||||||
|
|
||||||
|
@ -38,19 +43,57 @@ export class CommentsRepository {
|
||||||
.executeTakeFirst();
|
.executeTakeFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
async findOne(id: string) {
|
async findOne(id: string, withUserId: boolean) {
|
||||||
return await this.database
|
return await this.database
|
||||||
.selectFrom("Comments")
|
.selectFrom("Comments")
|
||||||
.select([
|
.select((eq) => [
|
||||||
"id",
|
"id",
|
||||||
"content",
|
"content",
|
||||||
"attachments",
|
"attachments",
|
||||||
"createdAt",
|
"createdAt",
|
||||||
"userId",
|
|
||||||
"updatedAt",
|
"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<number>().as("likes")),
|
||||||
|
replies: eq
|
||||||
|
.selectFrom("Comments")
|
||||||
|
.where((qb) =>
|
||||||
|
qb("Comments.kweekId", "=", id).or("parentId", "=", id),
|
||||||
|
)
|
||||||
|
.select(eq.fn.countAll<number>().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",
|
"kweekId",
|
||||||
"parentId",
|
"parentId",
|
||||||
])
|
])
|
||||||
|
.where("Comments.parentId", "=", id),
|
||||||
|
).as("replies"),
|
||||||
|
"kweekId",
|
||||||
|
"parentId",
|
||||||
|
])
|
||||||
|
.$if(withUserId, (qb) => qb.select("userId"))
|
||||||
.where("id", "=", id)
|
.where("id", "=", id)
|
||||||
.executeTakeFirst();
|
.executeTakeFirst();
|
||||||
}
|
}
|
||||||
|
@ -94,24 +137,4 @@ export class CommentsRepository {
|
||||||
.returningAll()
|
.returningAll()
|
||||||
.executeTakeFirst();
|
.executeTakeFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
async countLikes(id: string) {
|
|
||||||
const count = await this.database
|
|
||||||
.selectFrom("CommentLike")
|
|
||||||
.where("commentId", "=", id)
|
|
||||||
.select(this.database.fn.countAll<number>().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<number>().as("count"))
|
|
||||||
.executeTakeFirstOrThrow();
|
|
||||||
|
|
||||||
return count.count ?? 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
import { Injectable } from "@nestjs/common";
|
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 { Database } from "src/services/kysely/kysely.service";
|
||||||
import { v4 as uuid } from "uuid";
|
import { v4 as uuid } from "uuid";
|
||||||
|
|
||||||
|
@ -31,10 +37,61 @@ export class KweeksRepository {
|
||||||
.executeTakeFirst();
|
.executeTakeFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
async findOne(id: string) {
|
async findOne(id: string, withUserId: boolean) {
|
||||||
return await this.database
|
return await this.database
|
||||||
.selectFrom("Kweek")
|
.selectFrom("Kweek")
|
||||||
.selectAll()
|
.select((eq) => [
|
||||||
|
"id",
|
||||||
|
"content",
|
||||||
|
"attachments",
|
||||||
|
"createdAt",
|
||||||
|
"updatedAt",
|
||||||
|
jsonBuildObject({
|
||||||
|
likes: eq
|
||||||
|
.selectFrom("KweekLike")
|
||||||
|
.whereRef("kweekId", "=", "Kweek.id")
|
||||||
|
.select(eq.fn.countAll<number>().as("likes")),
|
||||||
|
comments: eq
|
||||||
|
.selectFrom("Comments")
|
||||||
|
.where("kweekId", "=", id)
|
||||||
|
.select(eq.fn.countAll<number>().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<number>().as("likes")),
|
||||||
|
replies: qb
|
||||||
|
.selectFrom("Comments as Reply")
|
||||||
|
.whereRef("Reply.parentId", "=", "Comments.id")
|
||||||
|
.select(qb.fn.countAll<number>().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)
|
.where("id", "=", id)
|
||||||
.executeTakeFirst();
|
.executeTakeFirst();
|
||||||
}
|
}
|
||||||
|
@ -78,22 +135,4 @@ export class KweeksRepository {
|
||||||
.returningAll()
|
.returningAll()
|
||||||
.executeTakeFirst();
|
.executeTakeFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
async countLikes(id: string) {
|
|
||||||
const count = await this.database
|
|
||||||
.selectFrom("KweekLike")
|
|
||||||
.where("kweekId", "=", id)
|
|
||||||
.select(this.database.fn.countAll<number>().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<number>().as("count"))
|
|
||||||
.executeTakeFirstOrThrow();
|
|
||||||
return count.count ?? 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,15 +12,11 @@ import { Configuration } from "./configuration";
|
||||||
/*
|
/*
|
||||||
--- Present ---
|
--- 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: Add a authorization system.
|
||||||
TODO: Send e-mails to the user when something happens to his account.
|
TODO: Send e-mails to the user when something happens to his account.
|
||||||
TODO: Create the chat system.
|
TODO: Create the chat system.
|
||||||
-> Initialize the websocket system first.
|
-> Initialize the websocket system first.
|
||||||
TODO: Create a TOS.
|
TODO: Create a TOS.
|
||||||
TODO: Improve Kysely Queries.
|
|
||||||
TODO: Fix Docker Image.
|
TODO: Fix Docker Image.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
import { Module } from "@nestjs/common";
|
|
||||||
import { PrismaService } from "./prisma.service";
|
|
||||||
|
|
||||||
@Module({
|
|
||||||
providers: [PrismaService],
|
|
||||||
exports: [PrismaService],
|
|
||||||
})
|
|
||||||
export class PrismaModule {}
|
|
|
@ -1,18 +0,0 @@
|
||||||
import { INestApplication, Injectable, OnModuleInit } from "@nestjs/common";
|
|
||||||
import { Prisma, PrismaClient } from "@prisma/client";
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class PrismaService
|
|
||||||
extends PrismaClient<Prisma.PrismaClientOptions, "beforeExit">
|
|
||||||
implements OnModuleInit
|
|
||||||
{
|
|
||||||
async onModuleInit() {
|
|
||||||
await this.$connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
async enableShutdownHooks(app: INestApplication) {
|
|
||||||
this.$on("beforeExit", async () => {
|
|
||||||
await app.close();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue