mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Update watchlist when inserting into history
This commit is contained in:
parent
c0e00c0fd4
commit
69006478cb
@ -1,9 +1,22 @@
|
|||||||
import { and, eq, isNotNull, ne, not, or, sql } from "drizzle-orm";
|
import {
|
||||||
|
and,
|
||||||
|
count,
|
||||||
|
eq,
|
||||||
|
exists,
|
||||||
|
gt,
|
||||||
|
isNotNull,
|
||||||
|
ne,
|
||||||
|
not,
|
||||||
|
or,
|
||||||
|
sql,
|
||||||
|
} from "drizzle-orm";
|
||||||
|
import { alias } from "drizzle-orm/pg-core";
|
||||||
import Elysia, { t } from "elysia";
|
import Elysia, { t } from "elysia";
|
||||||
import { auth, getUserInfo } from "~/auth";
|
import { auth, getUserInfo } from "~/auth";
|
||||||
import { db } from "~/db";
|
import { db } from "~/db";
|
||||||
import { entries, history, profiles, videos } from "~/db/schema";
|
import { entries, history, profiles, shows, videos } from "~/db/schema";
|
||||||
import { values } from "~/db/utils";
|
import { watchlist } from "~/db/schema/watchlist";
|
||||||
|
import { coalesce, values } from "~/db/utils";
|
||||||
import { Entry } from "~/models/entry";
|
import { Entry } from "~/models/entry";
|
||||||
import { KError } from "~/models/error";
|
import { KError } from "~/models/error";
|
||||||
import { SeedHistory } from "~/models/history";
|
import { SeedHistory } from "~/models/history";
|
||||||
@ -165,6 +178,10 @@ export const historyH = new Elysia({ tags: ["profiles"] })
|
|||||||
async ({ body, jwt: { sub }, error }) => {
|
async ({ body, jwt: { sub }, error }) => {
|
||||||
const profilePk = await getOrCreateProfile(sub);
|
const profilePk = await getOrCreateProfile(sub);
|
||||||
|
|
||||||
|
const vals = values(
|
||||||
|
body.map((x) => ({ ...x, entryUseId: isUuid(x.entry) })),
|
||||||
|
).as("hist");
|
||||||
|
|
||||||
const rows = await db
|
const rows = await db
|
||||||
.insert(history)
|
.insert(history)
|
||||||
.select(
|
.select(
|
||||||
@ -177,11 +194,7 @@ export const historyH = new Elysia({ tags: ["profiles"] })
|
|||||||
time: sql`hist.time::integer`,
|
time: sql`hist.time::integer`,
|
||||||
playedDate: sql`hist.playedDate::timestamptz`,
|
playedDate: sql`hist.playedDate::timestamptz`,
|
||||||
})
|
})
|
||||||
.from(
|
.from(vals)
|
||||||
values(
|
|
||||||
body.map((x) => ({ ...x, entryUseId: isUuid(x.entry) })),
|
|
||||||
).as("hist"),
|
|
||||||
)
|
|
||||||
.innerJoin(
|
.innerJoin(
|
||||||
entries,
|
entries,
|
||||||
or(
|
or(
|
||||||
@ -198,6 +211,121 @@ export const historyH = new Elysia({ tags: ["profiles"] })
|
|||||||
.leftJoin(videos, eq(videos.id, sql`hist.videoId::uuid`)),
|
.leftJoin(videos, eq(videos.id, sql`hist.videoId::uuid`)),
|
||||||
)
|
)
|
||||||
.returning({ pk: history.pk });
|
.returning({ pk: history.pk });
|
||||||
|
|
||||||
|
// automatically update watchlist with this new info
|
||||||
|
|
||||||
|
const nextEntry = alias(entries, "next_entry");
|
||||||
|
const nextEntryQ = db
|
||||||
|
.select({
|
||||||
|
pk: nextEntry.pk,
|
||||||
|
})
|
||||||
|
.from(nextEntry)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(nextEntry.showPk, entries.showPk),
|
||||||
|
gt(nextEntry.order, entries.order),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.orderBy(nextEntry.showPk, entries.order)
|
||||||
|
.as("nextEntryQ");
|
||||||
|
|
||||||
|
const seenCountQ = db
|
||||||
|
.select({ c: count() })
|
||||||
|
.from(entries)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(entries.showPk, sql`excluded.show_pk`),
|
||||||
|
exists(
|
||||||
|
db
|
||||||
|
.select()
|
||||||
|
.from(history)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(history.profilePk, profilePk),
|
||||||
|
eq(history.entryPk, entries.pk),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.as("seenCountQ");
|
||||||
|
|
||||||
|
await db
|
||||||
|
.insert(watchlist)
|
||||||
|
.select(
|
||||||
|
db
|
||||||
|
.select({
|
||||||
|
profilePk: sql`${profilePk}`,
|
||||||
|
showPk: entries.showPk,
|
||||||
|
status: sql`
|
||||||
|
case
|
||||||
|
when
|
||||||
|
hist.progress >= 95
|
||||||
|
and ${nextEntryQ.pk} is null
|
||||||
|
then 'completed'::watchstatus
|
||||||
|
else 'watching'::watchstatus
|
||||||
|
end
|
||||||
|
`,
|
||||||
|
seenCount: sql`
|
||||||
|
case
|
||||||
|
when ${eq(entries.kind, "movie")} then hist.progress::number
|
||||||
|
when hist.progress >= 95 then 1
|
||||||
|
else 0
|
||||||
|
end
|
||||||
|
`,
|
||||||
|
nextEntry: nextEntryQ.pk,
|
||||||
|
score: sql`null`,
|
||||||
|
startedAt: sql`hist.playedDate::timestamptz`,
|
||||||
|
completedAt: sql`
|
||||||
|
case
|
||||||
|
when ${nextEntryQ.pk} is null then hist.playedDate::timestamptz
|
||||||
|
else null
|
||||||
|
end
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
.from(vals)
|
||||||
|
.leftJoin(
|
||||||
|
entries,
|
||||||
|
or(
|
||||||
|
and(
|
||||||
|
sql`hist.entryUseId::boolean`,
|
||||||
|
eq(entries.id, sql`hist.entry::uuid`),
|
||||||
|
),
|
||||||
|
and(
|
||||||
|
not(sql`hist.entryUseId::boolean`),
|
||||||
|
eq(entries.slug, sql`hist.entry`),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.leftLateralJoin(nextEntryQ, sql`true`),
|
||||||
|
)
|
||||||
|
.onConflictDoUpdate({
|
||||||
|
target: [watchlist.profilePk, watchlist.showPk],
|
||||||
|
set: {
|
||||||
|
status: sql`
|
||||||
|
case
|
||||||
|
when ${eq(sql`excluded.status`, "completed")} then excluded.status
|
||||||
|
when ${and(
|
||||||
|
ne(watchlist.status, "completed"),
|
||||||
|
ne(watchlist.status, "rewatching"),
|
||||||
|
)} then excluded.status
|
||||||
|
else ${watchlist.status}
|
||||||
|
end
|
||||||
|
`,
|
||||||
|
seenCount: sql`${seenCountQ.c}`,
|
||||||
|
nextEntry: sql`
|
||||||
|
case
|
||||||
|
when ${eq(watchlist.status, "completed")} then null
|
||||||
|
else excluded.nextEntry
|
||||||
|
end
|
||||||
|
`,
|
||||||
|
completedAt: coalesce(
|
||||||
|
watchlist.completedAt,
|
||||||
|
sql`excluded.completed_at`,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return error(201, { status: 201, inserted: rows.length });
|
return error(201, { status: 201, inserted: rows.length });
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
getEntries,
|
getEntries,
|
||||||
getHistory,
|
getHistory,
|
||||||
getNews,
|
getNews,
|
||||||
|
getWatchlist,
|
||||||
} from "tests/helpers";
|
} from "tests/helpers";
|
||||||
import { expectStatus } from "tests/utils";
|
import { expectStatus } from "tests/utils";
|
||||||
import { db } from "~/db";
|
import { db } from "~/db";
|
||||||
@ -127,23 +128,22 @@ describe("Set & get history", () => {
|
|||||||
|
|
||||||
// extras, unknowns
|
// extras, unknowns
|
||||||
|
|
||||||
// it("Update watchlist", async () => {
|
it("Update watchlist", async () => {
|
||||||
// const [r, b] = await setMovieStatus(bubble.slug, {
|
const [resp, body] = await getWatchlist("me", {});
|
||||||
// status: "rewatching",
|
expectStatus(resp, body).toBe(200);
|
||||||
// // we still need to specify all values
|
expect(body.items).toBeArrayOfSize(2);
|
||||||
// completedAt: "2024-12-21",
|
// watching items before completed ones
|
||||||
// score: 85,
|
expect(body.items[0].slug).toBe(madeInAbyss.slug);
|
||||||
// });
|
expect(body.items[0].watchStatus).toMatchObject({
|
||||||
// expectStatus(r, b).toBe(200);
|
status: "watching",
|
||||||
//
|
seenCount: 1,
|
||||||
// const [resp, body] = await getMovie(bubble.slug, {});
|
startedAt: "2025-02-01 00:00:00+00",
|
||||||
// expectStatus(resp, body).toBe(200);
|
});
|
||||||
// expect(body.slug).toBe(bubble.slug);
|
expect(body.items[1].slug).toBe(bubble.slug);
|
||||||
// expect(body.progress).toMatchObject({
|
expect(body.items[1].watchStatus).toMatchObject({
|
||||||
// status: "rewatching",
|
status: "completed",
|
||||||
// completedAt: "2024-12-21 00:00:00+00",
|
percent: 100,
|
||||||
// score: 85,
|
startedAt: "2025-02-02 00:00:00+00",
|
||||||
// percent: 0,
|
});
|
||||||
// });
|
});
|
||||||
// });
|
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user