diff --git a/apps/api/prisma/schema.prisma b/apps/api/prisma/schema.prisma index 0fef314..e6fb5ea 100644 --- a/apps/api/prisma/schema.prisma +++ b/apps/api/prisma/schema.prisma @@ -5,7 +5,8 @@ // Try Prisma Accelerate: https://pris.ly/cli/accelerate-init generator client { - provider = "prisma-client-js" + provider = "prisma-client-js" + previewFeatures = ["fullTextSearch"] } datasource db { diff --git a/apps/api/src/app.ts b/apps/api/src/app.ts index 06870b8..922d4b7 100644 --- a/apps/api/src/app.ts +++ b/apps/api/src/app.ts @@ -9,7 +9,7 @@ import { errorHandler } from "./middleware/errorHandler"; import config from "./config/config"; import { xssMiddleware } from "./middleware/xssMiddleware"; import { createServer } from "http"; -import { streamRouter, userRouter } from "./routes"; +import { searchRouter, streamRouter, userRouter } from "./routes"; import { Server } from "socket.io"; import logger from "./middleware/logger"; import { @@ -132,6 +132,8 @@ app.use("/api/user", userRouter); app.use("/api/stream", streamRouter); +app.use("/api/search", searchRouter); + io.use(async (socket, next) => { const { token } = socket.handshake.auth; diff --git a/apps/api/src/controller/index.ts b/apps/api/src/controller/index.ts index d34b33a..dd76b4b 100644 --- a/apps/api/src/controller/index.ts +++ b/apps/api/src/controller/index.ts @@ -1,4 +1,5 @@ import * as userController from "./user.controller"; import * as streamController from "./stream.controller"; +import * as searchController from "./search.controller"; -export { userController, streamController }; +export { userController, streamController, searchController }; diff --git a/apps/api/src/controller/search.controller.ts b/apps/api/src/controller/search.controller.ts new file mode 100644 index 0000000..d88657a --- /dev/null +++ b/apps/api/src/controller/search.controller.ts @@ -0,0 +1,119 @@ +import type { Request, Response } from "express"; +import httpStatus from "http-status"; +import prismaClient from "../config/prisma"; +import { User } from "@prisma/client"; +import { TypedResponse } from "../types/types"; +import { createErrorObject } from "../utils/createErrorObject"; + +export const search = async ( + req: Request< + object, + unknown, + unknown, + { + query: string; + courser: string; + limit: string; + } + >, + res: Response< + TypedResponse<{ + result: { + users: Pick< + User, + "id" | "username" | "dispname" | "avatar_url" | "followerCount" + >[]; + }; + nextCursor: string; + hasNext: boolean; + }> + > +) => { + const { query, courser, limit } = req.query; + + if (!query || !limit) { + return res.status(httpStatus.BAD_REQUEST).json({ + success: false, + data: null, + error: [ + ...createErrorObject( + httpStatus.BAD_REQUEST, + "query and limit must be defined" + ) + ] + }); + } + + // prisma query + const userData = await prismaClient.user.findMany({ + take: 30, + ...(courser && { + skip: 1, // Do not include the cursor itself in the query result. + cursor: { + id: courser + } + }), + where: { + OR: [ + { + dispname: { + search: query + } + }, + { + username: { + search: query + } + } + ] + }, + select: { + id: true, + username: true, + dispname: true, + avatar_url: true, + followerCount: true + } + }); + + const next = await prismaClient.user.findMany({ + take: 30, + + skip: 1, + cursor: { + id: courser + }, + + where: { + OR: [ + { + dispname: { + search: query + } + }, + { + username: { + search: query + } + } + ] + }, + select: { + id: true + } + }); + + return res.status(httpStatus.OK).json({ + success: true, + data: { + result: { + users: userData + }, + nextCursor: userData.at(-1)?.id ?? "", + hasNext: next.length > 0 + }, + error: [] + }); + + // return +}; diff --git a/apps/api/src/routes/index.ts b/apps/api/src/routes/index.ts index 3d8f827..4b2cd37 100644 --- a/apps/api/src/routes/index.ts +++ b/apps/api/src/routes/index.ts @@ -1,4 +1,5 @@ import userRouter from "./user.route"; import streamRouter from "./stream.route"; +import searchRouter from "./search.route"; -export { userRouter, streamRouter }; +export { userRouter, streamRouter, searchRouter }; diff --git a/apps/api/src/routes/search.route.ts b/apps/api/src/routes/search.route.ts new file mode 100644 index 0000000..c06215c --- /dev/null +++ b/apps/api/src/routes/search.route.ts @@ -0,0 +1,8 @@ +import { Router } from "express"; +import { searchController } from "src/controller"; + +const searchRouter = Router(); + +searchRouter.get("/", searchController.search); + +export default searchRouter;