From f70caba3f20e4d224e6e86aad9b05b66375d8aa3 Mon Sep 17 00:00:00 2001 From: hpkoh <53825802+hpkoh@users.noreply.github.com> Date: Tue, 25 Oct 2022 01:22:05 +0800 Subject: [PATCH] [questions][feat] add text search (#412) --- .../migration.sql | 8 ++++++ apps/portal/prisma/schema.prisma | 3 +++ .../router/questions-question-router.ts | 27 ++++++++++++++++++- 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 apps/portal/prisma/migrations/20221014105030_add_question_content_search/migration.sql diff --git a/apps/portal/prisma/migrations/20221014105030_add_question_content_search/migration.sql b/apps/portal/prisma/migrations/20221014105030_add_question_content_search/migration.sql new file mode 100644 index 00000000..2aed7085 --- /dev/null +++ b/apps/portal/prisma/migrations/20221014105030_add_question_content_search/migration.sql @@ -0,0 +1,8 @@ +-- AlterTable +ALTER TABLE "QuestionsQuestion" ADD COLUMN "contentSearch" TSVECTOR + GENERATED ALWAYS AS + to_tsvector('english', coalesce(content, '')) + STORED; + +-- CreateIndex +CREATE INDEX "QuestionsQuestion_contentSearch_idx" ON "QuestionsQuestion" USING GIN("textSearch"); \ No newline at end of file diff --git a/apps/portal/prisma/schema.prisma b/apps/portal/prisma/schema.prisma index c3902fe0..f6bde90e 100644 --- a/apps/portal/prisma/schema.prisma +++ b/apps/portal/prisma/schema.prisma @@ -414,6 +414,9 @@ model QuestionsQuestion { answers QuestionsAnswer[] QuestionsListQuestionEntry QuestionsListQuestionEntry[] + contentSearch Unsupported("TSVECTOR")? + + @@index([contentSearch]) @@index([lastSeenAt, id]) @@index([upvotes, id]) } diff --git a/apps/portal/src/server/router/questions-question-router.ts b/apps/portal/src/server/router/questions-question-router.ts index 3ea33bce..b3e2ecbd 100644 --- a/apps/portal/src/server/router/questions-question-router.ts +++ b/apps/portal/src/server/router/questions-question-router.ts @@ -316,6 +316,31 @@ export const questionsQuestionRouter = createProtectedRouter() return question; }, }) + .query('getRelatedQuestionsByContent', { + input: z.object({ + content: z.string(), + }), + async resolve({ ctx, input }) { + const escapeChars = /[()|&:*!]/g; + + const query = + input.content + .replace(escapeChars, " ") + .trim() + .split(/\s+/) + .join(" | "); + + const relatedQuestions = await ctx.prisma.$queryRaw` + SELECT * FROM "QuestionsQuestion" + WHERE + "contentSearch" @@ to_tsquery('english', ${query}) + ORDER BY ts_rank("textSearch", to_tsquery('english', ${query})) DESC + `; + + return relatedQuestions; + } + + }) .mutation('create', { input: z.object({ companyId: z.string(), @@ -537,7 +562,7 @@ export const questionsQuestionRouter = createProtectedRouter() const incrementValue = voteToDelete.vote === Vote.UPVOTE ? -1 : 1; - const [questionVote] = await ctx.prisma.$transaction([ + const [ questionVote ] = await ctx.prisma.$transaction([ ctx.prisma.questionsQuestionVote.delete({ where: { id: input.id,