Add `paginated` helper function, DRY pagination code
This commit is contained in:
parent
ce4a330812
commit
4216a7931a
|
@ -6,7 +6,7 @@ import { booleanParamSchema } from '@/schema.ts';
|
||||||
import { jsonMetaContentSchema } from '@/schemas/nostr.ts';
|
import { jsonMetaContentSchema } from '@/schemas/nostr.ts';
|
||||||
import { toAccount, toRelationship, toStatus } from '@/transformers/nostr-to-mastoapi.ts';
|
import { toAccount, toRelationship, toStatus } from '@/transformers/nostr-to-mastoapi.ts';
|
||||||
import { eventDateComparator, isFollowing, lookupAccount } from '@/utils.ts';
|
import { eventDateComparator, isFollowing, lookupAccount } from '@/utils.ts';
|
||||||
import { buildLinkHeader, paginationSchema, parseBody } from '@/utils/web.ts';
|
import { paginated, paginationSchema, parseBody } from '@/utils/web.ts';
|
||||||
import { createEvent } from '@/utils/web.ts';
|
import { createEvent } from '@/utils/web.ts';
|
||||||
|
|
||||||
const createAccountController: AppController = (c) => {
|
const createAccountController: AppController = (c) => {
|
||||||
|
@ -110,9 +110,7 @@ const accountStatusesController: AppController = async (c) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const statuses = await Promise.all(events.map(toStatus));
|
const statuses = await Promise.all(events.map(toStatus));
|
||||||
|
return paginated(c, events, statuses);
|
||||||
const link = buildLinkHeader(c.req.url, events);
|
|
||||||
return c.json(statuses, 200, link ? { link } : undefined);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const fileSchema = z.custom<File>((value) => value instanceof File);
|
const fileSchema = z.custom<File>((value) => value instanceof File);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { type AppController } from '@/app.ts';
|
import { type AppController } from '@/app.ts';
|
||||||
import * as mixer from '@/mixer.ts';
|
import * as mixer from '@/mixer.ts';
|
||||||
import { buildLinkHeader, paginationSchema } from '@/utils/web.ts';
|
import { paginated, paginationSchema } from '@/utils/web.ts';
|
||||||
import { toNotification } from '@/transformers/nostr-to-mastoapi.ts';
|
import { toNotification } from '@/transformers/nostr-to-mastoapi.ts';
|
||||||
import { Time } from '@/utils.ts';
|
import { Time } from '@/utils.ts';
|
||||||
|
|
||||||
|
@ -14,9 +14,7 @@ const notificationsController: AppController = async (c) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
const statuses = await Promise.all(events.map(toNotification));
|
const statuses = await Promise.all(events.map(toNotification));
|
||||||
|
return paginated(c, events, statuses);
|
||||||
const link = buildLinkHeader(c.req.url, events);
|
|
||||||
return c.json(statuses, 200, link ? { link } : undefined);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export { notificationsController };
|
export { notificationsController };
|
||||||
|
|
|
@ -3,7 +3,7 @@ import * as mixer from '@/mixer.ts';
|
||||||
import { getFeed, getPublicFeed } from '@/queries.ts';
|
import { getFeed, getPublicFeed } from '@/queries.ts';
|
||||||
import { booleanParamSchema } from '@/schema.ts';
|
import { booleanParamSchema } from '@/schema.ts';
|
||||||
import { toStatus } from '@/transformers/nostr-to-mastoapi.ts';
|
import { toStatus } from '@/transformers/nostr-to-mastoapi.ts';
|
||||||
import { buildLinkHeader, paginationSchema } from '@/utils/web.ts';
|
import { paginated, paginationSchema } from '@/utils/web.ts';
|
||||||
import { Time } from '@/utils.ts';
|
import { Time } from '@/utils.ts';
|
||||||
|
|
||||||
import type { AppController } from '@/app.ts';
|
import type { AppController } from '@/app.ts';
|
||||||
|
@ -17,10 +17,8 @@ const homeTimelineController: AppController = async (c) => {
|
||||||
return c.json([]);
|
return c.json([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const statuses = (await Promise.all(events.map(toStatus))).filter(Boolean);
|
const statuses = await Promise.all(events.map(toStatus));
|
||||||
|
return paginated(c, events, statuses);
|
||||||
const link = buildLinkHeader(c.req.url, events);
|
|
||||||
return c.json(statuses, 200, link ? { link } : undefined);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const publicQuerySchema = z.object({
|
const publicQuerySchema = z.object({
|
||||||
|
@ -36,10 +34,8 @@ const publicTimelineController: AppController = async (c) => {
|
||||||
return c.json([]);
|
return c.json([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const statuses = (await Promise.all(events.map(toStatus))).filter(Boolean);
|
const statuses = await Promise.all(events.map(toStatus));
|
||||||
|
return paginated(c, events, statuses);
|
||||||
const link = buildLinkHeader(c.req.url, events);
|
|
||||||
return c.json(statuses, 200, link ? { link } : undefined);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const hashtagTimelineController: AppController = async (c) => {
|
const hashtagTimelineController: AppController = async (c) => {
|
||||||
|
@ -55,10 +51,8 @@ const hashtagTimelineController: AppController = async (c) => {
|
||||||
return c.json([]);
|
return c.json([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const statuses = (await Promise.all(events.map(toStatus))).filter(Boolean);
|
const statuses = await Promise.all(events.map(toStatus));
|
||||||
|
return paginated(c, events, statuses);
|
||||||
const link = buildLinkHeader(c.req.url, events);
|
|
||||||
return c.json(statuses, 200, link ? { link } : undefined);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export { hashtagTimelineController, homeTimelineController, publicTimelineController };
|
export { hashtagTimelineController, homeTimelineController, publicTimelineController };
|
||||||
|
|
|
@ -89,6 +89,22 @@ function buildLinkHeader(url: string, events: Event[]): string | undefined {
|
||||||
return `<${next}>; rel="next", <${prev}>; rel="prev"`;
|
return `<${next}>; rel="next", <${prev}>; rel="prev"`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Entity = { id: string };
|
||||||
|
type HeaderRecord = Record<string, string | string[]>;
|
||||||
|
|
||||||
|
/** Return results with pagination headers. */
|
||||||
|
function paginated(c: AppContext, events: Event[], entities: (Entity | undefined)[], headers: HeaderRecord = {}) {
|
||||||
|
const link = buildLinkHeader(c.req.url, events);
|
||||||
|
|
||||||
|
if (link) {
|
||||||
|
headers.link = link;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter out undefined entities.
|
||||||
|
const results = entities.filter((entity): entity is Entity => Boolean(entity));
|
||||||
|
return c.json(results, 200, headers);
|
||||||
|
}
|
||||||
|
|
||||||
/** JSON-LD context. */
|
/** JSON-LD context. */
|
||||||
type LDContext = (string | Record<string, string | Record<string, string>>)[];
|
type LDContext = (string | Record<string, string | Record<string, string>>)[];
|
||||||
|
|
||||||
|
@ -107,12 +123,4 @@ function activityJson<T, P extends string>(c: Context<any, P>, object: T) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { activityJson, createAdminEvent, createEvent, paginated, type PaginationParams, paginationSchema, parseBody };
|
||||||
activityJson,
|
|
||||||
buildLinkHeader,
|
|
||||||
createAdminEvent,
|
|
||||||
createEvent,
|
|
||||||
type PaginationParams,
|
|
||||||
paginationSchema,
|
|
||||||
parseBody,
|
|
||||||
};
|
|
||||||
|
|
Loading…
Reference in New Issue