diff --git a/packages/api/src/router/test.ts b/packages/api/src/router/test.ts index cef204e..1b08839 100644 --- a/packages/api/src/router/test.ts +++ b/packages/api/src/router/test.ts @@ -5,11 +5,11 @@ import { playersHighscoreSchema } from "@acme/schema/src/play"; import { TRPCError } from "@trpc/server"; import { Prisma } from "@acme/db"; -import type { PlayersHighscore } from "@acme/schema/src/types"; import { deleteTestFromAlgolia, updateTestInAlgolia, } from "../services/algoliaApiHandlers/algoliaCudHandlers"; +import type { _PlayersHighscore } from "../types"; type QuestionCreateInput = Prisma.QuestionCreateInput; @@ -857,33 +857,44 @@ export const testRouter = router({ const { testId } = input; const playsWithHighestScore = await ctx.prisma - .$queryRaw(Prisma.sql` - SELECT - DISTINCT ON ("Play"."playerId") - "User"."firstName", - "User"."imageUrl", - "Play"."playerId" AS "id", - "Play"."createdAt", - MAX("Play"."score") AS "highScore" - FROM - "Play" - JOIN - "User" - ON - "Play"."playerId" = "User"."userId" - WHERE - "Play"."isFinished" = TRUE - AND "Play"."testId" = ${testId} - GROUP BY - "Play"."playerId", - "Play"."createdAt", - "User"."firstName", - "User"."imageUrl" - ORDER BY - "Play"."playerId", - "highScore" DESC, - "Play"."createdAt" ASC; - `); + .$queryRaw<_PlayersHighscore[]>( + Prisma.sql` + SELECT + DISTINCT ON ("play"."player_id") + "user"."user_first_name", + "user"."user_image_url", + "play"."player_id" AS "id", + "play"."play_created_at", + MAX("play"."play_score") AS "high_score" + FROM + "play" + JOIN + "user" + ON + "play"."player_id" = "user"."clerk_user_id" + WHERE + "play"."play_is_finished" = TRUE + AND "play"."test_id" = ${testId} + GROUP BY + "play"."player_id", + "play"."play_created_at", + "user"."user_first_name", + "user"."user_image_url" + ORDER BY + "play"."player_id", + "high_score" DESC, + "play"."play_created_at" ASC; + `, + ) + .then((plays) => + plays.map((play) => ({ + id: play.id, + createdAt: play.play_created_at, + highScore: play.high_score, + firstName: play.user_first_name, + imageUrl: play.user_image_url, + })), + ); const sortedPlays = playsWithHighestScore.sort((a, b) => { return b.highScore - a.highScore; diff --git a/packages/api/src/router/tests/testQueries.test.ts b/packages/api/src/router/tests/testQueries.test.ts index 2d74fc6..7245eb5 100644 --- a/packages/api/src/router/tests/testQueries.test.ts +++ b/packages/api/src/router/tests/testQueries.test.ts @@ -203,25 +203,25 @@ describe("testRouter - queries", () => { beforeEach(async () => { ctx.prisma.$queryRaw = vi.fn().mockResolvedValue([ { - firstName: "John", - imageUrl: "img1.jpg", + user_first_name: "John", + user_image_url: "img1.jpg", id: "playerId1", - createdAt: new Date("2023-01-10T10:00:00Z"), - highScore: 95, + play_created_at: new Date("2023-01-10T10:00:00Z"), + high_score: 95, }, { - firstName: "Doe", - imageUrl: "img2.jpg", + user_first_name: "Doe", + user_image_url: "img2.jpg", id: "playerId2", - createdAt: new Date("2023-01-05T10:00:00Z"), - highScore: 89, + play_created_at: new Date("2023-01-05T10:00:00Z"), + high_score: 89, }, { - firstName: "Alice", - imageUrl: "img3.jpg", + user_first_name: "Alice", + user_image_url: "img3.jpg", id: "playerId3", - createdAt: new Date("2023-01-08T10:00:00Z"), - highScore: 92, + play_created_at: new Date("2023-01-08T10:00:00Z"), + high_score: 92, }, ]); }); diff --git a/packages/api/src/router/tests/user.test.ts b/packages/api/src/router/tests/user.test.ts index 1c0b80d..6da45e5 100644 --- a/packages/api/src/router/tests/user.test.ts +++ b/packages/api/src/router/tests/user.test.ts @@ -172,30 +172,30 @@ describe("useRouter", () => { expect(ctx.prisma.$queryRaw).toHaveBeenCalledWith( //Note: the next lines `SELECT...LIMIT 3;` are CASE, SPACE, and NEXT-LINE SENSITIVE Prisma.sql` - SELECT - DISTINCT ON ("Play"."playerId") - "User"."firstName", - "User"."imageUrl", - "Play"."playerId" AS "id", - MAX("Play"."score") AS "highScore" - FROM - "Play" - JOIN - "User" - ON - "Play"."playerId" = "User"."userId" - WHERE - "Play"."isFinished" = TRUE - AND "Play"."testId" = ${item.testId} - GROUP BY - "Play"."playerId", - "User"."firstName", - "User"."imageUrl" - ORDER BY - "Play"."playerId", - "highScore" DESC - LIMIT 3; - `, + SELECT + DISTINCT ON ("play"."player_id") + "user"."user_first_name", + "user"."user_image_url", + "play"."player_id" AS "id", + MAX("play"."play_score") AS "high_score" + FROM + "play" + JOIN + "user" + ON + "play"."player_id" = "user"."clerk_user_id" + WHERE + "play"."play_is_finished" = TRUE + AND "play"."test_id" = ${item.testId} + GROUP BY + "play"."player_id", + "user"."user_first_name", + "user"."user_image_url" + ORDER BY + "play"."player_id", + "high_score" DESC + LIMIT 3; + `, ); }, { concurrency: 5 }, diff --git a/packages/api/src/router/user.ts b/packages/api/src/router/user.ts index 4c967e4..fe23908 100644 --- a/packages/api/src/router/user.ts +++ b/packages/api/src/router/user.ts @@ -2,10 +2,11 @@ import { highlightUsersInput, userStoredSchema } from "@acme/schema/src/user"; import { z } from "zod"; import { protectedProcedure, router } from "../trpc"; import { Prisma } from "@acme/db"; -import { PlayersHighscore } from "@acme/schema/src/types"; import pMap from "p-map"; import { updateUserInAlgolia } from "../services/algoliaApiHandlers/algoliaCudHandlers"; +import type { _PlayersHighscore } from "../types"; + export const useRouter = router({ getTop: protectedProcedure .meta({ @@ -137,32 +138,42 @@ export const useRouter = router({ userPlays, async (item) => { const top3Plays = await ctx.prisma - .$queryRaw(Prisma.sql` - SELECT - DISTINCT ON ("Play"."playerId") - "User"."firstName", - "User"."imageUrl", - "Play"."playerId" AS "id", - MAX("Play"."score") AS "highScore" - FROM - "Play" - JOIN - "User" - ON - "Play"."playerId" = "User"."userId" - WHERE - "Play"."isFinished" = TRUE - AND "Play"."testId" = ${item.testId} - GROUP BY - "Play"."playerId", - "User"."firstName", - "User"."imageUrl" - ORDER BY - "Play"."playerId", - "highScore" DESC - LIMIT 3; - `); - + .$queryRaw<_PlayersHighscore[]>( + Prisma.sql` + SELECT + DISTINCT ON ("play"."player_id") + "user"."user_first_name", + "user"."user_image_url", + "play"."player_id" AS "id", + MAX("play"."play_score") AS "high_score" + FROM + "play" + JOIN + "user" + ON + "play"."player_id" = "user"."clerk_user_id" + WHERE + "play"."play_is_finished" = TRUE + AND "play"."test_id" = ${item.testId} + GROUP BY + "play"."player_id", + "user"."user_first_name", + "user"."user_image_url" + ORDER BY + "play"."player_id", + "high_score" DESC + LIMIT 3; + `, + ) + .then((plays) => + plays.map((play) => ({ + id: play.id, + createdAt: play.play_created_at, + highScore: play.high_score, + firstName: play.user_first_name, + imageUrl: play.user_image_url, + })), + ); const userTop3Count = top3Plays.filter( (topPlay) => topPlay.id === ctx.auth.userId, ).length; diff --git a/packages/api/src/types.ts b/packages/api/src/types.ts new file mode 100644 index 0000000..529884c --- /dev/null +++ b/packages/api/src/types.ts @@ -0,0 +1,7 @@ +export type _PlayersHighscore = { + id: string; + user_first_name: string; + user_image_url: string; + play_created_at: Date; + high_score: number; +};