Adding the first stubs of the magazine browser
This commit is contained in:
@@ -23,6 +23,10 @@ import {
|
||||
aliases,
|
||||
webrefs,
|
||||
websites,
|
||||
magazines,
|
||||
issues,
|
||||
magrefs,
|
||||
referencetypes,
|
||||
} from "@/server/schema/zxdb";
|
||||
|
||||
export interface SearchParams {
|
||||
@@ -66,6 +70,58 @@ export interface EntryFacets {
|
||||
machinetypes: FacetItem<number>[];
|
||||
}
|
||||
|
||||
export interface MagazineListItem {
|
||||
id: number;
|
||||
title: string;
|
||||
languageId: string;
|
||||
issueCount: number;
|
||||
}
|
||||
|
||||
export interface MagazineDetail {
|
||||
id: number;
|
||||
title: string;
|
||||
languageId: string;
|
||||
linkSite?: string | null;
|
||||
linkMask?: string | null;
|
||||
archiveMask?: string | null;
|
||||
issues: Array<{
|
||||
id: number;
|
||||
dateYear: number | null;
|
||||
dateMonth: number | null;
|
||||
number: number | null;
|
||||
volume: number | null;
|
||||
special: string | null;
|
||||
supplement: string | null;
|
||||
linkMask?: string | null;
|
||||
archiveMask?: string | null;
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface IssueDetail {
|
||||
id: number;
|
||||
magazine: { id: number; title: string };
|
||||
dateYear: number | null;
|
||||
dateMonth: number | null;
|
||||
number: number | null;
|
||||
volume: number | null;
|
||||
special: string | null;
|
||||
supplement: string | null;
|
||||
linkMask?: string | null;
|
||||
archiveMask?: string | null;
|
||||
refs: Array<{
|
||||
id: number;
|
||||
page: number;
|
||||
typeId: number;
|
||||
typeName: string;
|
||||
entryId: number | null;
|
||||
entryTitle: string | null;
|
||||
labelId: number | null;
|
||||
labelName: string | null;
|
||||
isOriginal: number;
|
||||
scoreGroup: string;
|
||||
}>
|
||||
}
|
||||
|
||||
export async function searchEntries(params: SearchParams): Promise<PagedResult<SearchResultItem>> {
|
||||
const q = (params.q ?? "").trim();
|
||||
const pageSize = Math.max(1, Math.min(params.pageSize ?? 20, 100));
|
||||
@@ -1180,3 +1236,149 @@ export async function listCurrencies() {
|
||||
export async function listRoletypes() {
|
||||
return db.select().from(roletypes).orderBy(roletypes.name);
|
||||
}
|
||||
|
||||
export async function listMagazines(params: { q?: string; page?: number; pageSize?: number }): Promise<PagedResult<MagazineListItem>> {
|
||||
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;
|
||||
|
||||
const whereExpr = q ? like(magazines.name, `%${q}%`) : sql`true`;
|
||||
|
||||
const [items, totalRows] = await Promise.all([
|
||||
db
|
||||
.select({
|
||||
id: magazines.id,
|
||||
// Expose as `title` to UI while DB column is `name`
|
||||
title: magazines.name,
|
||||
languageId: magazines.languageId,
|
||||
issueCount: sql<number>`count(${issues.id})`,
|
||||
})
|
||||
.from(magazines)
|
||||
.leftJoin(issues, eq(issues.magazineId, magazines.id))
|
||||
.where(whereExpr)
|
||||
.groupBy(magazines.id)
|
||||
.orderBy(asc(magazines.name))
|
||||
.limit(pageSize)
|
||||
.offset(offset),
|
||||
db
|
||||
.select({ cnt: sql<number>`count(*)` })
|
||||
.from(magazines)
|
||||
.where(whereExpr),
|
||||
]);
|
||||
|
||||
return {
|
||||
items,
|
||||
page,
|
||||
pageSize,
|
||||
total: totalRows[0]?.cnt ?? 0,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getMagazine(id: number): Promise<MagazineDetail | null> {
|
||||
const rows = await db
|
||||
.select({
|
||||
id: magazines.id,
|
||||
// Alias DB `name` as `title` for UI shape
|
||||
title: magazines.name,
|
||||
languageId: magazines.languageId,
|
||||
linkSite: magazines.linkSite,
|
||||
linkMask: magazines.linkMask,
|
||||
archiveMask: magazines.archiveMask,
|
||||
})
|
||||
.from(magazines)
|
||||
.where(eq(magazines.id, id));
|
||||
if (rows.length === 0) return null;
|
||||
const mag = rows[0];
|
||||
|
||||
const iss = await db
|
||||
.select({
|
||||
id: issues.id,
|
||||
dateYear: issues.dateYear,
|
||||
dateMonth: issues.dateMonth,
|
||||
number: issues.number,
|
||||
volume: issues.volume,
|
||||
special: issues.special,
|
||||
supplement: issues.supplement,
|
||||
linkMask: issues.linkMask,
|
||||
archiveMask: issues.archiveMask,
|
||||
})
|
||||
.from(issues)
|
||||
.where(eq(issues.magazineId, id))
|
||||
.orderBy(
|
||||
asc(issues.dateYear),
|
||||
asc(issues.dateMonth),
|
||||
asc(issues.volume),
|
||||
asc(issues.number),
|
||||
asc(issues.id),
|
||||
);
|
||||
|
||||
return { ...mag, issues: iss };
|
||||
}
|
||||
|
||||
export async function getIssue(id: number): Promise<IssueDetail | null> {
|
||||
const rows = await db
|
||||
.select({
|
||||
id: issues.id,
|
||||
magazineId: issues.magazineId,
|
||||
magazineTitle: magazines.name,
|
||||
dateYear: issues.dateYear,
|
||||
dateMonth: issues.dateMonth,
|
||||
number: issues.number,
|
||||
volume: issues.volume,
|
||||
special: issues.special,
|
||||
supplement: issues.supplement,
|
||||
linkMask: issues.linkMask,
|
||||
archiveMask: issues.archiveMask,
|
||||
})
|
||||
.from(issues)
|
||||
.leftJoin(magazines, eq(magazines.id, issues.magazineId))
|
||||
.where(eq(issues.id, id));
|
||||
const base = rows[0];
|
||||
if (!base) return null;
|
||||
|
||||
const refs = await db
|
||||
.select({
|
||||
id: magrefs.id,
|
||||
page: magrefs.page,
|
||||
typeId: magrefs.referencetypeId,
|
||||
typeName: referencetypes.name,
|
||||
entryId: magrefs.entryId,
|
||||
entryTitle: entries.title,
|
||||
labelId: magrefs.labelId,
|
||||
labelName: labels.name,
|
||||
isOriginal: magrefs.isOriginal,
|
||||
scoreGroup: magrefs.scoreGroup,
|
||||
})
|
||||
.from(magrefs)
|
||||
.leftJoin(referencetypes, eq(referencetypes.id, magrefs.referencetypeId))
|
||||
.leftJoin(entries, eq(entries.id, magrefs.entryId))
|
||||
.leftJoin(labels, eq(labels.id, magrefs.labelId))
|
||||
.where(eq(magrefs.issueId, id))
|
||||
.orderBy(asc(magrefs.page), asc(magrefs.id));
|
||||
|
||||
return {
|
||||
id: base.id,
|
||||
magazine: { id: Number(base.magazineId), title: base.magazineTitle ?? "" },
|
||||
dateYear: base.dateYear,
|
||||
dateMonth: base.dateMonth,
|
||||
number: base.number,
|
||||
volume: base.volume,
|
||||
special: base.special,
|
||||
supplement: base.supplement,
|
||||
linkMask: base.linkMask,
|
||||
archiveMask: base.archiveMask,
|
||||
refs: refs.map((r) => ({
|
||||
id: r.id,
|
||||
page: r.page,
|
||||
typeId: Number(r.typeId),
|
||||
typeName: r.typeName ?? "",
|
||||
entryId: r.entryId ?? null,
|
||||
entryTitle: r.entryTitle ?? null,
|
||||
labelId: r.labelId ?? null,
|
||||
labelName: r.labelName ?? null,
|
||||
isOriginal: Number(r.isOriginal),
|
||||
scoreGroup: r.scoreGroup,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user