Add /studios/:id

This commit is contained in:
Zoe Roux 2025-03-03 10:01:41 +01:00
parent 03d071acb4
commit 44658ce6b0
No known key found for this signature in database
5 changed files with 170 additions and 10 deletions

View File

@ -1,8 +1,16 @@
import { and, eq, exists } from "drizzle-orm";
import { and, eq, exists, sql } from "drizzle-orm";
import Elysia, { t } from "elysia";
import { db } from "~/db";
import { showStudioJoin, shows, studios } from "~/db/schema";
import {
showStudioJoin,
shows,
studioTranslations,
studios,
} from "~/db/schema";
import { sqlarr } from "~/db/utils";
import { KError } from "~/models/error";
import { Movie } from "~/models/movie";
import { Serie } from "~/models/serie";
import { Show } from "~/models/show";
import { Studio, StudioTranslation } from "~/models/studio";
import {
@ -15,14 +23,94 @@ import {
} from "~/models/utils";
import { desc } from "~/models/utils/descriptions";
import { getShows, showFilters, showSort } from "./shows/logic";
import { Serie } from "~/models/serie";
import { Movie } from "~/models/movie";
export const studiosH = new Elysia({ tags: ["studios"] })
export const studiosH = new Elysia({ prefix: "/studios", tags: ["studios"] })
.model({
studio: Studio,
"studio-translation": StudioTranslation,
})
.get(
"/:id",
async ({
params: { id },
headers: { "accept-language": languages },
query: { with: relations },
error,
set,
}) => {
const langs = processLanguages(languages);
const ret = await db.query.studios.findFirst({
where: isUuid(id) ? eq(studios.id, id) : eq(studios.slug, id),
with: {
selectedTranslation: {
columns: { pk: false },
where: !languages.includes("*")
? eq(studioTranslations.language, sql`any(${sqlarr(langs)})`)
: undefined,
orderBy: [
sql`array_position(${sqlarr(langs)}, ${studioTranslations.language})`,
],
limit: 1,
},
...(relations.includes("translations") && {
translations: {
columns: {
pk: false,
},
},
}),
},
});
if (!ret) {
return error(404, {
status: 404,
message: `No studio with the id or slug: '${id}'`,
});
}
const tr = ret.selectedTranslation[0];
set.headers["content-language"] = tr.language;
return {
...ret,
...tr,
...(ret.translations && {
translations: Object.fromEntries(
ret.translations.map(
({ language, ...translation }) =>
[language, translation] as const,
),
),
}),
};
},
{
detail: {
description: "Get a studio by id or slug",
},
params: t.Object({
id: t.String({
description: "The id or slug of the collection to retrieve.",
example: "mappa",
}),
}),
query: t.Object({
with: t.Array(t.UnionEnum(["translations"]), {
default: [],
description: "Include related resources in the response.",
}),
}),
headers: t.Object({
"accept-language": AcceptLanguage(),
}),
response: {
200: { ...Studio, description: "Found" },
404: {
...KError,
description: "No collection found with the given id or slug.",
},
422: KError,
},
},
)
.guard({
params: t.Object({
id: t.String({
@ -52,7 +140,7 @@ export const studiosH = new Elysia({ tags: ["studios"] })
}),
})
.get(
"/studios/:id/shows",
"/:id/shows",
async ({
params: { id },
query: { limit, after, query, sort, filter, preferOriginal },
@ -111,7 +199,7 @@ export const studiosH = new Elysia({ tags: ["studios"] })
},
)
.get(
"/studios/:id/movies",
"/:id/movies",
async ({
params: { id },
query: { limit, after, query, sort, filter, preferOriginal },
@ -171,7 +259,7 @@ export const studiosH = new Elysia({ tags: ["studios"] })
},
)
.get(
"/studios/:id/series",
"/:id/series",
async ({
params: { id },
query: { limit, after, query, sort, filter, preferOriginal },

View File

@ -1,4 +1,4 @@
import { sql } from "drizzle-orm";
import { relations, sql } from "drizzle-orm";
import {
index,
integer,
@ -53,3 +53,37 @@ export const showStudioJoin = schema.table(
},
(t) => [primaryKey({ columns: [t.show, t.studio] })],
);
export const studioRelations = relations(studios, ({ many }) => ({
translations: many(studioTranslations, {
relationName: "studio_translations",
}),
selectedTranslation: many(studioTranslations, {
relationName: "studio_selected_translation",
}),
showsJoin: many(showStudioJoin, { relationName: "show_studios" }),
}));
export const studioTrRelations = relations(studioTranslations, ({ one }) => ({
studio: one(studios, {
relationName: "studio_translations",
fields: [studioTranslations.pk],
references: [studios.pk],
}),
selectedTranslation: one(studios, {
relationName: "studio_selected_translation",
fields: [studioTranslations.pk],
references: [studios.pk],
}),
}));
export const ssjRelations = relations(showStudioJoin, ({ one }) => ({
show: one(shows, {
relationName: "ssj_show",
fields: [showStudioJoin.show],
references: [shows.pk],
}),
studio: one(studios, {
relationName: "ssj_studio",
fields: [showStudioJoin.studio],
references: [studios.pk],
}),
}));

View File

@ -1,5 +1,6 @@
export * from "./movies-helper";
export * from "./series-helper";
export * from "./studio-helper";
export * from "./videos-helper";
export * from "~/elysia";

View File

@ -1,6 +1,24 @@
import { buildUrl } from "tests/utils";
import { app } from "~/elysia";
export const getStudio = async (
id: string,
{ langs, ...query }: { langs?: string; preferOriginal?: boolean },
) => {
const resp = await app.handle(
new Request(buildUrl(`studios/${id}`, query), {
method: "GET",
headers: langs
? {
"Accept-Language": langs,
}
: {},
}),
);
const body = await resp.json();
return [resp, body] as const;
};
export const getShowsByStudio = async (
studio: string,
{

View File

@ -1,5 +1,5 @@
import { beforeAll, describe, expect, it } from "bun:test";
import { getShowsByStudio } from "tests/helpers/studio-helper";
import { getShowsByStudio, getStudio } from "tests/helpers";
import { expectStatus } from "tests/utils";
import { seedSerie } from "~/controllers/seed/series";
import { madeInAbyss } from "~/models/examples";
@ -28,3 +28,22 @@ describe("Get by studio", () => {
expect(body.items[0].slug).toBe(madeInAbyss.slug);
});
});
describe("Get a studio", () => {
it("Invalid slug", async () => {
const [resp, body] = await getStudio("sotneuhn", { langs: "en" });
expectStatus(resp, body).toBe(404);
expect(body).toMatchObject({
status: 404,
message: expect.any(String),
});
});
it("Get by id", async () => {
const slug = madeInAbyss.studios[0].slug;
const [resp, body] = await getStudio(slug, { langs: "en" });
expectStatus(resp, body).toBe(200);
expect(body.slug).toBe(slug);
});
});