server/utils/timelines.ts

85 lines
2.9 KiB
TypeScript
Raw Normal View History

import type { db } from "@versia/kit/db";
import type { SQL } from "drizzle-orm";
2024-04-11 14:12:16 +02:00
import type {
Notification,
findManyNotifications,
} from "~/classes/functions/notification";
import type { Status, findManyNotes } from "~/classes/functions/status";
import type { UserType, findManyUsers } from "~/classes/functions/user";
import { config } from "~/packages/config-manager/index.ts";
2024-04-08 04:24:18 +02:00
export async function fetchTimeline<T extends UserType | Status | Notification>(
2024-04-08 05:28:18 +02:00
model:
| typeof findManyNotes
| typeof findManyUsers
2024-04-11 14:12:16 +02:00
| typeof findManyNotifications,
2024-04-08 05:28:18 +02:00
args:
| Parameters<typeof findManyNotes>[0]
| Parameters<typeof findManyUsers>[0]
| Parameters<typeof db.query.Notifications.findMany>[0],
2024-04-08 04:24:18 +02:00
req: Request,
userId?: string,
): Promise<{
link: string;
objects: T[];
}> {
2024-04-08 04:32:45 +02:00
// BEFORE: Before in a top-to-bottom order, so the most recent posts
// AFTER: After in a top-to-bottom order, so the oldest posts
2024-04-08 04:24:18 +02:00
// @ts-expect-error This is a hack to get around the fact that Prisma doesn't have a common base type for all models
const objects = (await model(args, userId)) as T[];
2024-04-08 04:24:18 +02:00
// Constuct HTTP Link header (next and prev) only if there are more statuses
2024-06-13 10:52:03 +02:00
const linkHeader: string[] = [];
const urlWithoutQuery = new URL(
new URL(req.url).pathname,
config.http.base_url,
).toString();
2024-04-08 04:24:18 +02:00
if (objects.length > 0) {
// Check if there are statuses before the first one
// @ts-expect-error This is a hack to get around the fact that Prisma doesn't have a common base type for all models
const objectsBefore = await model({
...args,
// @ts-expect-error this hack breaks typing :(
where: (object, { gt }): SQL | undefined =>
gt(object.id, objects[0].id),
limit: 1,
2024-04-08 04:24:18 +02:00
});
if (objectsBefore.length > 0) {
// Add prev link
linkHeader.push(
2024-04-11 15:52:44 +02:00
`<${urlWithoutQuery}?limit=${args?.limit ?? 20}&min_id=${
objects[0].id
}>; rel="prev"`,
2024-04-08 04:24:18 +02:00
);
}
if (objects.length >= Number(args?.limit ?? 20)) {
2024-04-08 04:24:18 +02:00
// Check if there are statuses after the last one
// @ts-expect-error hack again
const objectsAfter = await model({
...args,
// @ts-expect-error this hack breaks typing :(
where: (object, { lt }): SQL | undefined =>
lt(object.id, objects.at(-1)?.id),
limit: 1,
2024-04-08 04:24:18 +02:00
});
if (objectsAfter.length > 0) {
// Add next link
linkHeader.push(
2024-04-11 15:52:44 +02:00
`<${urlWithoutQuery}?limit=${args?.limit ?? 20}&max_id=${
objects.at(-1)?.id
}>; rel="next"`,
2024-04-08 04:24:18 +02:00
);
}
}
}
return {
link: linkHeader.join(", "),
objects,
};
}