Add serie model, dummy controller & example

This commit is contained in:
Zoe Roux 2024-11-09 12:29:09 +01:00
parent 89952185a9
commit c5a502ec32
No known key found for this signature in database
9 changed files with 196 additions and 30 deletions

View File

@ -0,0 +1,11 @@
import { Elysia, t } from "elysia";
import { Serie } from "../models/serie";
export const series = new Elysia({ prefix: "/series" })
.model({
serie: Serie,
error: t.Object({}),
})
.get("/:id", () => "hello" as unknown as Serie, {
response: { 200: "serie" },
});

View File

@ -3,6 +3,7 @@ import { swagger } from "@elysiajs/swagger";
import { migrate } from "drizzle-orm/node-postgres/migrator"; import { migrate } from "drizzle-orm/node-postgres/migrator";
import { Elysia } from "elysia"; import { Elysia } from "elysia";
import { movies } from "./controllers/movies"; import { movies } from "./controllers/movies";
import { series } from "./controllers/series";
import { videos } from "./controllers/videos"; import { videos } from "./controllers/videos";
import { db } from "./db"; import { db } from "./db";
@ -33,6 +34,7 @@ const app = new Elysia()
.use(swagger()) .use(swagger())
.get("/", () => "Hello Elysia") .get("/", () => "Hello Elysia")
.use(movies) .use(movies)
.use(series)
.use(videos) .use(videos)
.listen(3000); .listen(3000);

View File

@ -1,22 +1,4 @@
import type { TSchema } from "elysia"; import type { CompleteVideo } from "../video";
import type { CompleteVideo } from "./video";
export const registerExamples = <T extends TSchema>(
schema: T,
...examples: (T["static"] | undefined)[]
) => {
for (const example of examples) {
if (!example) continue;
for (const [key, val] of Object.entries(example)) {
const prop = schema.properties[
key as keyof typeof schema.properties
] as TSchema;
if (!prop) continue;
prop.examples ??= [];
prop.examples.push(val);
}
}
};
export const bubble: CompleteVideo = { export const bubble: CompleteVideo = {
id: "0934da28-4a49-404e-920b-a150404a3b6d", id: "0934da28-4a49-404e-920b-a150404a3b6d",

View File

@ -0,0 +1,27 @@
import type { TSchema } from "elysia";
export const registerExamples = <T extends TSchema>(
schema: T,
...examples: (T["static"] | undefined)[]
) => {
if ("anyOf" in schema) {
for (const union of schema.anyOf) {
registerExamples(union, examples);
}
return;
}
for (const example of examples) {
if (!example) continue;
for (const [key, val] of Object.entries(example)) {
const prop = schema.properties[
key as keyof typeof schema.properties
] as TSchema;
if (!prop) continue;
prop.examples ??= [];
prop.examples.push(val);
}
}
};
export { bubble } from "./bubble";
export { madeInAbyss } from "./made-in-abyss";

View File

@ -0,0 +1,79 @@
import type { Serie } from "../serie";
export const madeInAbyss: Serie = {
id: "04bcf2ac-3c09-42f6-8357-b003798f9562",
slug: "made-in-abyss",
name: "Made in Abyss",
tagline: "How far would you go… for the ones you love?",
aliases: [
"Made in Abyss: The Golden City of the Scorching Sun",
"Meidoinabisu",
"Meidoinabisu: Retsujitsu no ôgonkyô",
],
description:
"Located in the center of a remote island, the Abyss is the last unexplored region, a huge and treacherous fathomless hole inhabited by strange creatures where only the bravest adventurers descend in search of ancient relics. In the upper levels of the Abyss, Riko, a girl who dreams of becoming an explorer, stumbles upon a mysterious little boy.",
tags: [
"android",
"amnesia",
"post-apocalyptic future",
"exploration",
"friendship",
"mecha",
"survival",
"curse",
"tragedy",
"orphan",
"based on manga",
"robot",
"dark fantasy",
"seinen",
"anime",
"drastic change of life",
"fantasy",
"adventure",
],
genres: [
"animation",
"drama",
"action",
"adventure",
"science-fiction",
"fantasy",
],
status: "finished",
rating: 84,
runtime: 24,
originalLanguage: "ja",
startAir: "2017-07-07",
endAir: "2022-09-28",
poster: {
id: "8205a20e-d91f-804c-3a84-4e4dc6202d66",
source:
"https://image.tmdb.org/t/p/original/4Bh9qzB1Kau4RDaVQXVFdoJ0HcE.jpg",
blurhash: "LZGlS3XTD%jE~Wf,SeV@%2o|WERj",
},
thumbnail: {
id: "819d816c-88f6-9f3a-b5e7-ce3daaffbac4",
source:
"https://image.tmdb.org/t/p/original/Df9XrvZFIeQfLKfu8evRmzvRsd.jpg",
blurhash: "LmJtk{kq~q%2bbWCxaV@.8RixuNG",
},
logo: {
id: "23cb7b06-8406-2288-8e40-08bfc16180b5",
source:
"https://image.tmdb.org/t/p/original/7hY3Q4GhkiYPBfn4UoVg0AO4Zgk.png",
blurhash: "LKGaa%M{0zbI#7$%bbofGGw^wcw{",
},
banner: null,
trailerUrl: "https://www.youtube.com/watch?v=ePOyy6Wlk4s",
externalId: {
themoviedatabase: {
dataId: "72636",
link: "https://www.themoviedb.org/tv/72636",
},
imdb: { dataId: "tt7222086", link: "https://www.imdb.com/title/tt7222086" },
tvdb: { dataId: "326109", link: null },
},
createdAt: "2023-11-29T11:12:11.949503Z",
nextRefresh: "2025-01-07T11:42:50.948248Z",
};

View File

@ -1,10 +1,13 @@
import { t } from "elysia"; import { t } from "elysia";
import { Genre, ShowStatus } from "./show"; import { Genre } from "./show";
import { Image } from "./image"; import { Image } from "./image";
import { ExternalId } from "./external-id"; import { ExternalId } from "./external-id";
import { bubble, registerExamples } from "./examples"; import { bubble, registerExamples } from "./examples";
import { comment } from "../utils"; import { comment } from "../utils";
export const MovieStatus = t.UnionEnum(["unknown", "finished", "planned"]);
export type MovieStatus = typeof MovieStatus.static;
export const Movie = t.Object({ export const Movie = t.Object({
id: t.String({ format: "uuid" }), id: t.String({ format: "uuid" }),
slug: t.String(), slug: t.String(),
@ -16,8 +19,10 @@ export const Movie = t.Object({
genres: t.Array(Genre), genres: t.Array(Genre),
rating: t.Nullable(t.Number({ minimum: 0, maximum: 100 })), rating: t.Nullable(t.Number({ minimum: 0, maximum: 100 })),
status: ShowStatus, status: MovieStatus,
runtime: t.Nullable(t.Number({ minimum: 0 })), runtime: t.Nullable(
t.Number({ minimum: 0, description: "Runtime of the movie in minutes." }),
),
airDate: t.Nullable(t.String({ format: "date" })), airDate: t.Nullable(t.String({ format: "date" })),
originalLanguage: t.Nullable( originalLanguage: t.Nullable(

61
api/src/models/serie.ts Normal file
View File

@ -0,0 +1,61 @@
import { t } from "elysia";
import { Genre } from "./show";
import { Image } from "./image";
import { ExternalId } from "./external-id";
import { madeInAbyss , registerExamples } from "./examples";
import { comment } from "../utils";
export const SerieStatus = t.UnionEnum([
"unknown",
"finished",
"airing",
"planned",
]);
export type SerieStatus = typeof SerieStatus.static;
export const Serie = t.Object({
id: t.String({ format: "uuid" }),
slug: t.String(),
name: t.String(),
description: t.Nullable(t.String()),
tagline: t.Nullable(t.String()),
aliases: t.Array(t.String()),
tags: t.Array(t.String()),
genres: t.Array(Genre),
rating: t.Nullable(t.Number({ minimum: 0, maximum: 100 })),
status: SerieStatus,
runtime: t.Nullable(
t.Number({
minimum: 0,
description: "Average runtime of all episodes (in minutes.)",
}),
),
startAir: t.Nullable(t.String({ format: "date" })),
endAir: t.Nullable(t.String({ format: "date" })),
originalLanguage: t.Nullable(
t.String({
description: comment`
The language code this movie was made in.
This is a BCP 47 language code (the IETF Best Current Practices on Tags for Identifying Languages).
BCP 47 is also known as RFC 5646. It subsumes ISO 639 and is backward compatible with it.
`,
}),
),
poster: t.Nullable(Image),
thumbnail: t.Nullable(Image),
banner: t.Nullable(Image),
logo: t.Nullable(Image),
trailerUrl: t.Nullable(t.String()),
createdAt: t.String({ format: "date-time" }),
nextRefresh: t.String({ format: "date-time" }),
externalId: ExternalId,
});
export type Serie = typeof Serie.static;
registerExamples(Serie, madeInAbyss);

View File

@ -1,13 +1,5 @@
import { t } from "elysia"; import { t } from "elysia";
export const ShowStatus = t.UnionEnum([
"unknown",
"finished",
"airing",
"planned",
]);
export type ShowStatus = typeof ShowStatus.static;
export const Genre = t.UnionEnum([ export const Genre = t.UnionEnum([
"action", "action",
"adventure", "adventure",

7
api/src/seed.ts Normal file
View File

@ -0,0 +1,7 @@
import { db } from "./db";
import { videos } from "./db/schema/videos";
import { Video } from "./models/video";
const seed = async () =>{
db.insert(videos).values(Video.examples)
};