feat(news): add searchable paginated publication archive
CI / check (push) Failing after 53s
CI / deploy (push) Skipped
CI / publish-container (push) Skipped

This commit is contained in:
Simo committed 2026-09-11 00:19:12 +02:00
1 parent a537c55793
commit 5d18af932d
3 files changed
+207 -5

No files matched your search

+55
View File
@@ -0,0 +1,55 @@
import "server-only";
import { and, asc, count, desc, eq, like, or, sql } from "drizzle-orm";
import { db, WebsiteArticles } from "@/lib/db";
export async function loadNewsArchive(
options: { search?: string; page?: number; order?: string } = {},
) {
const search = (options.search ?? "").trim().slice(0, 191);
const order = options.order === "oldest" ? "oldest" : "newest";
const publishedAt =
sql<Date | null>`COALESCE(${WebsiteArticles.publishAt}, ${WebsiteArticles.createdAt})`.mapWith(
WebsiteArticles.createdAt,
);
const where = and(
eq(WebsiteArticles.status, "published"),
or(
sql`${WebsiteArticles.publishAt} IS NULL`,
sql`${WebsiteArticles.publishAt} <= NOW()`,
),
search
? or(
like(WebsiteArticles.title, `%${search}%`),
like(WebsiteArticles.shortStory, `%${search}%`),
)
: undefined,
);
const totals = await db
.select({ value: count() })
.from(WebsiteArticles)
.where(where);
const total = Number(totals[0]?.value ?? 0);
const perPage = 24;
const lastPage = Math.max(1, Math.ceil(total / perPage));
const page = Math.min(
lastPage,
Number.isFinite(options.page)
? Math.max(1, Math.trunc(options.page ?? 1))
: 1,
);
const sort = order === "oldest" ? asc : desc;
const rows = await db
.select({
slug: WebsiteArticles.slug,
title: WebsiteArticles.title,
shortStory: WebsiteArticles.shortStory,
image: WebsiteArticles.image,
createdAt: publishedAt,
})
.from(WebsiteArticles)
.where(where)
.orderBy(sort(publishedAt), sort(WebsiteArticles.id))
.limit(perPage)
.offset((page - 1) * perPage);
return { rows, total, page, perPage, lastPage, search, order };
}