mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Add ?with=studios in movies & series
This commit is contained in:
parent
6cf8947c80
commit
750434465d
20
api/drizzle/0011_join_rename.sql
Normal file
20
api/drizzle/0011_join_rename.sql
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
ALTER TABLE "kyoo"."show_studio_join" RENAME COLUMN "show" TO "show_pk";--> statement-breakpoint
|
||||||
|
ALTER TABLE "kyoo"."show_studio_join" RENAME COLUMN "studio" TO "studio_pk";--> statement-breakpoint
|
||||||
|
ALTER TABLE "kyoo"."entry_video_join" RENAME COLUMN "entry" TO "entry_pk";--> statement-breakpoint
|
||||||
|
ALTER TABLE "kyoo"."entry_video_join" RENAME COLUMN "video" TO "video_pk";--> statement-breakpoint
|
||||||
|
ALTER TABLE "kyoo"."show_studio_join" DROP CONSTRAINT "show_studio_join_show_shows_pk_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "kyoo"."show_studio_join" DROP CONSTRAINT "show_studio_join_studio_studios_pk_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "kyoo"."entry_video_join" DROP CONSTRAINT "entry_video_join_entry_entries_pk_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "kyoo"."entry_video_join" DROP CONSTRAINT "entry_video_join_video_videos_pk_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "kyoo"."show_studio_join" DROP CONSTRAINT "show_studio_join_show_studio_pk";--> statement-breakpoint
|
||||||
|
ALTER TABLE "kyoo"."entry_video_join" DROP CONSTRAINT "entry_video_join_entry_video_pk";--> statement-breakpoint
|
||||||
|
ALTER TABLE "kyoo"."show_studio_join" ADD CONSTRAINT "show_studio_join_show_pk_studio_pk_pk" PRIMARY KEY("show_pk","studio_pk");--> statement-breakpoint
|
||||||
|
ALTER TABLE "kyoo"."entry_video_join" ADD CONSTRAINT "entry_video_join_entry_pk_video_pk_pk" PRIMARY KEY("entry_pk","video_pk");--> statement-breakpoint
|
||||||
|
ALTER TABLE "kyoo"."show_studio_join" ADD CONSTRAINT "show_studio_join_show_pk_shows_pk_fk" FOREIGN KEY ("show_pk") REFERENCES "kyoo"."shows"("pk") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "kyoo"."show_studio_join" ADD CONSTRAINT "show_studio_join_studio_pk_studios_pk_fk" FOREIGN KEY ("studio_pk") REFERENCES "kyoo"."studios"("pk") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "kyoo"."entry_video_join" ADD CONSTRAINT "entry_video_join_entry_pk_entries_pk_fk" FOREIGN KEY ("entry_pk") REFERENCES "kyoo"."entries"("pk") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "kyoo"."entry_video_join" ADD CONSTRAINT "entry_video_join_video_pk_videos_pk_fk" FOREIGN KEY ("video_pk") REFERENCES "kyoo"."videos"("pk") ON DELETE cascade ON UPDATE no action;
|
1265
api/drizzle/meta/0011_snapshot.json
Normal file
1265
api/drizzle/meta/0011_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -78,6 +78,13 @@
|
|||||||
"when": 1740950531468,
|
"when": 1740950531468,
|
||||||
"tag": "0010_studios",
|
"tag": "0010_studios",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 11,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1741014917375,
|
||||||
|
"tag": "0011_join_rename",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -141,8 +141,8 @@ export const insertEntries = async (
|
|||||||
.select(
|
.select(
|
||||||
db
|
db
|
||||||
.select({
|
.select({
|
||||||
entry: sql<number>`vids.entryPk::integer`.as("entry"),
|
entryPk: sql<number>`vids.entryPk::integer`.as("entry"),
|
||||||
video: sql`${videos.pk}`.as("video"),
|
videoPk: sql`${videos.pk}`.as("video"),
|
||||||
slug: computeVideoSlug(
|
slug: computeVideoSlug(
|
||||||
sql`${show.slug}::text`,
|
sql`${show.slug}::text`,
|
||||||
sql`vids.needRendering::boolean`,
|
sql`vids.needRendering::boolean`,
|
||||||
@ -154,7 +154,7 @@ export const insertEntries = async (
|
|||||||
.onConflictDoNothing()
|
.onConflictDoNothing()
|
||||||
.returning({
|
.returning({
|
||||||
slug: entryVideoJoin.slug,
|
slug: entryVideoJoin.slug,
|
||||||
entryPk: entryVideoJoin.entry,
|
entryPk: entryVideoJoin.entryPk,
|
||||||
});
|
});
|
||||||
|
|
||||||
return retEntries.map((entry) => ({
|
return retEntries.map((entry) => ({
|
||||||
|
@ -48,7 +48,7 @@ export const insertStudios = async (seed: SeedStudio[], showPk: number) => {
|
|||||||
|
|
||||||
await tx
|
await tx
|
||||||
.insert(showStudioJoin)
|
.insert(showStudioJoin)
|
||||||
.values(ret.map((studio) => ({ show: showPk, studio: studio.pk })))
|
.values(ret.map((studio) => ({ showPk: showPk, studioPk: studio.pk })))
|
||||||
.onConflictDoNothing();
|
.onConflictDoNothing();
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { StaticDecode } from "@sinclair/typebox";
|
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 } from "~/db/schema";
|
import { showTranslations, shows, studioTranslations } from "~/db/schema";
|
||||||
import { getColumns, sqlarr } from "~/db/utils";
|
import { getColumns, 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";
|
||||||
@ -12,6 +12,7 @@ import {
|
|||||||
Sort,
|
Sort,
|
||||||
isUuid,
|
isUuid,
|
||||||
keysetPaginate,
|
keysetPaginate,
|
||||||
|
selectTranslationQuery,
|
||||||
sortToSql,
|
sortToSql,
|
||||||
} from "~/models/utils";
|
} from "~/models/utils";
|
||||||
|
|
||||||
@ -130,7 +131,7 @@ export async function getShow(
|
|||||||
}: {
|
}: {
|
||||||
languages: string[];
|
languages: string[];
|
||||||
preferOriginal: boolean | undefined;
|
preferOriginal: boolean | undefined;
|
||||||
relations: ("translations" | "videos")[];
|
relations: ("translations" | "studios" | "videos")[];
|
||||||
filters: SQL | undefined;
|
filters: SQL | undefined;
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
@ -141,18 +142,7 @@ export async function getShow(
|
|||||||
},
|
},
|
||||||
where: and(isUuid(id) ? eq(shows.id, id) : eq(shows.slug, id), filters),
|
where: and(isUuid(id) ? eq(shows.id, id) : eq(shows.slug, id), filters),
|
||||||
with: {
|
with: {
|
||||||
selectedTranslation: {
|
selectedTranslation: selectTranslationQuery(showTranslations, languages),
|
||||||
columns: {
|
|
||||||
pk: false,
|
|
||||||
},
|
|
||||||
where: !languages.includes("*")
|
|
||||||
? eq(showTranslations.language, sql`any(${sqlarr(languages)})`)
|
|
||||||
: undefined,
|
|
||||||
orderBy: [
|
|
||||||
sql`array_position(${sqlarr(languages)}, ${showTranslations.language})`,
|
|
||||||
],
|
|
||||||
limit: 1,
|
|
||||||
},
|
|
||||||
originalTranslation: {
|
originalTranslation: {
|
||||||
columns: {
|
columns: {
|
||||||
poster: true,
|
poster: true,
|
||||||
@ -175,6 +165,23 @@ export async function getShow(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
...(relations.includes("studios") && {
|
||||||
|
studios: {
|
||||||
|
with: {
|
||||||
|
studio: {
|
||||||
|
columns: {
|
||||||
|
pk: false,
|
||||||
|
},
|
||||||
|
with: {
|
||||||
|
selectedTranslation: selectTranslationQuery(
|
||||||
|
studioTranslations,
|
||||||
|
languages,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (!ret) return null;
|
if (!ret) return null;
|
||||||
@ -198,6 +205,12 @@ export async function getShow(
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
|
...(ret.studios && {
|
||||||
|
studios: ret.studios.map((x: any) => ({
|
||||||
|
...x.studio,
|
||||||
|
...x.studio.selectedTranslation[0],
|
||||||
|
})),
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
return { show, language: translation.language };
|
return { show, language: translation.language };
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ export const movies = new Elysia({ prefix: "/movies", tags: ["movies"] })
|
|||||||
preferOriginal: t.Optional(
|
preferOriginal: t.Optional(
|
||||||
t.Boolean({ description: desc.preferOriginal }),
|
t.Boolean({ description: desc.preferOriginal }),
|
||||||
),
|
),
|
||||||
with: t.Array(t.UnionEnum(["translations", "videos"]), {
|
with: t.Array(t.UnionEnum(["translations", "studios", "videos"]), {
|
||||||
default: [],
|
default: [],
|
||||||
description: "Include related resources in the response.",
|
description: "Include related resources in the response.",
|
||||||
}),
|
}),
|
||||||
|
@ -65,7 +65,7 @@ export const series = new Elysia({ prefix: "/series", tags: ["series"] })
|
|||||||
preferOriginal: t.Optional(
|
preferOriginal: t.Optional(
|
||||||
t.Boolean({ description: desc.preferOriginal }),
|
t.Boolean({ description: desc.preferOriginal }),
|
||||||
),
|
),
|
||||||
with: t.Array(t.UnionEnum(["translations"]), {
|
with: t.Array(t.UnionEnum(["translations", "studios"]), {
|
||||||
default: [],
|
default: [],
|
||||||
description: "Include related resources in the response.",
|
description: "Include related resources in the response.",
|
||||||
}),
|
}),
|
||||||
|
@ -22,6 +22,7 @@ import {
|
|||||||
isUuid,
|
isUuid,
|
||||||
keysetPaginate,
|
keysetPaginate,
|
||||||
processLanguages,
|
processLanguages,
|
||||||
|
selectTranslationQuery,
|
||||||
sortToSql,
|
sortToSql,
|
||||||
} from "~/models/utils";
|
} from "~/models/utils";
|
||||||
import { desc } from "~/models/utils/descriptions";
|
import { desc } from "~/models/utils/descriptions";
|
||||||
@ -47,16 +48,10 @@ export const studiosH = new Elysia({ prefix: "/studios", tags: ["studios"] })
|
|||||||
const ret = await db.query.studios.findFirst({
|
const ret = await db.query.studios.findFirst({
|
||||||
where: isUuid(id) ? eq(studios.id, id) : eq(studios.slug, id),
|
where: isUuid(id) ? eq(studios.id, id) : eq(studios.slug, id),
|
||||||
with: {
|
with: {
|
||||||
selectedTranslation: {
|
selectedTranslation: selectTranslationQuery(
|
||||||
columns: { pk: false },
|
studioTranslations,
|
||||||
where: !languages.includes("*")
|
langs,
|
||||||
? eq(studioTranslations.language, sql`any(${sqlarr(langs)})`)
|
),
|
||||||
: undefined,
|
|
||||||
orderBy: [
|
|
||||||
sql`array_position(${sqlarr(langs)}, ${studioTranslations.language})`,
|
|
||||||
],
|
|
||||||
limit: 1,
|
|
||||||
},
|
|
||||||
...(relations.includes("translations") && {
|
...(relations.includes("translations") && {
|
||||||
translations: {
|
translations: {
|
||||||
columns: {
|
columns: {
|
||||||
@ -150,7 +145,7 @@ export const studiosH = new Elysia({ prefix: "/studios", tags: ["studios"] })
|
|||||||
.get(
|
.get(
|
||||||
"",
|
"",
|
||||||
async ({
|
async ({
|
||||||
query: { limit, after, query, sort, filter },
|
query: { limit, after, query, sort },
|
||||||
headers: { "accept-language": languages },
|
headers: { "accept-language": languages },
|
||||||
request: { url },
|
request: { url },
|
||||||
}) => {
|
}) => {
|
||||||
@ -271,8 +266,8 @@ export const studiosH = new Elysia({ prefix: "/studios", tags: ["studios"] })
|
|||||||
.from(showStudioJoin)
|
.from(showStudioJoin)
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(showStudioJoin.studio, studio.pk),
|
eq(showStudioJoin.studioPk, studio.pk),
|
||||||
eq(showStudioJoin.show, shows.pk),
|
eq(showStudioJoin.showPk, shows.pk),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -331,8 +326,8 @@ export const studiosH = new Elysia({ prefix: "/studios", tags: ["studios"] })
|
|||||||
.from(showStudioJoin)
|
.from(showStudioJoin)
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(showStudioJoin.studio, studio.pk),
|
eq(showStudioJoin.studioPk, studio.pk),
|
||||||
eq(showStudioJoin.show, shows.pk),
|
eq(showStudioJoin.showPk, shows.pk),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -391,8 +386,8 @@ export const studiosH = new Elysia({ prefix: "/studios", tags: ["studios"] })
|
|||||||
.from(showStudioJoin)
|
.from(showStudioJoin)
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(showStudioJoin.studio, studio.pk),
|
eq(showStudioJoin.studioPk, studio.pk),
|
||||||
eq(showStudioJoin.show, shows.pk),
|
eq(showStudioJoin.showPk, shows.pk),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -42,78 +42,77 @@ export const videosH = new Elysia({ prefix: "/videos", tags: ["videos"] })
|
|||||||
return error(201, oldRet);
|
return error(201, oldRet);
|
||||||
|
|
||||||
// TODO: this is a huge untested wip
|
// TODO: this is a huge untested wip
|
||||||
// biome-ignore lint/correctness/noUnreachable: leave me alone
|
// const vidsI = db.$with("vidsI").as(
|
||||||
const vidsI = db.$with("vidsI").as(
|
// db.insert(videos).values(body).onConflictDoNothing().returning({
|
||||||
db.insert(videos).values(body).onConflictDoNothing().returning({
|
// pk: videos.pk,
|
||||||
pk: videos.pk,
|
// id: videos.id,
|
||||||
id: videos.id,
|
// path: videos.path,
|
||||||
path: videos.path,
|
// guess: videos.guess,
|
||||||
guess: videos.guess,
|
// }),
|
||||||
}),
|
// );
|
||||||
);
|
//
|
||||||
|
// const findEntriesQ = db
|
||||||
const findEntriesQ = db
|
// .select({
|
||||||
.select({
|
// guess: videos.guess,
|
||||||
guess: videos.guess,
|
// entryPk: entries.pk,
|
||||||
entryPk: entries.pk,
|
// showSlug: shows.slug,
|
||||||
showSlug: shows.slug,
|
// // TODO: handle extras here
|
||||||
// TODO: handle extras here
|
// // guessit can't know if an episode is a special or not. treat specials like a normal episode.
|
||||||
// guessit can't know if an episode is a special or not. treat specials like a normal episode.
|
// kind: sql`
|
||||||
kind: sql`
|
// case when ${entries.kind} = 'movie' then 'movie' else 'episode' end
|
||||||
case when ${entries.kind} = 'movie' then 'movie' else 'episode' end
|
// `.as("kind"),
|
||||||
`.as("kind"),
|
// season: entries.seasonNumber,
|
||||||
season: entries.seasonNumber,
|
// episode: entries.episodeNumber,
|
||||||
episode: entries.episodeNumber,
|
// })
|
||||||
})
|
// .from(entries)
|
||||||
.from(entries)
|
// .leftJoin(entryVideoJoin, eq(entryVideoJoin.entry, entries.pk))
|
||||||
.leftJoin(entryVideoJoin, eq(entryVideoJoin.entry, entries.pk))
|
// .leftJoin(videos, eq(videos.pk, entryVideoJoin.video))
|
||||||
.leftJoin(videos, eq(videos.pk, entryVideoJoin.video))
|
// .leftJoin(shows, eq(shows.pk, entries.showPk))
|
||||||
.leftJoin(shows, eq(shows.pk, entries.showPk))
|
// .as("find_entries");
|
||||||
.as("find_entries");
|
//
|
||||||
|
// const hasRenderingQ = db
|
||||||
const hasRenderingQ = db
|
// .select()
|
||||||
.select()
|
// .from(entryVideoJoin)
|
||||||
.from(entryVideoJoin)
|
// .where(eq(entryVideoJoin.entry, findEntriesQ.entryPk));
|
||||||
.where(eq(entryVideoJoin.entry, findEntriesQ.entryPk));
|
//
|
||||||
|
// const ret = await db
|
||||||
const ret = await db
|
// .with(vidsI)
|
||||||
.with(vidsI)
|
// .insert(entryVideoJoin)
|
||||||
.insert(entryVideoJoin)
|
// .select(
|
||||||
.select(
|
// db
|
||||||
db
|
// .select({
|
||||||
.select({
|
// entry: findEntriesQ.entryPk,
|
||||||
entry: findEntriesQ.entryPk,
|
// video: vidsI.pk,
|
||||||
video: vidsI.pk,
|
// slug: computeVideoSlug(
|
||||||
slug: computeVideoSlug(
|
// findEntriesQ.showSlug,
|
||||||
findEntriesQ.showSlug,
|
// sql`exists(${hasRenderingQ})`,
|
||||||
sql`exists(${hasRenderingQ})`,
|
// ),
|
||||||
),
|
// })
|
||||||
})
|
// .from(vidsI)
|
||||||
.from(vidsI)
|
// .leftJoin(
|
||||||
.leftJoin(
|
// findEntriesQ,
|
||||||
findEntriesQ,
|
// and(
|
||||||
and(
|
// eq(
|
||||||
eq(
|
// sql`${findEntriesQ.guess}->'title'`,
|
||||||
sql`${findEntriesQ.guess}->'title'`,
|
// sql`${vidsI.guess}->'title'`,
|
||||||
sql`${vidsI.guess}->'title'`,
|
// ),
|
||||||
),
|
// // TODO: find if @> with a jsonb created on the fly is
|
||||||
// TODO: find if @> with a jsonb created on the fly is
|
// // better than multiples checks
|
||||||
// better than multiples checks
|
// sql`${vidsI.guess} @> {"kind": }::jsonb`,
|
||||||
sql`${vidsI.guess} @> {"kind": }::jsonb`,
|
// inArray(findEntriesQ.kind, sql`${vidsI.guess}->'type'`),
|
||||||
inArray(findEntriesQ.kind, sql`${vidsI.guess}->'type'`),
|
// inArray(findEntriesQ.episode, sql`${vidsI.guess}->'episode'`),
|
||||||
inArray(findEntriesQ.episode, sql`${vidsI.guess}->'episode'`),
|
// inArray(findEntriesQ.season, sql`${vidsI.guess}->'season'`),
|
||||||
inArray(findEntriesQ.season, sql`${vidsI.guess}->'season'`),
|
// ),
|
||||||
),
|
// ),
|
||||||
),
|
// )
|
||||||
)
|
// .onConflictDoNothing()
|
||||||
.onConflictDoNothing()
|
// .returning({
|
||||||
.returning({
|
// slug: entryVideoJoin.slug,
|
||||||
slug: entryVideoJoin.slug,
|
// entryPk: entryVideoJoin.entry,
|
||||||
entryPk: entryVideoJoin.entry,
|
// id: vidsI.id,
|
||||||
id: vidsI.id,
|
// path: vidsI.path,
|
||||||
path: vidsI.path,
|
// });
|
||||||
});
|
// return error(201, ret as any);
|
||||||
return error(201, ret as any);
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
body: t.Array(SeedVideo),
|
body: t.Array(SeedVideo),
|
||||||
|
@ -5,7 +5,6 @@ import {
|
|||||||
date,
|
date,
|
||||||
index,
|
index,
|
||||||
integer,
|
integer,
|
||||||
jsonb,
|
|
||||||
primaryKey,
|
primaryKey,
|
||||||
smallint,
|
smallint,
|
||||||
text,
|
text,
|
||||||
@ -15,7 +14,8 @@ import {
|
|||||||
} from "drizzle-orm/pg-core";
|
} from "drizzle-orm/pg-core";
|
||||||
import { entries } from "./entries";
|
import { entries } from "./entries";
|
||||||
import { seasons } from "./seasons";
|
import { seasons } from "./seasons";
|
||||||
import { image, language, schema } from "./utils";
|
import { showStudioJoin } from "./studios";
|
||||||
|
import { externalid, image, language, schema } from "./utils";
|
||||||
|
|
||||||
export const showKind = schema.enum("show_kind", [
|
export const showKind = schema.enum("show_kind", [
|
||||||
"serie",
|
"serie",
|
||||||
@ -54,20 +54,6 @@ export const genres = schema.enum("genres", [
|
|||||||
"talk",
|
"talk",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const externalid = () =>
|
|
||||||
jsonb()
|
|
||||||
.$type<
|
|
||||||
Record<
|
|
||||||
string,
|
|
||||||
{
|
|
||||||
dataId: string;
|
|
||||||
link: string | null;
|
|
||||||
}
|
|
||||||
>
|
|
||||||
>()
|
|
||||||
.notNull()
|
|
||||||
.default({});
|
|
||||||
|
|
||||||
export const shows = schema.table(
|
export const shows = schema.table(
|
||||||
"shows",
|
"shows",
|
||||||
{
|
{
|
||||||
@ -144,6 +130,7 @@ export const showsRelations = relations(shows, ({ many, one }) => ({
|
|||||||
}),
|
}),
|
||||||
entries: many(entries, { relationName: "show_entries" }),
|
entries: many(entries, { relationName: "show_entries" }),
|
||||||
seasons: many(seasons, { relationName: "show_seasons" }),
|
seasons: many(seasons, { relationName: "show_seasons" }),
|
||||||
|
studios: many(showStudioJoin, { relationName: "ssj_show" }),
|
||||||
}));
|
}));
|
||||||
export const showsTrRelations = relations(showTranslations, ({ one }) => ({
|
export const showsTrRelations = relations(showTranslations, ({ one }) => ({
|
||||||
show: one(shows, {
|
show: one(shows, {
|
||||||
|
@ -8,8 +8,8 @@ import {
|
|||||||
uuid,
|
uuid,
|
||||||
varchar,
|
varchar,
|
||||||
} from "drizzle-orm/pg-core";
|
} from "drizzle-orm/pg-core";
|
||||||
import { externalid, shows } from "./shows";
|
import { shows } from "./shows";
|
||||||
import { image, language, schema } from "./utils";
|
import { externalid, image, language, schema } from "./utils";
|
||||||
|
|
||||||
export const studios = schema.table("studios", {
|
export const studios = schema.table("studios", {
|
||||||
pk: integer().primaryKey().generatedAlwaysAsIdentity(),
|
pk: integer().primaryKey().generatedAlwaysAsIdentity(),
|
||||||
@ -44,14 +44,14 @@ export const studioTranslations = schema.table(
|
|||||||
export const showStudioJoin = schema.table(
|
export const showStudioJoin = schema.table(
|
||||||
"show_studio_join",
|
"show_studio_join",
|
||||||
{
|
{
|
||||||
show: integer()
|
showPk: integer()
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => shows.pk, { onDelete: "cascade" }),
|
.references(() => shows.pk, { onDelete: "cascade" }),
|
||||||
studio: integer()
|
studioPk: integer()
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => studios.pk, { onDelete: "cascade" }),
|
.references(() => studios.pk, { onDelete: "cascade" }),
|
||||||
},
|
},
|
||||||
(t) => [primaryKey({ columns: [t.show, t.studio] })],
|
(t) => [primaryKey({ columns: [t.showPk, t.studioPk] })],
|
||||||
);
|
);
|
||||||
|
|
||||||
export const studioRelations = relations(studios, ({ many }) => ({
|
export const studioRelations = relations(studios, ({ many }) => ({
|
||||||
@ -61,7 +61,7 @@ export const studioRelations = relations(studios, ({ many }) => ({
|
|||||||
selectedTranslation: many(studioTranslations, {
|
selectedTranslation: many(studioTranslations, {
|
||||||
relationName: "studio_selected_translation",
|
relationName: "studio_selected_translation",
|
||||||
}),
|
}),
|
||||||
showsJoin: many(showStudioJoin, { relationName: "show_studios" }),
|
showsJoin: many(showStudioJoin, { relationName: "ssj_studio" }),
|
||||||
}));
|
}));
|
||||||
export const studioTrRelations = relations(studioTranslations, ({ one }) => ({
|
export const studioTrRelations = relations(studioTranslations, ({ one }) => ({
|
||||||
studio: one(studios, {
|
studio: one(studios, {
|
||||||
@ -78,12 +78,12 @@ export const studioTrRelations = relations(studioTranslations, ({ one }) => ({
|
|||||||
export const ssjRelations = relations(showStudioJoin, ({ one }) => ({
|
export const ssjRelations = relations(showStudioJoin, ({ one }) => ({
|
||||||
show: one(shows, {
|
show: one(shows, {
|
||||||
relationName: "ssj_show",
|
relationName: "ssj_show",
|
||||||
fields: [showStudioJoin.show],
|
fields: [showStudioJoin.showPk],
|
||||||
references: [shows.pk],
|
references: [shows.pk],
|
||||||
}),
|
}),
|
||||||
studio: one(studios, {
|
studio: one(studios, {
|
||||||
relationName: "ssj_studio",
|
relationName: "ssj_studio",
|
||||||
fields: [showStudioJoin.studio],
|
fields: [showStudioJoin.studioPk],
|
||||||
references: [studios.pk],
|
references: [studios.pk],
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
@ -6,3 +6,18 @@ export const language = () => varchar({ length: 255 });
|
|||||||
|
|
||||||
export const image = () =>
|
export const image = () =>
|
||||||
jsonb().$type<{ id: string; source: string; blurhash: string }>();
|
jsonb().$type<{ id: string; source: string; blurhash: string }>();
|
||||||
|
|
||||||
|
export const externalid = () =>
|
||||||
|
jsonb()
|
||||||
|
.$type<
|
||||||
|
Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
dataId: string;
|
||||||
|
link: string | null;
|
||||||
|
}
|
||||||
|
>
|
||||||
|
>()
|
||||||
|
.notNull()
|
||||||
|
.default({});
|
||||||
|
|
||||||
|
@ -39,15 +39,15 @@ export const videos = schema.table(
|
|||||||
export const entryVideoJoin = schema.table(
|
export const entryVideoJoin = schema.table(
|
||||||
"entry_video_join",
|
"entry_video_join",
|
||||||
{
|
{
|
||||||
entry: integer()
|
entryPk: integer()
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => entries.pk, { onDelete: "cascade" }),
|
.references(() => entries.pk, { onDelete: "cascade" }),
|
||||||
video: integer()
|
videoPk: integer()
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => videos.pk, { onDelete: "cascade" }),
|
.references(() => videos.pk, { onDelete: "cascade" }),
|
||||||
slug: varchar({ length: 255 }).notNull().unique(),
|
slug: varchar({ length: 255 }).notNull().unique(),
|
||||||
},
|
},
|
||||||
(t) => [primaryKey({ columns: [t.entry, t.video] })],
|
(t) => [primaryKey({ columns: [t.entryPk, t.videoPk] })],
|
||||||
);
|
);
|
||||||
|
|
||||||
export const videosRelations = relations(videos, ({ many }) => ({
|
export const videosRelations = relations(videos, ({ many }) => ({
|
||||||
@ -59,12 +59,12 @@ export const videosRelations = relations(videos, ({ many }) => ({
|
|||||||
export const evjRelations = relations(entryVideoJoin, ({ one }) => ({
|
export const evjRelations = relations(entryVideoJoin, ({ one }) => ({
|
||||||
video: one(videos, {
|
video: one(videos, {
|
||||||
relationName: "evj_video",
|
relationName: "evj_video",
|
||||||
fields: [entryVideoJoin.video],
|
fields: [entryVideoJoin.videoPk],
|
||||||
references: [videos.pk],
|
references: [videos.pk],
|
||||||
}),
|
}),
|
||||||
entry: one(entries, {
|
entry: one(entries, {
|
||||||
relationName: "evj_entry",
|
relationName: "evj_entry",
|
||||||
fields: [entryVideoJoin.entry],
|
fields: [entryVideoJoin.entryPk],
|
||||||
references: [entries.pk],
|
references: [entries.pk],
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
@ -2,7 +2,7 @@ import { t } from "elysia";
|
|||||||
import type { Prettify } from "~/utils";
|
import type { Prettify } from "~/utils";
|
||||||
import { SeedCollection } from "./collections";
|
import { SeedCollection } from "./collections";
|
||||||
import { bubble, bubbleImages, registerExamples } from "./examples";
|
import { bubble, bubbleImages, registerExamples } from "./examples";
|
||||||
import { SeedStudio } from "./studio";
|
import { SeedStudio, Studio } from "./studio";
|
||||||
import {
|
import {
|
||||||
DbMetadata,
|
DbMetadata,
|
||||||
ExternalId,
|
ExternalId,
|
||||||
@ -68,6 +68,7 @@ export const FullMovie = t.Intersect([
|
|||||||
t.Object({
|
t.Object({
|
||||||
translations: t.Optional(TranslationRecord(MovieTranslation)),
|
translations: t.Optional(TranslationRecord(MovieTranslation)),
|
||||||
videos: t.Optional(t.Array(Video)),
|
videos: t.Optional(t.Array(Video)),
|
||||||
|
studios: t.Optional(t.Array(Studio)),
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
export type FullMovie = Prettify<typeof FullMovie.static>;
|
export type FullMovie = Prettify<typeof FullMovie.static>;
|
||||||
|
@ -4,7 +4,7 @@ import { SeedCollection } from "./collections";
|
|||||||
import { SeedEntry, SeedExtra } from "./entry";
|
import { SeedEntry, SeedExtra } from "./entry";
|
||||||
import { bubbleImages, madeInAbyss, registerExamples } from "./examples";
|
import { bubbleImages, madeInAbyss, registerExamples } from "./examples";
|
||||||
import { SeedSeason } from "./season";
|
import { SeedSeason } from "./season";
|
||||||
import { SeedStudio } from "./studio";
|
import { SeedStudio, Studio } from "./studio";
|
||||||
import {
|
import {
|
||||||
DbMetadata,
|
DbMetadata,
|
||||||
ExternalId,
|
ExternalId,
|
||||||
@ -76,6 +76,7 @@ export const FullSerie = t.Intersect([
|
|||||||
Serie,
|
Serie,
|
||||||
t.Object({
|
t.Object({
|
||||||
translations: t.Optional(TranslationRecord(SerieTranslation)),
|
translations: t.Optional(TranslationRecord(SerieTranslation)),
|
||||||
|
studios: t.Optional(t.Array(Studio)),
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
export type FullMovie = Prettify<typeof FullSerie.static>;
|
export type FullMovie = Prettify<typeof FullSerie.static>;
|
||||||
|
@ -4,7 +4,9 @@ import {
|
|||||||
type TSchema,
|
type TSchema,
|
||||||
type TString,
|
type TString,
|
||||||
} from "@sinclair/typebox";
|
} from "@sinclair/typebox";
|
||||||
|
import { type Column, type Table, eq, sql } from "drizzle-orm";
|
||||||
import { t } from "elysia";
|
import { t } from "elysia";
|
||||||
|
import { sqlarr } from "~/db/utils";
|
||||||
import { comment } from "../../utils";
|
import { comment } from "../../utils";
|
||||||
import { KErrorT } from "../error";
|
import { KErrorT } from "../error";
|
||||||
|
|
||||||
@ -106,3 +108,19 @@ export const AcceptLanguage = ({
|
|||||||
`
|
`
|
||||||
: ""),
|
: ""),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const selectTranslationQuery = (
|
||||||
|
translationTable: Table & { language: Column },
|
||||||
|
languages: string[],
|
||||||
|
) => ({
|
||||||
|
columns: {
|
||||||
|
pk: false,
|
||||||
|
} as const,
|
||||||
|
where: !languages.includes("*")
|
||||||
|
? eq(translationTable.language, sql`any(${sqlarr(languages)})`)
|
||||||
|
: undefined,
|
||||||
|
orderBy: [
|
||||||
|
sql`array_position(${sqlarr(languages)}, ${translationTable.language})`,
|
||||||
|
],
|
||||||
|
limit: 1,
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user