mirror of
https://github.com/zoriya/Kyoo.git
synced 2026-02-21 10:40:05 -05:00
127 lines
3.5 KiB
TypeScript
127 lines
3.5 KiB
TypeScript
import { and, count, eq, exists, sql } from "drizzle-orm";
|
|
import { db } from "~/db";
|
|
import { entries, entryVideoJoin, showTranslations, shows } from "~/db/schema";
|
|
import { conflictUpdateAllExcept, sqlarr } from "~/db/utils";
|
|
import type { SeedCollection } from "~/models/collections";
|
|
import type { SeedMovie } from "~/models/movie";
|
|
import type { SeedSerie } from "~/models/serie";
|
|
import { getYear } from "~/utils";
|
|
import { processOptImage } from "../images";
|
|
|
|
type Show = typeof shows.$inferInsert;
|
|
type ShowTrans = typeof showTranslations.$inferInsert;
|
|
|
|
export const insertShow = async (
|
|
show: Show,
|
|
translations:
|
|
| SeedMovie["translations"]
|
|
| SeedSerie["translations"]
|
|
| SeedCollection["translations"],
|
|
) => {
|
|
return await db.transaction(async (tx) => {
|
|
const ret = await insertBaseShow(tx, show);
|
|
if ("status" in ret) return ret;
|
|
|
|
const trans: ShowTrans[] = Object.entries(translations).map(
|
|
([lang, tr]) => ({
|
|
pk: ret.pk,
|
|
language: lang,
|
|
...tr,
|
|
poster: processOptImage(tr.poster),
|
|
thumbnail: processOptImage(tr.thumbnail),
|
|
logo: processOptImage(tr.logo),
|
|
banner: processOptImage(tr.banner),
|
|
}),
|
|
);
|
|
await tx
|
|
.insert(showTranslations)
|
|
.values(trans)
|
|
.onConflictDoUpdate({
|
|
target: [showTranslations.pk, showTranslations.language],
|
|
set: conflictUpdateAllExcept(showTranslations, ["pk", "language"]),
|
|
});
|
|
return ret;
|
|
});
|
|
};
|
|
|
|
async function insertBaseShow(
|
|
tx: Parameters<Parameters<typeof db.transaction>[0]>[0],
|
|
show: Show,
|
|
) {
|
|
function insert() {
|
|
return tx
|
|
.insert(shows)
|
|
.values(show)
|
|
.onConflictDoUpdate({
|
|
target: shows.slug,
|
|
set: conflictUpdateAllExcept(shows, ["pk", "id", "slug", "createdAt"]),
|
|
// if year is different, this is not an update but a conflict (ex: dune-1984 vs dune-2021)
|
|
setWhere: sql`date_part('year', ${shows.startAir}) = date_part('year', excluded."start_air")`,
|
|
})
|
|
.returning({
|
|
pk: shows.pk,
|
|
id: shows.id,
|
|
slug: shows.slug,
|
|
// https://stackoverflow.com/questions/39058213/differentiate-inserted-and-updated-rows-in-upsert-using-system-columns/39204667#39204667
|
|
updated: sql<boolean>`(xmax <> 0)`.as("updated"),
|
|
});
|
|
}
|
|
|
|
let [ret] = await insert();
|
|
if (ret) return ret;
|
|
|
|
// ret is undefined when the conflict's where return false (meaning we have
|
|
// a conflicting slug but a different air year.
|
|
// try to insert adding the year at the end of the slug.
|
|
if (show.startAir && !show.slug.endsWith(`${getYear(show.startAir)}`)) {
|
|
show.slug = `${show.slug}-${getYear(show.startAir)}`;
|
|
[ret] = await insert();
|
|
if (ret) return ret;
|
|
}
|
|
|
|
// if at this point ret is still undefined, we could not reconciliate.
|
|
// simply bail and let the caller handle this.
|
|
const [{ pk, id }] = await db
|
|
.select({ pk: shows.pk, id: shows.id })
|
|
.from(shows)
|
|
.where(eq(shows.slug, show.slug))
|
|
.limit(1);
|
|
return {
|
|
status: 409 as const,
|
|
pk,
|
|
id,
|
|
slug: show.slug,
|
|
};
|
|
}
|
|
|
|
export async function updateAvailableCount(
|
|
showPks: number[],
|
|
updateEntryCount = true,
|
|
) {
|
|
return await db
|
|
.update(shows)
|
|
.set({
|
|
availableCount: db
|
|
.select({ availableCount: count() })
|
|
.from(entries)
|
|
.where(
|
|
and(
|
|
eq(entries.showPk, shows.pk),
|
|
exists(
|
|
db
|
|
.select()
|
|
.from(entryVideoJoin)
|
|
.where(eq(entryVideoJoin.entryPk, entries.pk)),
|
|
),
|
|
),
|
|
),
|
|
...(updateEntryCount && {
|
|
entriesCount: db
|
|
.select({ entriesCount: count() })
|
|
.from(entries)
|
|
.where(eq(entries.showPk, shows.pk)),
|
|
}),
|
|
})
|
|
.where(eq(shows.pk, sql`any(${sqlarr(showPks)})`));
|
|
}
|