Fix POST /videos

This commit is contained in:
Zoe Roux 2025-05-01 18:49:19 +02:00
parent d2bb37b3a7
commit 07a41bb175
No known key found for this signature in database
5 changed files with 68 additions and 53 deletions

View File

@ -161,20 +161,49 @@ export const videosH = new Elysia({ prefix: "/videos", tags: ["videos"] })
.post( .post(
"", "",
async ({ body, error }) => { async ({ body, error }) => {
const vidsI = db.$with("vidsI").as( const vids = await db
db .insert(videos)
.insert(videos) .values(body)
.values(body) .onConflictDoUpdate({
.onConflictDoUpdate({ target: [videos.path],
target: [videos.path], set: conflictUpdateAllExcept(videos, ["pk", "id", "createdAt"]),
set: conflictUpdateAllExcept(videos, ["pk", "id", "createdAt"]), })
}) .returning({
.returning({ pk: videos.pk,
pk: videos.pk, id: videos.id,
id: videos.id, path: videos.path,
path: videos.path, });
}),
); const vidEntries = body.flatMap((x) => {
if (!x.for) return [];
return x.for.map((e) => ({
video: vids.find((v) => v.path === x.path)!.pk,
path: x.path,
needRendering: x.for!.length > 1,
entry: {
...e,
movie:
"movie" in e
? isUuid(e.movie)
? { id: e.movie }
: { slug: e.movie }
: undefined,
serie:
"serie" in e
? isUuid(e.serie)
? { id: e.serie }
: { slug: e.serie }
: undefined,
},
}));
});
if (!vidEntries.length) {
return error(
201,
vids.map((x) => ({ id: x.id, path: x.path, entries: [] })),
);
}
const entriesQ = db const entriesQ = db
.select({ .select({
@ -197,45 +226,18 @@ export const videosH = new Elysia({ prefix: "/videos", tags: ["videos"] })
.where(eq(entryVideoJoin.entryPk, entriesQ.pk)); .where(eq(entryVideoJoin.entryPk, entriesQ.pk));
const ret = await db const ret = await db
.with(vidsI)
.insert(entryVideoJoin) .insert(entryVideoJoin)
.select( .select(
db db
.select({ .select({
entry: entries.pk, entry: entries.pk,
video: vidsI.pk, video: sql`j.video`,
slug: computeVideoSlug( slug: computeVideoSlug(
entriesQ.showSlug, entriesQ.showSlug,
sql`j.needRendering::boolean || exists(${hasRenderingQ})`, sql`j.needRendering::boolean || exists(${hasRenderingQ})`,
), ),
}) })
.from( .from(values(vidEntries).as("j"))
values(
body.flatMap((x) => {
if (!x.for) return [];
return x.for.map((e) => ({
path: x.path,
needRendering: x.for!.length > 1,
entry: {
...e,
movie:
"movie" in e
? isUuid(e.movie)
? { id: e.movie }
: { slug: e.movie }
: undefined,
serie:
"serie" in e
? isUuid(e.serie)
? { id: e.serie }
: { slug: e.serie }
: undefined,
},
}));
}),
).as("j"),
)
.innerJoin(vidsI, eq(vidsI.path, sql`j.path`))
.innerJoin( .innerJoin(
entriesQ, entriesQ,
or( or(
@ -279,11 +281,20 @@ export const videosH = new Elysia({ prefix: "/videos", tags: ["videos"] })
.returning({ .returning({
slug: entryVideoJoin.slug, slug: entryVideoJoin.slug,
entryPk: entryVideoJoin.entryPk, entryPk: entryVideoJoin.entryPk,
id: vidsI.id, videoPk: entryVideoJoin.videoPk,
path: vidsI.path,
}); });
return error(201, ret); const entr = ret.reduce(
// return error(201, ret.map(x => ({ id: x.id, slug: x.}))); (acc, x) => {
acc[x.videoPk] ??= [];
acc[x.videoPk].push({ slug: x.slug });
return acc;
},
{} as Record<number, { slug: string }[]>,
);
return error(
201,
vids.map((x) => ({ id: x.id, path: x.path, entries: entr[x.pk] })),
);
}, },
{ {
detail: { detail: {

View File

@ -76,6 +76,7 @@ export function sqlarr(array: unknown[]) {
// See https://github.com/drizzle-team/drizzle-orm/issues/4044 // See https://github.com/drizzle-team/drizzle-orm/issues/4044
// TODO: type values (everything is a `text` for now) // TODO: type values (everything is a `text` for now)
export function values(items: Record<string, unknown>[]) { export function values(items: Record<string, unknown>[]) {
if (items[0] === undefined) throw new Error("Invalid values, expecting at least one items")
const [firstProp, ...props] = Object.keys(items[0]); const [firstProp, ...props] = Object.keys(items[0]);
const values = items const values = items
.map((x) => { .map((x) => {

View File

@ -122,8 +122,11 @@ export const Video = t.Intersect([
]); ]);
export type Video = Prettify<typeof Video.static>; export type Video = Prettify<typeof Video.static>;
// type used in entry responses // type used in entry responses (the slug comes from the entryVideoJoin)
export const EmbeddedVideo = t.Omit(Video, ["guess", "createdAt", "updatedAt"]); export const EmbeddedVideo = t.Intersect([
t.Object({ slug: t.String({ format: "slug" }) }),
t.Omit(Video, ["guess", "createdAt", "updatedAt"]),
]);
export type EmbeddedVideo = Prettify<typeof EmbeddedVideo.static>; export type EmbeddedVideo = Prettify<typeof EmbeddedVideo.static>;
registerExamples(Video, bubbleVideo); registerExamples(Video, bubbleVideo);

View File

@ -39,7 +39,7 @@ describe("Video seeding", () => {
expect(vid).not.toBeNil(); expect(vid).not.toBeNil();
expect(vid!.path).toBe("/video/unknown s1e13.mkv"); expect(vid!.path).toBe("/video/unknown s1e13.mkv");
expect(vid!.guess).toBe({ title: "unknown", from: "test" }); expect(vid!.guess).toMatchObject({ title: "unknown", from: "test" });
expect(body[0].entries).toBeArrayOfSize(0); expect(body[0].entries).toBeArrayOfSize(0);
expect(vid!.evj).toBeArrayOfSize(0); expect(vid!.evj).toBeArrayOfSize(0);
@ -68,7 +68,7 @@ describe("Video seeding", () => {
expect(vid).not.toBeNil(); expect(vid).not.toBeNil();
expect(vid!.path).toBe("/video/mia s1e13.mkv"); expect(vid!.path).toBe("/video/mia s1e13.mkv");
expect(vid!.guess).toBe({ title: "mia", from: "test" }); expect(vid!.guess).toMatchObject({ title: "mia", from: "test" });
expect(body[0].entries).toBeArrayOfSize(1); expect(body[0].entries).toBeArrayOfSize(1);
expect(vid!.evj).toBeArrayOfSize(1); expect(vid!.evj).toBeArrayOfSize(1);
@ -106,7 +106,7 @@ describe("Video seeding", () => {
expect(vid).not.toBeNil(); expect(vid).not.toBeNil();
expect(vid!.path).toBe("/video/mia s1e13.mkv"); expect(vid!.path).toBe("/video/mia s1e13.mkv");
expect(vid!.guess).toBe({ title: "mia", from: "test" }); expect(vid!.guess).toMatchObject({ title: "mia", from: "test" });
expect(body[0].entries).toBeArrayOfSize(1); expect(body[0].entries).toBeArrayOfSize(1);
expect(vid!.evj).toBeArrayOfSize(1); expect(vid!.evj).toBeArrayOfSize(1);

View File

@ -20,7 +20,7 @@
in in
pkgs.mkShell { pkgs.mkShell {
packages = with pkgs; [ packages = with pkgs; [
nodejs-18_x # nodejs-18_x
nodePackages.yarn nodePackages.yarn
dotnet dotnet
csharpier csharpier