From 039880d8124a5255ca203b0d974b2de6394b8e35 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sun, 9 Mar 2025 21:47:36 +0100 Subject: [PATCH] Add /series/:id/staff --- api/src/controllers/staff.ts | 142 +++++++++++++++++++++++++++++------ 1 file changed, 118 insertions(+), 24 deletions(-) diff --git a/api/src/controllers/staff.ts b/api/src/controllers/staff.ts index ad841c20..70696fdd 100644 --- a/api/src/controllers/staff.ts +++ b/api/src/controllers/staff.ts @@ -1,4 +1,5 @@ -import { and, eq, sql } from "drizzle-orm"; +import type { StaticDecode } from "@sinclair/typebox"; +import { type SQL, and, eq, sql } from "drizzle-orm"; import Elysia, { t } from "elysia"; import { db } from "~/db"; import { showTranslations, shows } from "~/db/schema"; @@ -50,6 +51,42 @@ const roleShowFilters: FilterDef = { ...showFilters, }; +async function getStaffRoles({ + after, + limit, + query, + sort, + filter, +}: { + after?: string; + limit: number; + query?: string; + sort?: StaticDecode; + filter?: SQL; +}) { + return await db + .select({ + ...getColumns(roles), + staff: getColumns(staff), + }) + .from(roles) + .innerJoin(staff, eq(roles.staffPk, staff.pk)) + .where( + and( + filter, + query ? sql`${staff.name} %> ${query}::text` : undefined, + keysetPaginate({ table: roles, sort, after }), + ), + ) + .orderBy( + ...(query + ? [sql`word_similarity(${query}::text, ${staff.name})`] + : sortToSql(sort, roles)), + shows.pk, + ) + .limit(limit); +} + export const staffH = new Elysia({ tags: ["staff"] }) .model({ staff: Staff, @@ -282,7 +319,12 @@ export const staffH = new Elysia({ tags: ["staff"] }) const [movie] = await db .select({ pk: shows.pk }) .from(shows) - .where(isUuid(id) ? eq(shows.id, id) : eq(shows.slug, id)) + .where( + and( + eq(shows.kind, "movie"), + isUuid(id) ? eq(shows.id, id) : eq(shows.slug, id), + ), + ) .limit(1); if (!movie) { @@ -292,28 +334,13 @@ export const staffH = new Elysia({ tags: ["staff"] }) }); } - const items = await db - .select({ - ...getColumns(roles), - staff: getColumns(staff), - }) - .from(roles) - .innerJoin(staff, eq(roles.staffPk, staff.pk)) - .where( - and( - filter, - query ? sql`${staff.name} %> ${query}::text` : undefined, - keysetPaginate({ table: roles, sort, after }), - ), - ) - .orderBy( - ...(query - ? [sql`word_similarity(${query}::text, ${staff.name})`] - : sortToSql(sort, roles)), - shows.pk, - ) - .limit(limit); - + const items = await getStaffRoles({ + limit, + after, + query, + sort, + filter: and(eq(shows.pk, roles.showPk), filter), + }); return createPage(items, { url, sort, limit }); }, { @@ -347,4 +374,71 @@ export const staffH = new Elysia({ tags: ["staff"] }) 422: KError, }, }, + ) + .get( + "/series/:id/staff", + async ({ + params: { id }, + query: { limit, after, query, sort, filter }, + request: { url }, + error, + }) => { + const [serie] = await db + .select({ pk: shows.pk }) + .from(shows) + .where( + and( + eq(shows.kind, "serie"), + isUuid(id) ? eq(shows.id, id) : eq(shows.slug, id), + ), + ) + .limit(1); + + if (!serie) { + return error(404, { + status: 404, + message: `No serie with the id or slug: '${id}'.`, + }); + } + + const items = await getStaffRoles({ + limit, + after, + query, + sort, + filter: and(eq(shows.pk, roles.showPk), filter), + }); + return createPage(items, { url, sort, limit }); + }, + { + detail: { + description: "Get all staff member who worked on this serie", + }, + params: t.Object({ + id: t.String({ + description: "The id or slug of the serie.", + example: "made-in-abyss", + }), + }), + query: t.Object({ + sort: staffRoleSort, + filter: t.Optional(Filter({ def: staffRoleFilter })), + query: t.Optional(t.String({ description: desc.query })), + limit: t.Integer({ + minimum: 1, + maximum: 250, + default: 50, + description: "Max page size.", + }), + after: t.Optional(t.String({ description: desc.after })), + }), + response: { + 200: Page(RoleWStaff), + 404: { + ...KError, + description: "No serie found with the given id or slug.", + }, + 422: KError, + }, + }, );