Fix prev/next generation

This commit is contained in:
Zoe Roux 2025-01-07 17:28:43 +01:00
parent 641ce4237e
commit 1389abb946
No known key found for this signature in database
3 changed files with 22 additions and 9 deletions

View File

@ -44,7 +44,8 @@ const getTranslationQuery = (languages: string[]) => {
return [query, col] as const;
};
const { pk: _, kind, startAir, endAir, ...moviesCol } = getColumns(shows);
// we keep the pk for after handling. it will be removed by elysia's validators after.
const { kind, startAir, endAir, ...moviesCol } = getColumns(shows);
const movieFilters: FilterDef = {
genres: {
@ -181,7 +182,7 @@ export const movies = new Elysia({ prefix: "/movies", tags: ["movies"] })
)
.limit(limit);
return createPage(items, { url, sort });
return createPage(items, { url, sort, limit });
},
{
detail: { description: "Get all movies" },
@ -201,7 +202,6 @@ export const movies = new Elysia({ prefix: "/movies", tags: ["movies"] })
}),
after: t.Optional(
t.String({
format: "byte",
description: comment`
Id of the cursor in the pagination.
You can ignore this and only use the prev/next field in the response.

View File

@ -58,5 +58,8 @@ export const generateAfter = (
...sort.map((by) => cursor[by.key]),
cursor.pk,
];
return Buffer.from(JSON.stringify(ret), "utf-8").toString("base64");
return Buffer.from(JSON.stringify(ret), "utf-8").toString("base64url");
};
const reverseStart = Buffer.from("[true,", "utf-8").toString("base64url");
export const isReverse = (x: string) => x.startsWith(reverseStart);

View File

@ -1,7 +1,7 @@
import type { ObjectOptions } from "@sinclair/typebox";
import { t, type TSchema } from "elysia";
import type { Sort } from "./sort";
import { generateAfter } from "./keyset-paginate";
import { generateAfter, isReverse } from "./keyset-paginate";
export const Page = <T extends TSchema>(schema: T, options?: ObjectOptions) =>
t.Object(
@ -16,17 +16,27 @@ export const Page = <T extends TSchema>(schema: T, options?: ObjectOptions) =>
export const createPage = <T>(
items: T[],
{ url, sort }: { url: string; sort: Sort<any, any> },
{ url, sort, limit }: { url: string; sort: Sort<any, any>; limit: number },
) => {
let prev: string | null = null;
let next: string | null = null;
const uri = new URL(url);
if (uri.searchParams.has("after")) {
const uri = new URL(url);
const after = uri.searchParams.get("after");
const reverse = after && isReverse(after) ? 1 : 0;
const has = [
// prev
items.length > 0 && after,
// next
items.length === limit && limit > 0,
];
if (has[0 + reverse]) {
uri.searchParams.set("after", generateAfter(items[0], sort, true));
prev = uri.toString();
}
if (items.length) {
if (has[1 - reverse]) {
uri.searchParams.set("after", generateAfter(items[items.length - 1], sort));
next = uri.toString();
}