Cursor pagination for the activity feed
Node · Node · advanced · greenfield
Adds cursor-based pagination to the activity feed: fetches limit+1 rows to detect a next page without a count query, returns the page and the next cursor. Typed against the row shape.
Feed is ordered by a monotonic id descending; the client passes back the nextCursor verbatim.
Requirements
- Return up to `limit` activity items after the given `cursor` (an opaque id), newest first.
- Include a `nextCursor` when more items exist, and `null` when the page is the last one.
- The presence check must not require a second query for the common case; `limit` is a positive integer.
Files touched
- src/feed/paginate.ts
--- src/feed/paginate.ts
+import { db } from '../lib/db';
+
+interface ActivityRow {
+ id: string;
+ actorId: string;
+ verb: string;
+}
+
+interface Page {
+ items: ActivityRow[];
+ nextCursor: string | null;
+}
+
+export async function activityPage(cursor: string | null, limit: number): Promise<Page> {
+ if (!Number.isInteger(limit) || limit < 1) {
+ throw new RangeError('limit must be a positive integer');
+ }
+ const rows: ActivityRow[] = await db.activity.findAfter(cursor, limit + 1);
+ const hasMore = rows.length > limit;
+ const items = hasMore ? rows.slice(0, limit) : rows;
+ const nextCursor = hasMore ? items[items.length - 1].id : null;
+ return { items, nextCursor };
+}