Type value lists

This commit is contained in:
Zoe Roux 2025-05-01 19:13:13 +02:00
parent 07a41bb175
commit 060c4d74b4
No known key found for this signature in database
4 changed files with 53 additions and 28 deletions

View File

@ -167,8 +167,14 @@ export const historyH = new Elysia({ tags: ["profiles"] })
async ({ body, jwt: { sub }, error }) => {
const profilePk = await getOrCreateProfile(sub);
const vals = values(
const hist = values(
body.map((x) => ({ ...x, entryUseId: isUuid(x.entry) })),
{
percent: "integer",
time: "integer",
playedDate: "timestamptz",
videoId: "uuid",
},
).as("hist");
const valEqEntries = sql`
case
@ -185,13 +191,13 @@ export const historyH = new Elysia({ tags: ["profiles"] })
profilePk: sql`${profilePk}`,
entryPk: entries.pk,
videoPk: videos.pk,
percent: sql`hist.percent::integer`,
time: sql`hist.time::integer`,
playedDate: sql`hist.playedDate::timestamptz`,
percent: sql`hist.percent`,
time: sql`hist.time`,
playedDate: sql`hist.playedDate`,
})
.from(vals)
.from(hist)
.innerJoin(entries, valEqEntries)
.leftJoin(videos, eq(videos.id, sql`hist.videoId::uuid`)),
.leftJoin(videos, eq(videos.id, sql`hist.videoId`)),
)
.returning({ pk: history.pk });
@ -249,7 +255,7 @@ export const historyH = new Elysia({ tags: ["profiles"] })
status: sql`
case
when
hist.percent::integer >= 95
hist.percent >= 95
and ${nextEntryQ.pk} is null
then 'completed'::watchlist_status
else 'watching'::watchlist_status
@ -257,30 +263,30 @@ export const historyH = new Elysia({ tags: ["profiles"] })
`,
seenCount: sql`
case
when ${entries.kind} = 'movie' then hist.percent::integer
when hist.percent::integer >= 95 then 1
when ${entries.kind} = 'movie' then hist.percent
when hist.percent >= 95 then 1
else 0
end
`,
nextEntry: sql`
case
when hist.percent::integer >= 95 then ${nextEntryQ.pk}
when hist.percent >= 95 then ${nextEntryQ.pk}
else ${entries.pk}
end
`,
score: sql`null`,
startedAt: sql`hist.playedDate::timestamptz`,
lastPlayedAt: sql`hist.playedDate::timestamptz`,
startedAt: sql`hist.playedDate`,
lastPlayedAt: sql`hist.playedDate`,
completedAt: sql`
case
when ${nextEntryQ.pk} is null then hist.playedDate::timestamptz
when ${nextEntryQ.pk} is null then hist.playedDate
else null
end
`,
// see https://github.com/drizzle-team/drizzle-orm/issues/3608
updatedAt: sql`now()`,
})
.from(vals)
.from(hist)
.leftJoin(entries, valEqEntries)
.leftJoinLateral(nextEntryQ, sql`true`),
)

View File

@ -167,15 +167,21 @@ export const insertEntries = async (
.select(
db
.select({
entryPk: sql<number>`vids.entryPk::integer`.as("entry"),
entryPk: sql<number>`vids.entryPk`.as("entry"),
videoPk: videos.pk,
slug: computeVideoSlug(
sql`vids.entrySlug::text`,
sql`vids.needRendering::boolean`,
sql`vids.entrySlug`,
sql`vids.needRendering`,
),
})
.from(values(vids).as("vids"))
.innerJoin(videos, eq(videos.id, sql`vids.videoId::uuid`)),
.from(
values(vids, {
entryPk: "integer",
needRendering: "boolean",
videoId: "uuid",
}).as("vids"),
)
.innerJoin(videos, eq(videos.id, sql`vids.videoId`)),
)
.onConflictDoNothing()
.returning({

View File

@ -230,14 +230,20 @@ export const videosH = new Elysia({ prefix: "/videos", tags: ["videos"] })
.select(
db
.select({
entry: entries.pk,
video: sql`j.video`,
entryPk: entriesQ.pk,
videoPk: sql`j.video`,
slug: computeVideoSlug(
entriesQ.showSlug,
sql`j.needRendering::boolean || exists(${hasRenderingQ})`,
sql`j.needRendering || exists(${hasRenderingQ})`,
),
})
.from(values(vidEntries).as("j"))
.from(
values(vidEntries, {
video: "integer",
needRendering: "boolean",
entry: "jsonb",
}).as("j"),
)
.innerJoin(
entriesQ,
or(

View File

@ -74,15 +74,22 @@ export function sqlarr(array: unknown[]) {
}
// See https://github.com/drizzle-team/drizzle-orm/issues/4044
// TODO: type values (everything is a `text` for now)
export function values(items: Record<string, unknown>[]) {
if (items[0] === undefined) throw new Error("Invalid values, expecting at least one items")
const [firstProp, ...props] = Object.keys(items[0]);
export function values<K extends string>(
items: Record<K, unknown>[],
typeInfo: Partial<Record<K, string>> = {},
) {
if (items[0] === undefined)
throw new Error("Invalid values, expecting at least one items");
const [firstProp, ...props] = Object.keys(items[0]) as K[];
const values = items
.map((x) => {
.map((x, i) => {
let ret = sql`(${x[firstProp]}`;
if (i === 0 && typeInfo[firstProp])
ret = sql`${ret}::${sql.raw(typeInfo[firstProp])}`;
for (const val of props) {
ret = sql`${ret}, ${x[val]}`;
if (i === 0 && typeInfo[val])
ret = sql`${ret}::${sql.raw(typeInfo[val])}`;
}
return sql`${ret})`;
})