diff --git a/api/src/controllers/seed/insert/entries.ts b/api/src/controllers/seed/insert/entries.ts index 97c1fd2a..e91c882a 100644 --- a/api/src/controllers/seed/insert/entries.ts +++ b/api/src/controllers/seed/insert/entries.ts @@ -1,4 +1,4 @@ -import { type Column, type SQL, and, eq, isNull, sql } from "drizzle-orm"; +import { type Column, type SQL, eq, sql } from "drizzle-orm"; import { db } from "~/db"; import { entries, @@ -6,7 +6,7 @@ import { entryVideoJoin, videos, } from "~/db/schema"; -import { conflictUpdateAllExcept, sqlarr, values } from "~/db/utils"; +import { conflictUpdateAllExcept, values } from "~/db/utils"; import type { SeedEntry as SEntry, SeedExtra as SExtra } from "~/models/entry"; import { enqueueOptImage } from "../images"; import { guessNextRefresh } from "../refresh"; diff --git a/api/src/controllers/videos.ts b/api/src/controllers/videos.ts index 51b0ef6c..0fe22fc5 100644 --- a/api/src/controllers/videos.ts +++ b/api/src/controllers/videos.ts @@ -392,48 +392,48 @@ export const videosH = new Elysia({ prefix: "/videos", tags: ["videos"] }) .delete( "", async ({ body }) => { - await db.transaction(async (tx) => { + return await db.transaction(async (tx) => { const vids = tx.$with("vids").as( tx .delete(videos) - .where(eq(videos.path, sql`any(${body})`)) - .returning({ pk: videos.pk }), + .where(eq(videos.path, sql`any(${sqlarr(body)})`)) + .returning({ pk: videos.pk, path: videos.path }), ); - const evj = alias(entryVideoJoin, "evj"); - const delEntries = tx.$with("del_entries").as( - tx - .with(vids) - .select({ entry: entryVideoJoin.entryPk }) - .from(entryVideoJoin) - .where( - and( - inArray(entryVideoJoin.videoPk, tx.select().from(vids)), - notExists( - tx - .select() - .from(evj) - .where( - and( - eq(evj.entryPk, entryVideoJoin.entryPk), - not(inArray(evj.videoPk, db.select().from(vids))), - ), - ), - ), - ), - ), - ); - const delShows = await tx - .with(delEntries) + + const deletedJoin = await tx + .with(vids) + .select({ entryPk: entryVideoJoin.entryPk, path: vids.path }) + .from(entryVideoJoin) + .rightJoin(vids, eq(vids.pk, entryVideoJoin.videoPk)); + + const delEntries = await tx .update(entries) .set({ availableSince: null }) - .where(inArray(entries.pk, db.select().from(delEntries))) + .where( + and( + eq( + entries.pk, + sql`any(${sqlarr( + deletedJoin.filter((x) => x.entryPk).map((x) => x.entryPk!), + )})`, + ), + notExists( + tx + .select() + .from(entryVideoJoin) + .where(eq(entries.pk, entryVideoJoin.entryPk)), + ), + ), + ) .returning({ show: entries.showPk }); await updateAvailableCount( tx, - delShows.map((x) => x.show), + delEntries.map((x) => x.show), false, ); + + return [...new Set(deletedJoin.map((x) => x.path))]; }); }, { @@ -444,6 +444,6 @@ export const videosH = new Elysia({ prefix: "/videos", tags: ["videos"] }) examples: [bubbleVideo.path], }), ), - response: { 204: t.Void() }, + response: { 200: t.Array(t.String()) }, }, ); diff --git a/api/tests/videos/getdel.test.ts b/api/tests/videos/getdel.test.ts index 8fb093f5..9f5b8aea 100644 --- a/api/tests/videos/getdel.test.ts +++ b/api/tests/videos/getdel.test.ts @@ -171,7 +171,9 @@ describe("Video get/deletion", () => { it("Delete video", async () => { const [resp, body] = await deleteVideo(["/video/mia s1e13 mismatch.mkv"]); - expectStatus(resp, body).toBe(204); + expectStatus(resp, body).toBe(200); + expect(body).toBeArrayOfSize(1); + expect(body).toContain("/video/mia s1e13 mismatch.mkv"); const bubble = await db.query.shows.findFirst({ where: eq(shows.slug, "bubble"), @@ -181,7 +183,9 @@ describe("Video get/deletion", () => { it("Delete all videos of a movie", async () => { const [resp, body] = await deleteVideo(["/video/bubble.mkv"]); - expectStatus(resp, body).toBe(204); + expectStatus(resp, body).toBe(200); + expect(body).toBeArrayOfSize(1); + expect(body).toContain("/video/bubble.mkv"); const bubble = await db.query.shows.findFirst({ where: eq(shows.slug, "bubble"), @@ -190,9 +194,9 @@ describe("Video get/deletion", () => { }); it("Delete non existing video", async () => { - // it's way too much of a pain to return deleted paths with the current query so this will do const [resp, body] = await deleteVideo(["/video/toto.mkv"]); - expectStatus(resp, body).toBe(204); + expectStatus(resp, body).toBe(200); + expect(body).toBeArrayOfSize(0); }); it("Delete episodes", async () => { @@ -200,7 +204,10 @@ describe("Video get/deletion", () => { "/video/mia s1e13.mkv", "/video/mia 2017 s2e1.mkv", ]); - expectStatus(resp, body).toBe(204); + expectStatus(resp, body).toBe(200); + expect(body).toBeArrayOfSize(2); + expect(body).toContain("/video/mia s1e13.mkv"); + expect(body).toContain("/video/mia 2017 s2e1.mkv"); const mia = await db.query.shows.findFirst({ where: eq(shows.slug, "made-in-abyss"), @@ -222,6 +229,8 @@ describe("Video get/deletion", () => { const [resp, body] = await deleteVideo([ "/video/mia s1e13 unknown test.mkv", ]); - expectStatus(resp, body).toBe(204); + expectStatus(resp, body).toBe(200); + expect(body).toBeArrayOfSize(1); + expect(body[0]).toBe("/video/mia s1e13 unknown test.mkv"); }); });