mirror of
https://github.com/yangshun/tech-interview-handbook.git
synced 2025-07-28 12:43:12 +08:00
[questions][feat] add encounters transaction for crud (#409)
* [questions][chore] refactor question queries * [questions][chore] destructure values from input * [questions][feat] add sorting * [question][fix] fix frontend * [questions][feat] add sorting * [questions][feat] add sorting index * [questions][chore] push migration file * [questions][fix] fix ci issues * [questions][fix] fix import errors * [questions][feat] add encounters transaction for crud * [questions][chore] fix import * [questions][chore] update error handling * [questions][feat] parallelize queries * [questions][fix] update to use corrcet client * Update questions-question-encounter-router.ts * Update questions-question-encounter-router.ts Co-authored-by: Jeff Sieu <jeffsy00@gmail.com>
This commit is contained in:
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "QuestionsQuestion" ALTER COLUMN "lastSeenAt" DROP NOT NULL;
|
@ -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("contentSearch");
|
@ -0,0 +1,8 @@
|
|||||||
|
-- DropIndex
|
||||||
|
DROP INDEX "QuestionsQuestion_contentSearch_idx";
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "QuestionsQuestion" ALTER COLUMN "contentSearch" DROP DEFAULT;
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "QuestionsQuestion_contentSearch_idx" ON "QuestionsQuestion"("contentSearch");
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
generator client {
|
generator client {
|
||||||
provider = "prisma-client-js"
|
provider = "prisma-client-js"
|
||||||
|
previewFeatures = ["interactiveTransactions"]
|
||||||
}
|
}
|
||||||
|
|
||||||
datasource db {
|
datasource db {
|
||||||
@ -402,7 +403,7 @@ model QuestionsQuestion {
|
|||||||
userId String?
|
userId String?
|
||||||
content String @db.Text
|
content String @db.Text
|
||||||
questionType QuestionsQuestionType
|
questionType QuestionsQuestionType
|
||||||
lastSeenAt DateTime
|
lastSeenAt DateTime?
|
||||||
upvotes Int @default(0)
|
upvotes Int @default(0)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
@ -4,6 +4,8 @@ import { TRPCError } from '@trpc/server';
|
|||||||
import { createProtectedRouter } from './context';
|
import { createProtectedRouter } from './context';
|
||||||
|
|
||||||
import type { AggregatedQuestionEncounter } from '~/types/questions';
|
import type { AggregatedQuestionEncounter } from '~/types/questions';
|
||||||
|
import { SortOrder } from '~/types/questions.d';
|
||||||
|
|
||||||
|
|
||||||
export const questionsQuestionEncounterRouter = createProtectedRouter()
|
export const questionsQuestionEncounterRouter = createProtectedRouter()
|
||||||
.query('getAggregatedEncounters', {
|
.query('getAggregatedEncounters', {
|
||||||
@ -68,11 +70,40 @@ export const questionsQuestionEncounterRouter = createProtectedRouter()
|
|||||||
async resolve({ ctx, input }) {
|
async resolve({ ctx, input }) {
|
||||||
const userId = ctx.session?.user?.id;
|
const userId = ctx.session?.user?.id;
|
||||||
|
|
||||||
return await ctx.prisma.questionsQuestionEncounter.create({
|
return await ctx.prisma.$transaction(async (tx) => {
|
||||||
|
const [questionToUpdate, questionEncounterCreated] = await Promise.all([
|
||||||
|
tx.questionsQuestion.findUnique({
|
||||||
|
where: {
|
||||||
|
id: input.questionId,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
tx.questionsQuestionEncounter.create({
|
||||||
data: {
|
data: {
|
||||||
...input,
|
...input,
|
||||||
userId,
|
userId,
|
||||||
},
|
},
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
if (questionToUpdate === null) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: 'BAD_REQUEST',
|
||||||
|
message: 'Question does not exist',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!questionToUpdate.lastSeenAt || questionToUpdate.lastSeenAt < input.seenAt) {
|
||||||
|
await tx.questionsQuestion.update({
|
||||||
|
data: {
|
||||||
|
lastSeenAt : input.seenAt,
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
id: input.questionId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return questionEncounterCreated;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -101,14 +132,48 @@ export const questionsQuestionEncounterRouter = createProtectedRouter()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return await ctx.prisma.questionsQuestionEncounter.update({
|
return await ctx.prisma.$transaction(async (tx) => {
|
||||||
|
const [questionToUpdate, questionEncounterUpdated] = await Promise.all([
|
||||||
|
tx.questionsQuestion.findUnique({
|
||||||
|
where: {
|
||||||
|
id: questionEncounterToUpdate.questionId,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
tx.questionsQuestionEncounter.update({
|
||||||
data: {
|
data: {
|
||||||
...input,
|
...input,
|
||||||
},
|
},
|
||||||
where: {
|
where: {
|
||||||
id: input.id,
|
id: input.id,
|
||||||
},
|
},
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
if (questionToUpdate!.lastSeenAt === questionEncounterToUpdate.seenAt) {
|
||||||
|
const latestEncounter = await ctx.prisma.questionsQuestionEncounter.findFirst({
|
||||||
|
orderBy: {
|
||||||
|
seenAt: SortOrder.DESC,
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
questionId: questionToUpdate!.id,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await tx.questionsQuestion.update({
|
||||||
|
data: {
|
||||||
|
lastSeenAt : latestEncounter!.seenAt,
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
id: questionToUpdate!.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return questionEncounterUpdated;
|
||||||
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.mutation('delete', {
|
.mutation('delete', {
|
||||||
@ -132,10 +197,43 @@ export const questionsQuestionEncounterRouter = createProtectedRouter()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return await ctx.prisma.questionsQuestionEncounter.delete({
|
return await ctx.prisma.$transaction(async (tx) => {
|
||||||
|
const [questionToUpdate, questionEncounterDeleted] = await Promise.all([
|
||||||
|
tx.questionsQuestion.findUnique({
|
||||||
|
where: {
|
||||||
|
id: questionEncounterToDelete.questionId,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
tx.questionsQuestionEncounter.delete({
|
||||||
where: {
|
where: {
|
||||||
id: input.id,
|
id: input.id,
|
||||||
},
|
},
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (questionToUpdate!.lastSeenAt === questionEncounterToDelete.seenAt) {
|
||||||
|
const latestEncounter = await ctx.prisma.questionsQuestionEncounter.findFirst({
|
||||||
|
orderBy: {
|
||||||
|
seenAt: SortOrder.DESC,
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
questionId: questionToUpdate!.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const lastSeenVal = latestEncounter ? latestEncounter!.seenAt : null;
|
||||||
|
|
||||||
|
await tx.questionsQuestion.update({
|
||||||
|
data: {
|
||||||
|
lastSeenAt : lastSeenVal,
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
id: questionToUpdate!.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return questionEncounterDeleted;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user