mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-31 20:24:27 -04:00
Add with=translations
in the sql builder logic
This commit is contained in:
parent
3f77a1bda5
commit
c161d680e3
@ -2,7 +2,12 @@ import type { StaticDecode } from "@sinclair/typebox";
|
|||||||
import { type SQL, and, eq, sql } from "drizzle-orm";
|
import { type SQL, and, eq, sql } from "drizzle-orm";
|
||||||
import { db } from "~/db";
|
import { db } from "~/db";
|
||||||
import { showTranslations, shows, studioTranslations } from "~/db/schema";
|
import { showTranslations, shows, studioTranslations } from "~/db/schema";
|
||||||
import { getColumns, sqlarr } from "~/db/utils";
|
import {
|
||||||
|
getColumns,
|
||||||
|
jsonbBuildObject,
|
||||||
|
jsonbObjectAgg,
|
||||||
|
sqlarr,
|
||||||
|
} from "~/db/utils";
|
||||||
import type { MovieStatus } from "~/models/movie";
|
import type { MovieStatus } from "~/models/movie";
|
||||||
import { SerieStatus } from "~/models/serie";
|
import { SerieStatus } from "~/models/serie";
|
||||||
import {
|
import {
|
||||||
@ -55,6 +60,16 @@ export const showSort = Sort(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const buildRelations = <R extends string>(
|
||||||
|
relations: R[],
|
||||||
|
toSql: (relation: R) => SQL,
|
||||||
|
) => {
|
||||||
|
return Object.fromEntries(relations.map((x) => [x, toSql(x)])) as Record<
|
||||||
|
R,
|
||||||
|
SQL
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
|
||||||
export async function getShows({
|
export async function getShows({
|
||||||
after,
|
after,
|
||||||
limit,
|
limit,
|
||||||
@ -64,15 +79,17 @@ export async function getShows({
|
|||||||
languages,
|
languages,
|
||||||
fallbackLanguage = true,
|
fallbackLanguage = true,
|
||||||
preferOriginal = false,
|
preferOriginal = false,
|
||||||
|
relations = [],
|
||||||
}: {
|
}: {
|
||||||
after: string | undefined;
|
after?: string;
|
||||||
limit: number;
|
limit: number;
|
||||||
query: string | undefined;
|
query?: string;
|
||||||
sort: StaticDecode<typeof showSort>;
|
sort?: StaticDecode<typeof showSort>;
|
||||||
filter: SQL | undefined;
|
filter?: SQL;
|
||||||
languages: string[];
|
languages: string[];
|
||||||
fallbackLanguage?: boolean;
|
fallbackLanguage?: boolean;
|
||||||
preferOriginal?: boolean;
|
preferOriginal?: boolean;
|
||||||
|
relations?: ("translations" | "studios" | "videos")[];
|
||||||
}) {
|
}) {
|
||||||
const transQ = db
|
const transQ = db
|
||||||
.selectDistinctOn([showTranslations.pk])
|
.selectDistinctOn([showTranslations.pk])
|
||||||
@ -89,6 +106,22 @@ export async function getShows({
|
|||||||
.as("t");
|
.as("t");
|
||||||
const { pk, ...transCol } = getColumns(transQ);
|
const { pk, ...transCol } = getColumns(transQ);
|
||||||
|
|
||||||
|
const relationsSql = buildRelations(relations, (x) => {
|
||||||
|
switch (x) {
|
||||||
|
case "studios":
|
||||||
|
case "videos":
|
||||||
|
case "translations": {
|
||||||
|
// we wrap that in a sql`` instead of using the builder because of this issue
|
||||||
|
// https://github.com/drizzle-team/drizzle-orm/pull/1674
|
||||||
|
const { pk, language, ...trans } = getColumns(showTranslations);
|
||||||
|
return sql`${db
|
||||||
|
.select({ json: jsonbObjectAgg(language, jsonbBuildObject(trans)) })
|
||||||
|
.from(showTranslations)
|
||||||
|
.where(eq(showTranslations.pk, shows.pk))}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return await db
|
return await db
|
||||||
.select({
|
.select({
|
||||||
...getColumns(shows),
|
...getColumns(shows),
|
||||||
@ -107,6 +140,8 @@ export async function getShows({
|
|||||||
banner: sql<Image>`coalesce(nullif(${shows.original}->'banner', 'null'::jsonb), ${transQ.banner})`,
|
banner: sql<Image>`coalesce(nullif(${shows.original}->'banner', 'null'::jsonb), ${transQ.banner})`,
|
||||||
logo: sql<Image>`coalesce(nullif(${shows.original}->'logo', 'null'::jsonb), ${transQ.logo})`,
|
logo: sql<Image>`coalesce(nullif(${shows.original}->'logo', 'null'::jsonb), ${transQ.logo})`,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
...relationsSql,
|
||||||
})
|
})
|
||||||
.from(shows)
|
.from(shows)
|
||||||
[fallbackLanguage ? "innerJoin" : "leftJoin"](
|
[fallbackLanguage ? "innerJoin" : "leftJoin"](
|
||||||
|
@ -32,6 +32,7 @@ export const movies = new Elysia({ prefix: "/movies", tags: ["movies"] })
|
|||||||
}) => {
|
}) => {
|
||||||
const langs = processLanguages(languages);
|
const langs = processLanguages(languages);
|
||||||
const [ret] = await getShows({
|
const [ret] = await getShows({
|
||||||
|
limit: 1,
|
||||||
filter: and(
|
filter: and(
|
||||||
isUuid(id) ? eq(shows.id, id) : eq(shows.slug, id),
|
isUuid(id) ? eq(shows.id, id) : eq(shows.slug, id),
|
||||||
eq(shows.kind, "movie"),
|
eq(shows.kind, "movie"),
|
||||||
|
@ -10,6 +10,7 @@ import {
|
|||||||
Filter,
|
Filter,
|
||||||
Page,
|
Page,
|
||||||
createPage,
|
createPage,
|
||||||
|
isUuid,
|
||||||
processLanguages,
|
processLanguages,
|
||||||
} from "~/models/utils";
|
} from "~/models/utils";
|
||||||
import { desc } from "~/models/utils/descriptions";
|
import { desc } from "~/models/utils/descriptions";
|
||||||
@ -30,11 +31,16 @@ export const series = new Elysia({ prefix: "/series", tags: ["series"] })
|
|||||||
set,
|
set,
|
||||||
}) => {
|
}) => {
|
||||||
const langs = processLanguages(languages);
|
const langs = processLanguages(languages);
|
||||||
const ret = await getShow(id, {
|
const [ret] = await getShows({
|
||||||
|
limit: 1,
|
||||||
|
filter: and(
|
||||||
|
isUuid(id) ? eq(shows.id, id) : eq(shows.slug, id),
|
||||||
|
eq(shows.kind, "serie"),
|
||||||
|
),
|
||||||
languages: langs,
|
languages: langs,
|
||||||
|
fallbackLanguage: langs.includes("*"),
|
||||||
preferOriginal,
|
preferOriginal,
|
||||||
relations,
|
relations,
|
||||||
filters: eq(shows.kind, "serie"),
|
|
||||||
});
|
});
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
return error(404, {
|
return error(404, {
|
||||||
@ -49,7 +55,7 @@ export const series = new Elysia({ prefix: "/series", tags: ["series"] })
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
set.headers["content-language"] = ret.language;
|
set.headers["content-language"] = ret.language;
|
||||||
return ret.show;
|
return ret;
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
detail: {
|
detail: {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
type ColumnsSelection,
|
type ColumnsSelection,
|
||||||
type SQL,
|
type SQL,
|
||||||
|
type SQLWrapper,
|
||||||
type Subquery,
|
type Subquery,
|
||||||
Table,
|
Table,
|
||||||
View,
|
View,
|
||||||
@ -92,3 +93,17 @@ export function values(items: Record<string, unknown>[]) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const jsonbObjectAgg = (key: SQLWrapper, value: SQLWrapper) => {
|
||||||
|
return sql`jsonb_object_agg(${sql.join([key, value], sql.raw(","))})`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const jsonbBuildObject = (select: Record<string, SQLWrapper>) => {
|
||||||
|
const query = sql.join(
|
||||||
|
Object.entries(select).flatMap(([k, v]) => {
|
||||||
|
return [sql.raw(`'${k}'`), v];
|
||||||
|
}),
|
||||||
|
sql.raw(", "),
|
||||||
|
);
|
||||||
|
return sql`jsonb_build_object(${query})`;
|
||||||
|
};
|
||||||
|
@ -60,6 +60,40 @@ export const madeInAbyss = {
|
|||||||
banner: null,
|
banner: null,
|
||||||
trailerUrl: "https://www.youtube.com/watch?v=ePOyy6Wlk4s",
|
trailerUrl: "https://www.youtube.com/watch?v=ePOyy6Wlk4s",
|
||||||
},
|
},
|
||||||
|
ja: {
|
||||||
|
name: "メイドインアビス",
|
||||||
|
tagline: "さぁ 大穴(アビス)へ――",
|
||||||
|
aliases: ["烈日の黄金郷"],
|
||||||
|
description:
|
||||||
|
"隅々まで探索されつくした世界に、唯一残された秘境の大穴『アビス』。どこまで続くとも知れない深く巨大なその縦穴には、奇妙奇怪な生物たちが生息し、今の人類では作りえない貴重な遺物が眠っている。「アビス」の不可思議に満ちた姿は人々を魅了し、冒険へと駆り立てた。そうして幾度も大穴に挑戦する冒険者たちは、次第に『探窟家』と呼ばれるようになっていった。 アビスの縁に築かれた街『オース』に暮らす孤児のリコは、いつか母のような偉大な探窟家になり、アビスの謎を解き明かすことを夢見ていた。そんなある日、リコはアビスを探窟中に、少年の姿をしたロボットを拾い…?",
|
||||||
|
tags: [
|
||||||
|
"android",
|
||||||
|
"amnesia",
|
||||||
|
"post-apocalyptic future",
|
||||||
|
"exploration",
|
||||||
|
"friendship",
|
||||||
|
"mecha",
|
||||||
|
"survival",
|
||||||
|
"curse",
|
||||||
|
"tragedy",
|
||||||
|
"orphan",
|
||||||
|
"based on manga",
|
||||||
|
"robot",
|
||||||
|
"dark fantasy",
|
||||||
|
"seinen",
|
||||||
|
"anime",
|
||||||
|
"drastic change of life",
|
||||||
|
"fantasy",
|
||||||
|
"adventure",
|
||||||
|
],
|
||||||
|
poster:
|
||||||
|
"https://image.tmdb.org/t/p/original/4Bh9qzB1Kau4RDaVQXVFdoJ0HcE.jpg",
|
||||||
|
thumbnail:
|
||||||
|
"https://image.tmdb.org/t/p/original/Df9XrvZFIeQfLKfu8evRmzvRsd.jpg",
|
||||||
|
logo: "https://image.tmdb.org/t/p/original/7hY3Q4GhkiYPBfn4UoVg0AO4Zgk.png",
|
||||||
|
banner: null,
|
||||||
|
trailerUrl: "https://www.youtube.com/watch?v=ePOyy6Wlk4s",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
genres: [
|
genres: [
|
||||||
"animation",
|
"animation",
|
||||||
|
@ -26,9 +26,9 @@ export const keysetPaginate = <
|
|||||||
}: {
|
}: {
|
||||||
table: Table<"pk" | Sort<T, Remap>["sort"][number]["key"]>;
|
table: Table<"pk" | Sort<T, Remap>["sort"][number]["key"]>;
|
||||||
after: string | undefined;
|
after: string | undefined;
|
||||||
sort: Sort<T, Remap>;
|
sort: Sort<T, Remap> | undefined;
|
||||||
}) => {
|
}) => {
|
||||||
if (!after) return undefined;
|
if (!after || !sort) return undefined;
|
||||||
const cursor: After = JSON.parse(
|
const cursor: After = JSON.parse(
|
||||||
Buffer.from(after, "base64").toString("utf-8"),
|
Buffer.from(after, "base64").toString("utf-8"),
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { db, migrate } from "~/db";
|
import { db, migrate } from "~/db";
|
||||||
import { shows, videos } from "~/db/schema";
|
import { shows, videos } from "~/db/schema";
|
||||||
import { madeInAbyss, madeInAbyssVideo } from "~/models/examples";
|
import { madeInAbyss, madeInAbyssVideo } from "~/models/examples";
|
||||||
import { createSerie, createVideo } from "./helpers";
|
import { createSerie, createVideo, getSerie } from "./helpers";
|
||||||
|
|
||||||
// test file used to run manually using `bun tests/manual.ts`
|
// test file used to run manually using `bun tests/manual.ts`
|
||||||
|
|
||||||
@ -13,3 +13,5 @@ const [_, vid] = await createVideo(madeInAbyssVideo);
|
|||||||
console.log(vid);
|
console.log(vid);
|
||||||
const [__, ser] = await createSerie(madeInAbyss);
|
const [__, ser] = await createSerie(madeInAbyss);
|
||||||
console.log(ser);
|
console.log(ser);
|
||||||
|
const [___, got] = await getSerie(madeInAbyss.slug, { with: ["translations"] });
|
||||||
|
console.log(got);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user