Add insert seasons

This commit is contained in:
Zoe Roux 2025-01-28 21:28:36 +01:00
parent 5d8d5721af
commit 32a1e89b27
No known key found for this signature in database
9 changed files with 140 additions and 13 deletions

View File

@ -0,0 +1,61 @@
import { db } from "~/db";
import { seasonTranslations, seasons } from "~/db/schema";
import { conflictUpdateAllExcept } from "~/db/utils";
import type { SeedSeason } from "~/models/season";
import { processOptImage } from "../images";
import { guessNextRefresh } from "../refresh";
type SeasonI = typeof seasons.$inferInsert;
type SeasonTransI = typeof seasonTranslations.$inferInsert;
export const insertSeasons = async (
show: { pk: number; slug: string },
items: SeedSeason[],
) => {
return db.transaction(async (tx) => {
const vals: SeasonI[] = items.map((x) => {
const { translations, ...season } = x;
return {
...season,
showPk: show.pk,
slug: `${show.slug}-s${season.seasonNumber}`,
nextRefresh: guessNextRefresh(season.startAir ?? new Date()),
};
});
const ret = await tx
.insert(seasons)
.values(vals)
.onConflictDoUpdate({
target: seasons.slug,
set: conflictUpdateAllExcept(seasons, [
"pk",
"showPk",
"id",
"slug",
"createdAt",
]),
})
.returning({ pk: seasons.pk, id: seasons.id, slug: seasons.slug });
const trans: SeasonTransI[] = items.flatMap((seed, i) =>
Object.entries(seed.translations).map(([lang, tr]) => ({
// assumes ret is ordered like items.
pk: ret[i].pk,
language: lang,
...tr,
poster: processOptImage(tr.poster),
thumbnail: processOptImage(tr.thumbnail),
banner: processOptImage(tr.banner),
})),
);
await tx
.insert(seasonTranslations)
.values(trans)
.onConflictDoUpdate({
target: [seasonTranslations.pk, seasonTranslations.language],
set: conflictUpdateAllExcept(seasonTranslations, ["pk", "language"]),
});
return ret;
});
};

View File

@ -4,10 +4,17 @@ import { getYear } from "~/utils";
import { insertEntries } from "./insert/entries";
import { insertShow } from "./insert/shows";
import { guessNextRefresh } from "./refresh";
import { insertSeasons } from "./insert/seasons";
export const SeedSerieResponse = t.Object({
id: t.String({ format: "uuid" }),
slug: t.String({ format: "slug", examples: ["made-in-abyss"] }),
seasons: t.Array(
t.Object({
id: t.String({ format: "uuid" }),
slug: t.String({ format: "slug", examples: ["made-in-abyss-s1"] }),
}),
),
entries: t.Array(
t.Object({
id: t.String({ format: "uuid" }),
@ -55,12 +62,14 @@ export const seedSerie = async (
);
if ("status" in show) return show;
const retSeasons = await insertSeasons(show, seasons);
const retEntries = await insertEntries(show, entries);
return {
updated: show.updated,
id: show.id,
slug: show.slug,
seasons: retSeasons,
entries: retEntries,
};
};

View File

@ -2,7 +2,7 @@ import { t } from "elysia";
import { Image } from "../utils/image";
export const BaseEntry = t.Object({
airDate: t.Nullable(t.String({ format: "data" })),
airDate: t.Nullable(t.String({ format: "date" })),
runtime: t.Nullable(
t.Number({ minimum: 0, description: "Runtime of the episode in minutes" }),
),

View File

@ -1,5 +1,5 @@
import type { SeedMovie } from "../movie";
import type { Video } from "../video";
import type { SeedMovie } from "~/models/movie";
import type { Video } from "~/models/video";
export const bubbleVideo: Video = {
id: "3cd436ee-01ff-4f45-ba98-62aabeb22f25",

View File

@ -1,4 +1,22 @@
import type { SeedSerie } from "~/models/serie";
import type { Video } from "~/models/video";
export const madeInAbyssVideo: Video = {
id: "3cd436ee-01ff-4f45-ba98-654282531234",
slug: "made-in-abyss-s1e1",
path: "/video/Made in abyss S01E01.mkv",
rendering: "459429fa062adeebedcc2bb04b9965de0262bfa453369783132d261be79021bd",
part: null,
version: 1,
guess: {
title: "Made in abyss",
season: [1],
episode: [1],
type: "episode",
from: "guessit",
},
createdAt: "2024-11-23T15:01:24.968Z",
};
export const madeInAbyss = {
slug: "made-in-abyss",

View File

@ -45,6 +45,7 @@ export const SeedSeason = t.Intersect([
),
}),
]);
export type SeedSeason = typeof SeedSeason.static;
registerExamples(Season, {
...madeInAbyss.seasons[0],

View File

@ -37,22 +37,24 @@ export const Video = t.Object({
t.Object(
{
title: t.String(),
year: t.Array(t.Integer(), { default: [] }),
season: t.Array(t.Integer(), { default: [] }),
episode: t.Array(t.Integer(), { default: [] }),
year: t.Optional(t.Array(t.Integer(), { default: [] })),
season: t.Optional(t.Array(t.Integer(), { default: [] })),
episode: t.Optional(t.Array(t.Integer(), { default: [] })),
// TODO: maybe replace "extra" with the `extraKind` value (aka behind-the-scene, trailer, etc)
type: t.Optional(t.UnionEnum(["episode", "movie", "extra"])),
from: t.String({
description: "Name of the tool that made the guess",
}),
history: t.Array(t.Omit(Self, ["history"]), {
default: [],
description: comment`
When another tool refines the guess or a user manually edit it, the history of the guesses
are kept in this \`history\` value.
`,
}),
history: t.Optional(
t.Array(t.Omit(Self, ["history"]), {
default: [],
description: comment`
When another tool refines the guess or a user manually edit it, the history of the guesses
are kept in this \`history\` value.
`,
}),
),
},
{
additionalProperties: true,

View File

@ -0,0 +1,35 @@
import { describe, expect, it } from "bun:test";
import { eq } from "drizzle-orm";
import { expectStatus } from "tests/utils";
import { db } from "~/db";
import { seasons, shows, videos } from "~/db/schema";
import { madeInAbyss, madeInAbyssVideo } from "~/models/examples";
import { createSerie } from "../helpers";
describe("Serie seeding", () => {
it("Can create a serie with seasons and episodes", async () => {
// create video beforehand to test linking
await db.insert(videos).values(madeInAbyssVideo);
const [resp, body] = await createSerie(madeInAbyss);
expectStatus(resp, body).toBe(201);
expect(body.id).toBeString();
expect(body.slug).toBe("made-in-abyss");
const ret = await db.query.shows.findFirst({
where: eq(shows.id, body.id),
with: {
seasons: { orderBy: seasons.seasonNumber },
entries: true,
},
});
expect(ret).not.toBeNull();
expect(ret!.seasons).toBeArrayOfSize(2);
expect(ret!.seasons[0].slug).toBe("made-in-abyss-s1");
expect(ret!.seasons[1].slug).toBe("made-in-abyss-s2");
// expect(ret!.entries).toBeArrayOfSize(
// madeInAbyss.entries.length + madeInAbyss.extras.length,
// );
});
});

View File

@ -2,6 +2,7 @@
"$schema": "https://biomejs.dev/schemas/1.8.1/schema.json",
"formatter": {
"enabled": true,
"formatWithErrors": true,
"indentStyle": "tab",
"indentWidth": 2,
"lineEnding": "lf",