feat(search): search public news events users and open rooms
This commit is contained in:
1 parent
506e14783c
commit
ba9c61d808
5 files changed
+424
-184
No files matched your search
@@ -0,0 +1,124 @@
|
||||
import { publicReadFailure } from "@/lib/services/public-read";
|
||||
import "server-only";
|
||||
import { and, asc, count, eq, inArray, like, or } from "drizzle-orm";
|
||||
import { db, Rooms, User, WebsiteEvent } from "@/lib/db";
|
||||
import { loadNewsArchive } from "@/lib/services/news-archive";
|
||||
|
||||
function pageNumber(value: number | undefined, total: number) {
|
||||
return Math.min(
|
||||
Math.max(1, Math.ceil(total / 12)),
|
||||
Number.isFinite(value) ? Math.max(1, Math.trunc(value ?? 1)) : 1,
|
||||
);
|
||||
}
|
||||
export async function loadPublicSearch(options: {
|
||||
query: string;
|
||||
usersPage?: number;
|
||||
roomsPage?: number;
|
||||
newsPage?: number;
|
||||
eventsPage?: number;
|
||||
}) {
|
||||
const query = (typeof options.query === "string" ? options.query : "")
|
||||
.trim()
|
||||
.slice(0, 191);
|
||||
if (!query) return null;
|
||||
const userWhere = like(User.username, `%${query}%`);
|
||||
const roomWhere = and(
|
||||
like(Rooms.name, `%${query}%`),
|
||||
eq(Rooms.state, "open"),
|
||||
);
|
||||
const eventWhere = and(
|
||||
inArray(WebsiteEvent.status, ["published", "completed"]),
|
||||
or(
|
||||
like(WebsiteEvent.title, `%${query}%`),
|
||||
like(WebsiteEvent.description, `%${query}%`),
|
||||
),
|
||||
);
|
||||
const [users, rooms, news, events] = await Promise.allSettled([
|
||||
(async () => {
|
||||
const [{ value: total }] = await db
|
||||
.select({ value: count() })
|
||||
.from(User)
|
||||
.where(userWhere);
|
||||
const page = pageNumber(options.usersPage, Number(total));
|
||||
const rows = await db
|
||||
.select({
|
||||
id: User.id,
|
||||
username: User.username,
|
||||
look: User.look,
|
||||
online: User.online,
|
||||
})
|
||||
.from(User)
|
||||
.where(userWhere)
|
||||
.orderBy(asc(User.username), asc(User.id))
|
||||
.limit(12)
|
||||
.offset((page - 1) * 12);
|
||||
return {
|
||||
rows,
|
||||
total: Number(total),
|
||||
page,
|
||||
lastPage: Math.max(1, Math.ceil(Number(total) / 12)),
|
||||
};
|
||||
})(),
|
||||
(async () => {
|
||||
const [{ value: total }] = await db
|
||||
.select({ value: count() })
|
||||
.from(Rooms)
|
||||
.where(roomWhere);
|
||||
const page = pageNumber(options.roomsPage, Number(total));
|
||||
const rows = await db
|
||||
.select({
|
||||
id: Rooms.id,
|
||||
name: Rooms.name,
|
||||
ownerName: Rooms.ownerName,
|
||||
users: Rooms.users,
|
||||
usersMax: Rooms.usersMax,
|
||||
})
|
||||
.from(Rooms)
|
||||
.where(roomWhere)
|
||||
.orderBy(asc(Rooms.name), asc(Rooms.id))
|
||||
.limit(12)
|
||||
.offset((page - 1) * 12);
|
||||
return {
|
||||
rows,
|
||||
total: Number(total),
|
||||
page,
|
||||
lastPage: Math.max(1, Math.ceil(Number(total) / 12)),
|
||||
};
|
||||
})(),
|
||||
loadNewsArchive({ search: query, page: options.newsPage }),
|
||||
(async () => {
|
||||
const [{ value: total }] = await db
|
||||
.select({ value: count() })
|
||||
.from(WebsiteEvent)
|
||||
.where(eventWhere);
|
||||
const page = pageNumber(options.eventsPage, Number(total));
|
||||
const rows = await db
|
||||
.select({
|
||||
id: WebsiteEvent.id,
|
||||
title: WebsiteEvent.title,
|
||||
startsAt: WebsiteEvent.startsAt,
|
||||
})
|
||||
.from(WebsiteEvent)
|
||||
.where(eventWhere)
|
||||
.orderBy(asc(WebsiteEvent.startsAt), asc(WebsiteEvent.id))
|
||||
.limit(12)
|
||||
.offset((page - 1) * 12);
|
||||
return {
|
||||
rows,
|
||||
total: Number(total),
|
||||
page,
|
||||
lastPage: Math.max(1, Math.ceil(Number(total) / 12)),
|
||||
};
|
||||
})(),
|
||||
]);
|
||||
for (const [section, result] of Object.entries({
|
||||
users,
|
||||
rooms,
|
||||
news,
|
||||
events,
|
||||
})) {
|
||||
if (result.status === "rejected")
|
||||
publicReadFailure(`search.${section}`)(result.reason);
|
||||
}
|
||||
return { query, users, rooms, news, events };
|
||||
}
|
||||
Reference in new issue
Block a user