Use unnest everywhere

This commit is contained in:
Zoe Roux
2025-11-26 19:42:17 +01:00
parent a45e992339
commit 8fc279d2ed
9 changed files with 67 additions and 28 deletions
+7 -3
View File
@@ -11,6 +11,7 @@ import { db, type Transaction } from "~/db";
import { mqueue } from "~/db/schema/mqueue";
import type { Image } from "~/models/utils";
import { getFile } from "~/utils";
import { unnestValues } from "~/db/utils";
export const imageDir = process.env.IMAGES_PATH ?? "/images";
export const defaultBlurhash = "000000";
@@ -83,9 +84,12 @@ export const flushImageQueue = async (
) => {
if (!imgQueue.length) return;
record("enqueue images", async () => {
await tx
.insert(mqueue)
.values(imgQueue.map((x) => ({ kind: "image", message: x, priority })));
await tx.insert(mqueue).select(
unnestValues(
imgQueue.map((x) => ({ kind: "image", message: x, priority })),
mqueue,
),
);
await tx.execute(sql`notify kyoo_image`);
});
};
@@ -1,7 +1,7 @@
import { sql } from "drizzle-orm";
import { db } from "~/db";
import { shows, showTranslations } from "~/db/schema";
import { conflictUpdateAllExcept } from "~/db/utils";
import { conflictUpdateAllExcept, unnestValues } from "~/db/utils";
import type { SeedCollection } from "~/models/collections";
import type { SeedMovie } from "~/models/movie";
import type { SeedSerie } from "~/models/serie";
@@ -75,7 +75,7 @@ export const insertCollection = async (
await flushImageQueue(tx, imgQueue, 100);
await tx
.insert(showTranslations)
.values(trans)
.select(unnestValues(trans, showTranslations))
.onConflictDoUpdate({
target: [showTranslations.pk, showTranslations.language],
set: conflictUpdateAllExcept(showTranslations, ["pk", "language"]),
+4 -3
View File
@@ -6,7 +6,7 @@ import {
entryVideoJoin,
videos,
} from "~/db/schema";
import { conflictUpdateAllExcept, unnestValues, values } from "~/db/utils";
import { conflictUpdateAllExcept, unnest, unnestValues } from "~/db/utils";
import type { SeedEntry as SEntry, SeedExtra as SExtra } from "~/models/entry";
import { enqueueOptImage, flushImageQueue, type ImageTask } from "../images";
import { guessNextRefresh } from "../refresh";
@@ -169,11 +169,12 @@ export const insertEntries = async (
),
})
.from(
values(vids, {
unnest(vids, "vids", {
entryPk: "integer",
entrySlug: "string",
needRendering: "boolean",
videoId: "uuid",
}).as("vids"),
}),
)
.innerJoin(videos, eq(videos.id, sql`vids.videoId`)),
)
+3 -3
View File
@@ -1,6 +1,6 @@
import { db } from "~/db";
import { seasons, seasonTranslations } from "~/db/schema";
import { conflictUpdateAllExcept } from "~/db/utils";
import { conflictUpdateAllExcept, unnestValues } from "~/db/utils";
import type { SeedSeason } from "~/models/season";
import { enqueueOptImage, flushImageQueue, type ImageTask } from "../images";
import { guessNextRefresh } from "../refresh";
@@ -30,7 +30,7 @@ export const insertSeasons = async (
});
const ret = await tx
.insert(seasons)
.values(vals)
.select(unnestValues(vals, seasons))
.onConflictDoUpdate({
target: seasons.slug,
set: conflictUpdateAllExcept(seasons, [
@@ -66,7 +66,7 @@ export const insertSeasons = async (
await flushImageQueue(tx, imgQueue, -10);
await tx
.insert(seasonTranslations)
.values(trans)
.select(unnestValues(trans, seasonTranslations))
.onConflictDoUpdate({
target: [seasonTranslations.pk, seasonTranslations.language],
set: conflictUpdateAllExcept(seasonTranslations, ["pk", "language"]),
+2 -2
View File
@@ -16,7 +16,7 @@ import {
shows,
showTranslations,
} from "~/db/schema";
import { conflictUpdateAllExcept, sqlarr } from "~/db/utils";
import { conflictUpdateAllExcept, sqlarr, unnestValues } from "~/db/utils";
import type { SeedCollection } from "~/models/collections";
import type { SeedMovie } from "~/models/movie";
import type { SeedSerie } from "~/models/serie";
@@ -95,7 +95,7 @@ export const insertShow = async (
await flushImageQueue(tx, imgQueue, 200);
await tx
.insert(showTranslations)
.values(trans)
.select(unnestValues(trans, showTranslations))
.onConflictDoUpdate({
target: [showTranslations.pk, showTranslations.language],
set: conflictUpdateAllExcept(showTranslations, ["pk", "language"]),
+3 -3
View File
@@ -1,7 +1,7 @@
import { eq, sql } from "drizzle-orm";
import { db } from "~/db";
import { roles, staff } from "~/db/schema";
import { conflictUpdateAllExcept } from "~/db/utils";
import { conflictUpdateAllExcept, unnestValues } from "~/db/utils";
import type { SeedStaff } from "~/models/staff";
import { enqueueOptImage, flushImageQueue, type ImageTask } from "../images";
@@ -22,7 +22,7 @@ export const insertStaff = async (
}));
const ret = await tx
.insert(staff)
.values(people)
.select(unnestValues(people, staff))
.onConflictDoUpdate({
target: staff.slug,
set: conflictUpdateAllExcept(staff, ["pk", "id", "slug", "createdAt"]),
@@ -50,7 +50,7 @@ export const insertStaff = async (
// - we want `order` to stay in sync (& without duplicates)
// - we don't have ways to identify a role so we can't onConflict
await tx.delete(roles).where(eq(roles.showPk, showPk));
await tx.insert(roles).values(rval);
await tx.insert(roles).select(unnestValues(rval, roles));
return ret;
});
+12 -4
View File
@@ -1,6 +1,7 @@
import { sql } from "drizzle-orm";
import { db } from "~/db";
import { showStudioJoin, studios, studioTranslations } from "~/db/schema";
import { conflictUpdateAllExcept } from "~/db/utils";
import { conflictUpdateAllExcept, sqlarr, unnestValues } from "~/db/utils";
import type { SeedStudio } from "~/models/studio";
import { enqueueOptImage, flushImageQueue, type ImageTask } from "../images";
@@ -21,7 +22,7 @@ export const insertStudios = async (
const ret = await tx
.insert(studios)
.values(vals)
.select(unnestValues(vals, studios))
.onConflictDoUpdate({
target: studios.slug,
set: conflictUpdateAllExcept(studios, [
@@ -48,7 +49,7 @@ export const insertStudios = async (
await flushImageQueue(tx, imgQueue, -100);
await tx
.insert(studioTranslations)
.values(trans)
.select(unnestValues(trans, studioTranslations))
.onConflictDoUpdate({
target: [studioTranslations.pk, studioTranslations.language],
set: conflictUpdateAllExcept(studioTranslations, ["pk", "language"]),
@@ -56,7 +57,14 @@ export const insertStudios = async (
await tx
.insert(showStudioJoin)
.values(ret.map((studio) => ({ showPk: showPk, studioPk: studio.pk })))
.select(
db
.select({
showPk: sql`${showPk}`.as("showPk"),
studioPk: sql`v.studioPk`.as("studioPk"),
})
.from(sql`unnest(${sqlarr(ret.map((x) => x.pk))}) as v("studioPk")`),
)
.onConflictDoNothing();
return ret;
});
+5 -4
View File
@@ -35,7 +35,8 @@ import {
jsonbBuildObject,
jsonbObjectAgg,
sqlarr,
values,
unnest,
unnestValues,
} from "~/db/utils";
import { Entry } from "~/models/entry";
import { KError } from "~/models/error";
@@ -129,10 +130,10 @@ async function linkVideos(
slug: computeVideoSlug(entriesQ.slug, hasRenderingQ),
})
.from(
values(links, {
unnest(links, "j", {
video: "integer",
entry: "jsonb",
}).as("j"),
}),
)
.innerJoin(videos, eq(videos.pk, sql`j.video`))
.innerJoin(
@@ -835,7 +836,7 @@ export const videosWriteH = new Elysia({ prefix: "/videos", tags: ["videos"] })
try {
vids = await tx
.insert(videos)
.values(body)
.select(unnestValues(body, videos))
.onConflictDoUpdate({
target: [videos.path],
set: conflictUpdateAllExcept(videos, ["pk", "id", "createdAt"]),