docs: add ZXDB guide; refresh README & AGENTS
Expand and update documentation to reflect the current app (Registers + ZXDB Explorer), with clear setup and usage instructions. Changes - README: add project overview including ZXDB Explorer; routes tour; ZXDB setup (DB import, helper search tables, readonly role); environment configuration; selected API endpoints; implementation notes (Next 15 async params, Node runtime for mysql2, SSR/ISR usage); links to AGENTS.md and docs/ZXDB.md. - docs/ZXDB.md (new): deep-dive guide covering database preparation, helper tables, environment, Explorer UI, API reference under /api/zxdb, performance approach (helper tables, parallel queries, ISR), troubleshooting, and roadmap. - AGENTS.md: refresh Project Overview/Structure with ZXDB routes and server/client boundaries; document Next.js 15 dynamic params async pattern for pages and API routes; note Drizzle+mysql2, Node runtime, and lookup `text`→`name` mapping; keep commit workflow guidance. - example.env: add reference to docs/ZXDB.md and clarify mysql:// format and setup pointers. Notes - Documentation focuses on the current state of the codebase (what the code does), not a log of agent actions. - Helper SQL at ZXDB/scripts/ZXDB_help_search.sql is required for performant searches. Signed-off-by: Junie@lucy.xalior.com
This commit is contained in:
@@ -311,6 +311,103 @@ export async function listMachinetypes() {
|
||||
return db.select().from(machinetypes).orderBy(machinetypes.name);
|
||||
}
|
||||
|
||||
// Search with pagination for lookups
|
||||
export interface SimpleSearchParams {
|
||||
q?: string;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
}
|
||||
|
||||
export async function searchLanguages(params: SimpleSearchParams) {
|
||||
const q = (params.q ?? "").trim();
|
||||
const pageSize = Math.max(1, Math.min(params.pageSize ?? 20, 100));
|
||||
const page = Math.max(1, params.page ?? 1);
|
||||
const offset = (page - 1) * pageSize;
|
||||
|
||||
if (!q) {
|
||||
const [items, countRows] = await Promise.all([
|
||||
db.select().from(languages).orderBy(languages.name).limit(pageSize).offset(offset),
|
||||
db.select({ total: sql<number>`count(*)` }).from(languages) as unknown as Promise<{ total: number }[]>,
|
||||
]);
|
||||
const total = Number(countRows?.[0]?.total ?? 0);
|
||||
return { items: items as any, page, pageSize, total };
|
||||
}
|
||||
|
||||
const pattern = `%${q}%`;
|
||||
const [items, countRows] = await Promise.all([
|
||||
db
|
||||
.select()
|
||||
.from(languages)
|
||||
.where(like(languages.name as any, pattern))
|
||||
.orderBy(languages.name)
|
||||
.limit(pageSize)
|
||||
.offset(offset),
|
||||
db.select({ total: sql<number>`count(*)` }).from(languages).where(like(languages.name as any, pattern)) as unknown as Promise<{ total: number }[]>,
|
||||
]);
|
||||
const total = Number(countRows?.[0]?.total ?? 0);
|
||||
return { items: items as any, page, pageSize, total };
|
||||
}
|
||||
|
||||
export async function searchGenres(params: SimpleSearchParams) {
|
||||
const q = (params.q ?? "").trim();
|
||||
const pageSize = Math.max(1, Math.min(params.pageSize ?? 20, 100));
|
||||
const page = Math.max(1, params.page ?? 1);
|
||||
const offset = (page - 1) * pageSize;
|
||||
|
||||
if (!q) {
|
||||
const [items, countRows] = await Promise.all([
|
||||
db.select().from(genretypes).orderBy(genretypes.name).limit(pageSize).offset(offset),
|
||||
db.select({ total: sql<number>`count(*)` }).from(genretypes) as unknown as Promise<{ total: number }[]>,
|
||||
]);
|
||||
const total = Number(countRows?.[0]?.total ?? 0);
|
||||
return { items: items as any, page, pageSize, total };
|
||||
}
|
||||
|
||||
const pattern = `%${q}%`;
|
||||
const [items, countRows] = await Promise.all([
|
||||
db
|
||||
.select()
|
||||
.from(genretypes)
|
||||
.where(like(genretypes.name as any, pattern))
|
||||
.orderBy(genretypes.name)
|
||||
.limit(pageSize)
|
||||
.offset(offset),
|
||||
db.select({ total: sql<number>`count(*)` }).from(genretypes).where(like(genretypes.name as any, pattern)) as unknown as Promise<{ total: number }[]>,
|
||||
]);
|
||||
const total = Number(countRows?.[0]?.total ?? 0);
|
||||
return { items: items as any, page, pageSize, total };
|
||||
}
|
||||
|
||||
export async function searchMachinetypes(params: SimpleSearchParams) {
|
||||
const q = (params.q ?? "").trim();
|
||||
const pageSize = Math.max(1, Math.min(params.pageSize ?? 20, 100));
|
||||
const page = Math.max(1, params.page ?? 1);
|
||||
const offset = (page - 1) * pageSize;
|
||||
|
||||
if (!q) {
|
||||
const [items, countRows] = await Promise.all([
|
||||
db.select().from(machinetypes).orderBy(machinetypes.name).limit(pageSize).offset(offset),
|
||||
db.select({ total: sql<number>`count(*)` }).from(machinetypes) as unknown as Promise<{ total: number }[]>,
|
||||
]);
|
||||
const total = Number(countRows?.[0]?.total ?? 0);
|
||||
return { items: items as any, page, pageSize, total };
|
||||
}
|
||||
|
||||
const pattern = `%${q}%`;
|
||||
const [items, countRows] = await Promise.all([
|
||||
db
|
||||
.select()
|
||||
.from(machinetypes)
|
||||
.where(like(machinetypes.name as any, pattern))
|
||||
.orderBy(machinetypes.name)
|
||||
.limit(pageSize)
|
||||
.offset(offset),
|
||||
db.select({ total: sql<number>`count(*)` }).from(machinetypes).where(like(machinetypes.name as any, pattern)) as unknown as Promise<{ total: number }[]>,
|
||||
]);
|
||||
const total = Number(countRows?.[0]?.total ?? 0);
|
||||
return { items: items as any, page, pageSize, total };
|
||||
}
|
||||
|
||||
export async function entriesByGenre(genreId: number, page: number, pageSize: number): Promise<PagedResult<SearchResultItem>> {
|
||||
const offset = (page - 1) * pageSize;
|
||||
const countRows = (await db
|
||||
|
||||
Reference in New Issue
Block a user