No explicit any
This commit is contained in:
@@ -73,39 +73,47 @@ export async function searchEntries(params: SearchParams): Promise<PagedResult<S
|
||||
if (q.length === 0) {
|
||||
// Default listing: return first page by id desc (no guaranteed ordering field; using id)
|
||||
// Apply optional filters even without q
|
||||
const whereClauses = [
|
||||
params.genreId ? eq(entries.genretypeId, params.genreId as any) : undefined,
|
||||
params.languageId ? eq(entries.languageId, params.languageId as any) : undefined,
|
||||
params.machinetypeId ? eq(entries.machinetypeId, params.machinetypeId as any) : undefined,
|
||||
].filter(Boolean) as any[];
|
||||
const whereClauses: Array<ReturnType<typeof eq>> = [];
|
||||
if (typeof params.genreId === "number") {
|
||||
whereClauses.push(eq(entries.genretypeId, params.genreId));
|
||||
}
|
||||
if (typeof params.languageId === "string") {
|
||||
whereClauses.push(eq(entries.languageId, params.languageId));
|
||||
}
|
||||
if (typeof params.machinetypeId === "number") {
|
||||
whereClauses.push(eq(entries.machinetypeId, params.machinetypeId));
|
||||
}
|
||||
|
||||
const whereExpr = whereClauses.length ? and(...whereClauses) : undefined;
|
||||
|
||||
const [items, countRows] = await Promise.all([
|
||||
db
|
||||
.select({
|
||||
id: entries.id,
|
||||
title: entries.title,
|
||||
isXrated: entries.isXrated,
|
||||
machinetypeId: entries.machinetypeId,
|
||||
machinetypeName: machinetypes.name,
|
||||
languageId: entries.languageId,
|
||||
languageName: languages.name,
|
||||
})
|
||||
.from(entries)
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId as any))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId as any))
|
||||
.where(whereExpr as any)
|
||||
.orderBy(sort === "id_desc" ? desc(entries.id) : entries.title)
|
||||
.limit(pageSize)
|
||||
.offset(offset),
|
||||
(async () => {
|
||||
let q1 = db
|
||||
.select({
|
||||
id: entries.id,
|
||||
title: entries.title,
|
||||
isXrated: entries.isXrated,
|
||||
machinetypeId: entries.machinetypeId,
|
||||
machinetypeName: machinetypes.name,
|
||||
languageId: entries.languageId,
|
||||
languageName: languages.name,
|
||||
})
|
||||
.from(entries)
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId));
|
||||
if (whereExpr) q1 = q1.where(whereExpr);
|
||||
return q1
|
||||
.orderBy(sort === "id_desc" ? desc(entries.id) : entries.title)
|
||||
.limit(pageSize)
|
||||
.offset(offset);
|
||||
})(),
|
||||
db
|
||||
.select({ total: sql<number>`count(*)` })
|
||||
.from(entries)
|
||||
.where(whereExpr as any) as unknown as Promise<{ total: number }[]>,
|
||||
.where(whereExpr ?? sql`true`),
|
||||
]);
|
||||
const total = Number(countRows?.[0]?.total ?? 0);
|
||||
return { items: items as any, page, pageSize, total };
|
||||
return { items, page, pageSize, total };
|
||||
}
|
||||
|
||||
const pattern = `%${q.toLowerCase().replace(/[^a-z0-9]+/g, "")}%`;
|
||||
@@ -131,15 +139,15 @@ export async function searchEntries(params: SearchParams): Promise<PagedResult<S
|
||||
})
|
||||
.from(searchByTitles)
|
||||
.innerJoin(entries, eq(entries.id, searchByTitles.entryId))
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId as any))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId as any))
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId))
|
||||
.where(like(searchByTitles.entryTitle, pattern))
|
||||
.groupBy(entries.id)
|
||||
.orderBy(sort === "id_desc" ? desc(entries.id) : entries.title)
|
||||
.limit(pageSize)
|
||||
.offset(offset);
|
||||
|
||||
return { items: items as any, page, pageSize, total };
|
||||
return { items, page, pageSize, total };
|
||||
}
|
||||
|
||||
export interface LabelSummary {
|
||||
@@ -235,9 +243,9 @@ export async function getEntryById(id: number): Promise<EntryDetail | null> {
|
||||
issueId: entries.issueId,
|
||||
})
|
||||
.from(entries)
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId as any))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId as any))
|
||||
.leftJoin(genretypes, eq(genretypes.id, entries.genretypeId as any))
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId))
|
||||
.leftJoin(genretypes, eq(genretypes.id, entries.genretypeId))
|
||||
.where(eq(entries.id, id)),
|
||||
db
|
||||
.select({ id: labels.id, name: labels.name, labeltypeId: labels.labeltypeId })
|
||||
@@ -279,13 +287,36 @@ export async function getEntryById(id: number): Promise<EntryDetail | null> {
|
||||
typeName: filetypes.name,
|
||||
})
|
||||
.from(files)
|
||||
.innerJoin(filetypes, eq(filetypes.id, files.filetypeId as any))
|
||||
.where(eq(files.issueId as any, base.issueId as any))) as any;
|
||||
.innerJoin(filetypes, eq(filetypes.id, files.filetypeId))
|
||||
.where(eq(files.issueId, base.issueId)));
|
||||
}
|
||||
|
||||
let releaseRows: any[] = [];
|
||||
let downloadRows: any[] = [];
|
||||
let downloadFlatRows: any[] = [];
|
||||
type ReleaseRow = { releaseSeq: number | string; year: number | string | null };
|
||||
type DownloadRow = {
|
||||
id: number | string;
|
||||
releaseSeq: number | string;
|
||||
link: string;
|
||||
size: number | string | null;
|
||||
md5: string | null;
|
||||
comments: string | null;
|
||||
isDemo: number | boolean | null;
|
||||
filetypeId: number | string;
|
||||
filetypeName: string;
|
||||
dlLangId: string | null;
|
||||
dlLangName: string | null;
|
||||
dlMachineId: number | string | null;
|
||||
dlMachineName: string | null;
|
||||
schemeId: string | null;
|
||||
schemeName: string | null;
|
||||
sourceId: string | null;
|
||||
sourceName: string | null;
|
||||
caseId: string | null;
|
||||
caseName: string | null;
|
||||
year: number | string | null;
|
||||
};
|
||||
let releaseRows: ReleaseRow[] = [];
|
||||
let downloadRows: DownloadRow[] = [];
|
||||
let downloadFlatRows: DownloadRow[] = [];
|
||||
|
||||
// Fetch releases for this entry (optional; ignore if table missing)
|
||||
try {
|
||||
@@ -295,7 +326,7 @@ export async function getEntryById(id: number): Promise<EntryDetail | null> {
|
||||
year: releases.releaseYear,
|
||||
})
|
||||
.from(releases)
|
||||
.where(eq(releases.entryId as any, id as any))) as any;
|
||||
.where(eq(releases.entryId, id)));
|
||||
} catch {
|
||||
releaseRows = [];
|
||||
}
|
||||
@@ -326,13 +357,13 @@ export async function getEntryById(id: number): Promise<EntryDetail | null> {
|
||||
year: downloads.releaseYear,
|
||||
})
|
||||
.from(downloads)
|
||||
.innerJoin(filetypes, eq(filetypes.id as any, downloads.filetypeId as any))
|
||||
.leftJoin(languages, eq(languages.id as any, downloads.languageId as any))
|
||||
.leftJoin(machinetypes, eq(machinetypes.id as any, downloads.machinetypeId as any))
|
||||
.leftJoin(schemetypes, eq(schemetypes.id as any, downloads.schemetypeId as any))
|
||||
.leftJoin(sourcetypes, eq(sourcetypes.id as any, downloads.sourcetypeId as any))
|
||||
.leftJoin(casetypes, eq(casetypes.id as any, downloads.casetypeId as any))
|
||||
.where(eq(downloads.entryId as any, id as any))) as any;
|
||||
.innerJoin(filetypes, eq(filetypes.id, downloads.filetypeId))
|
||||
.leftJoin(languages, eq(languages.id, downloads.languageId))
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, downloads.machinetypeId))
|
||||
.leftJoin(schemetypes, eq(schemetypes.id, downloads.schemetypeId))
|
||||
.leftJoin(sourcetypes, eq(sourcetypes.id, downloads.sourcetypeId))
|
||||
.leftJoin(casetypes, eq(casetypes.id, downloads.casetypeId))
|
||||
.where(eq(downloads.entryId, id)));
|
||||
} catch {
|
||||
downloadRows = [];
|
||||
}
|
||||
@@ -340,7 +371,7 @@ export async function getEntryById(id: number): Promise<EntryDetail | null> {
|
||||
// Flat list: same rows mapped, independent of releases
|
||||
downloadFlatRows = downloadRows;
|
||||
|
||||
const downloadsBySeq = new Map<number, any[]>();
|
||||
const downloadsBySeq = new Map<number, DownloadRow[]>();
|
||||
for (const row of downloadRows) {
|
||||
const arr = downloadsBySeq.get(row.releaseSeq) ?? [];
|
||||
arr.push(row);
|
||||
@@ -350,14 +381,14 @@ export async function getEntryById(id: number): Promise<EntryDetail | null> {
|
||||
// Build a map of downloads grouped by release_seq
|
||||
// Then ensure we create "synthetic" release groups for any release_seq
|
||||
// that appears in downloads but has no corresponding releases row.
|
||||
const releasesData = releaseRows.map((r: any) => ({
|
||||
const releasesData = releaseRows.map((r) => ({
|
||||
releaseSeq: Number(r.releaseSeq),
|
||||
type: { id: null, name: null },
|
||||
language: { id: null, name: null },
|
||||
machinetype: { id: null, name: null },
|
||||
year: (r.year as any) ?? null,
|
||||
year: (r.year) ?? null,
|
||||
comments: null,
|
||||
downloads: (downloadsBySeq.get(Number(r.releaseSeq)) ?? []).map((d: any) => ({
|
||||
downloads: (downloadsBySeq.get(Number(r.releaseSeq)) ?? []).map((d) => ({
|
||||
id: d.id,
|
||||
link: d.link,
|
||||
size: d.size ?? null,
|
||||
@@ -365,12 +396,12 @@ export async function getEntryById(id: number): Promise<EntryDetail | null> {
|
||||
comments: d.comments ?? null,
|
||||
isDemo: !!d.isDemo,
|
||||
type: { id: d.filetypeId, name: d.filetypeName },
|
||||
language: { id: (d.dlLangId as any) ?? null, name: (d.dlLangName as any) ?? null },
|
||||
machinetype: { id: (d.dlMachineId as any) ?? null, name: (d.dlMachineName as any) ?? null },
|
||||
scheme: { id: (d.schemeId as any) ?? null, name: (d.schemeName as any) ?? null },
|
||||
source: { id: (d.sourceId as any) ?? null, name: (d.sourceName as any) ?? null },
|
||||
case: { id: (d.caseId as any) ?? null, name: (d.caseName as any) ?? null },
|
||||
year: (d.year as any) ?? null,
|
||||
language: { id: (d.dlLangId) ?? null, name: (d.dlLangName) ?? null },
|
||||
machinetype: { id: (d.dlMachineId) ?? null, name: (d.dlMachineName) ?? null },
|
||||
scheme: { id: (d.schemeId) ?? null, name: (d.schemeName) ?? null },
|
||||
source: { id: (d.sourceId) ?? null, name: (d.sourceName) ?? null },
|
||||
case: { id: (d.caseId) ?? null, name: (d.caseName) ?? null },
|
||||
year: (d.year) ?? null,
|
||||
})),
|
||||
}));
|
||||
|
||||
@@ -382,17 +413,17 @@ export async function getEntryById(id: number): Promise<EntryDetail | null> {
|
||||
return {
|
||||
id: base.id,
|
||||
title: base.title,
|
||||
isXrated: base.isXrated as any,
|
||||
machinetype: { id: (base.machinetypeId as any) ?? null, name: (base.machinetypeName as any) ?? null },
|
||||
language: { id: (base.languageId as any) ?? null, name: (base.languageName as any) ?? null },
|
||||
genre: { id: (base.genreId as any) ?? null, name: (base.genreName as any) ?? null },
|
||||
authors: authorRows as any,
|
||||
publishers: publisherRows as any,
|
||||
maxPlayers: (base.maxPlayers as any) ?? undefined,
|
||||
availabletypeId: (base.availabletypeId as any) ?? undefined,
|
||||
withoutLoadScreen: (base.withoutLoadScreen as any) ?? undefined,
|
||||
withoutInlay: (base.withoutInlay as any) ?? undefined,
|
||||
issueId: (base.issueId as any) ?? undefined,
|
||||
isXrated: base.isXrated,
|
||||
machinetype: { id: (base.machinetypeId) ?? null, name: (base.machinetypeName) ?? null },
|
||||
language: { id: (base.languageId) ?? null, name: (base.languageName) ?? null },
|
||||
genre: { id: (base.genreId) ?? null, name: (base.genreName) ?? null },
|
||||
authors: authorRows,
|
||||
publishers: publisherRows,
|
||||
maxPlayers: (base.maxPlayers) ?? undefined,
|
||||
availabletypeId: (base.availabletypeId) ?? undefined,
|
||||
withoutLoadScreen: (base.withoutLoadScreen) ?? undefined,
|
||||
withoutInlay: (base.withoutInlay) ?? undefined,
|
||||
issueId: (base.issueId) ?? undefined,
|
||||
files:
|
||||
fileRows.length > 0
|
||||
? fileRows.map((f) => ({
|
||||
@@ -405,7 +436,7 @@ export async function getEntryById(id: number): Promise<EntryDetail | null> {
|
||||
}))
|
||||
: [],
|
||||
releases: releasesData,
|
||||
downloadsFlat: downloadFlatRows.map((d: any) => ({
|
||||
downloadsFlat: downloadFlatRows.map((d) => ({
|
||||
id: d.id,
|
||||
link: d.link,
|
||||
size: d.size ?? null,
|
||||
@@ -413,12 +444,12 @@ export async function getEntryById(id: number): Promise<EntryDetail | null> {
|
||||
comments: d.comments ?? null,
|
||||
isDemo: !!d.isDemo,
|
||||
type: { id: d.filetypeId, name: d.filetypeName },
|
||||
language: { id: (d.dlLangId as any) ?? null, name: (d.dlLangName as any) ?? null },
|
||||
machinetype: { id: (d.dlMachineId as any) ?? null, name: (d.dlMachineName as any) ?? null },
|
||||
scheme: { id: (d.schemeId as any) ?? null, name: (d.schemeName as any) ?? null },
|
||||
source: { id: (d.sourceId as any) ?? null, name: (d.sourceName as any) ?? null },
|
||||
case: { id: (d.caseId as any) ?? null, name: (d.caseName as any) ?? null },
|
||||
year: (d.year as any) ?? null,
|
||||
language: { id: (d.dlLangId) ?? null, name: (d.dlLangName) ?? null },
|
||||
machinetype: { id: (d.dlMachineId) ?? null, name: (d.dlMachineName) ?? null },
|
||||
scheme: { id: (d.schemeId) ?? null, name: (d.schemeName) ?? null },
|
||||
source: { id: (d.sourceId) ?? null, name: (d.sourceName) ?? null },
|
||||
case: { id: (d.caseId) ?? null, name: (d.caseName) ?? null },
|
||||
year: (d.year) ?? null,
|
||||
releaseSeq: Number(d.releaseSeq),
|
||||
})),
|
||||
};
|
||||
@@ -448,33 +479,33 @@ export async function searchLabels(params: LabelSearchParams): Promise<PagedResu
|
||||
.from(labels) as unknown as Promise<{ total: number }[]>,
|
||||
]);
|
||||
const total = Number(countRows?.[0]?.total ?? 0);
|
||||
return { items: items as any, page, pageSize, total };
|
||||
return { items: items, page, pageSize, total };
|
||||
}
|
||||
|
||||
// Using helper search_by_names for efficiency
|
||||
const pattern = `%${q}%`;
|
||||
const countRows = await db
|
||||
.select({ total: sql<number>`count(distinct ${sql.identifier("label_id")})` })
|
||||
.from(sql`search_by_names` as any)
|
||||
.where(like(sql.identifier("label_name") as any, pattern));
|
||||
.from(sql`search_by_names`)
|
||||
.where(like(sql.identifier("label_name"), pattern));
|
||||
const total = Number(countRows[0]?.total ?? 0);
|
||||
|
||||
const items = await db
|
||||
.select({ id: labels.id, name: labels.name, labeltypeId: labels.labeltypeId })
|
||||
.from(sql`search_by_names` as any)
|
||||
.innerJoin(labels, eq(labels.id as any, sql.identifier("label_id") as any))
|
||||
.where(like(sql.identifier("label_name") as any, pattern))
|
||||
.from(sql`search_by_names`)
|
||||
.innerJoin(labels, eq(labels.id, sql.identifier("label_id")))
|
||||
.where(like(sql.identifier("label_name"), pattern))
|
||||
.groupBy(labels.id)
|
||||
.orderBy(labels.name)
|
||||
.limit(pageSize)
|
||||
.offset(offset);
|
||||
|
||||
return { items: items as any, page, pageSize, total };
|
||||
return { items: items, page, pageSize, total };
|
||||
}
|
||||
|
||||
export async function getLabelById(id: number): Promise<LabelDetail | null> {
|
||||
const rows = await db.select().from(labels).where(eq(labels.id, id)).limit(1);
|
||||
return (rows[0] as any) ?? null;
|
||||
return (rows[0]) ?? null;
|
||||
}
|
||||
|
||||
export interface LabelContribsParams {
|
||||
@@ -508,15 +539,15 @@ export async function getLabelAuthoredEntries(labelId: number, params: LabelCont
|
||||
})
|
||||
.from(authors)
|
||||
.innerJoin(entries, eq(entries.id, authors.entryId))
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId as any))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId as any))
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId))
|
||||
.where(eq(authors.labelId, labelId))
|
||||
.groupBy(entries.id)
|
||||
.orderBy(entries.title)
|
||||
.limit(pageSize)
|
||||
.offset(offset);
|
||||
|
||||
return { items: items as any, page, pageSize, total };
|
||||
return { items: items, page, pageSize, total };
|
||||
}
|
||||
|
||||
const pattern = `%${params.q!.toLowerCase().replace(/[^a-z0-9]+/g, "")}%`;
|
||||
@@ -524,8 +555,8 @@ export async function getLabelAuthoredEntries(labelId: number, params: LabelCont
|
||||
.select({ total: sql<number>`count(distinct ${entries.id})` })
|
||||
.from(authors)
|
||||
.innerJoin(entries, eq(entries.id, authors.entryId))
|
||||
.where(and(eq(authors.labelId, labelId), sql`${entries.id} in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`) as any);
|
||||
const total = Number((countRows as any)[0]?.total ?? 0);
|
||||
.where(and(eq(authors.labelId, labelId), sql`${entries.id} in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`));
|
||||
const total = Number((countRows)[0]?.total ?? 0);
|
||||
const items = await db
|
||||
.select({
|
||||
id: entries.id,
|
||||
@@ -538,15 +569,15 @@ export async function getLabelAuthoredEntries(labelId: number, params: LabelCont
|
||||
})
|
||||
.from(authors)
|
||||
.innerJoin(entries, eq(entries.id, authors.entryId))
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId as any))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId as any))
|
||||
.where(and(eq(authors.labelId, labelId), sql`${entries.id} in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`) as any)
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId))
|
||||
.where(and(eq(authors.labelId, labelId), sql`${entries.id} in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`))
|
||||
.groupBy(entries.id)
|
||||
.orderBy(entries.title)
|
||||
.limit(pageSize)
|
||||
.offset(offset);
|
||||
|
||||
return { items: items as any, page, pageSize, total };
|
||||
return { items: items, page, pageSize, total };
|
||||
}
|
||||
|
||||
export async function getLabelPublishedEntries(labelId: number, params: LabelContribsParams): Promise<PagedResult<SearchResultItem>> {
|
||||
@@ -574,15 +605,15 @@ export async function getLabelPublishedEntries(labelId: number, params: LabelCon
|
||||
})
|
||||
.from(publishers)
|
||||
.innerJoin(entries, eq(entries.id, publishers.entryId))
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId as any))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId as any))
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId))
|
||||
.where(eq(publishers.labelId, labelId))
|
||||
.groupBy(entries.id)
|
||||
.orderBy(entries.title)
|
||||
.limit(pageSize)
|
||||
.offset(offset);
|
||||
|
||||
return { items: items as any, page, pageSize, total };
|
||||
return { items: items, page, pageSize, total };
|
||||
}
|
||||
|
||||
const pattern = `%${params.q!.toLowerCase().replace(/[^a-z0-9]+/g, "")}%`;
|
||||
@@ -590,8 +621,8 @@ export async function getLabelPublishedEntries(labelId: number, params: LabelCon
|
||||
.select({ total: sql<number>`count(distinct ${entries.id})` })
|
||||
.from(publishers)
|
||||
.innerJoin(entries, eq(entries.id, publishers.entryId))
|
||||
.where(and(eq(publishers.labelId, labelId), sql`${entries.id} in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`) as any);
|
||||
const total = Number((countRows as any)[0]?.total ?? 0);
|
||||
.where(and(eq(publishers.labelId, labelId), sql`${entries.id} in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`));
|
||||
const total = Number((countRows)[0]?.total ?? 0);
|
||||
const items = await db
|
||||
.select({
|
||||
id: entries.id,
|
||||
@@ -604,15 +635,15 @@ export async function getLabelPublishedEntries(labelId: number, params: LabelCon
|
||||
})
|
||||
.from(publishers)
|
||||
.innerJoin(entries, eq(entries.id, publishers.entryId))
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId as any))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId as any))
|
||||
.where(and(eq(publishers.labelId, labelId), sql`${entries.id} in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`) as any)
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId))
|
||||
.where(and(eq(publishers.labelId, labelId), sql`${entries.id} in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`))
|
||||
.groupBy(entries.id)
|
||||
.orderBy(entries.title)
|
||||
.limit(pageSize)
|
||||
.offset(offset);
|
||||
|
||||
return { items: items as any, page, pageSize, total };
|
||||
return { items: items, page, pageSize, total };
|
||||
}
|
||||
|
||||
// ----- Lookups lists and category browsing -----
|
||||
@@ -646,10 +677,10 @@ export async function searchLanguages(params: SimpleSearchParams) {
|
||||
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 }[]>,
|
||||
db.select({ total: sql<number>`count(*)` }).from(languages),
|
||||
]);
|
||||
const total = Number(countRows?.[0]?.total ?? 0);
|
||||
return { items: items as any, page, pageSize, total };
|
||||
return { items, page, pageSize, total };
|
||||
}
|
||||
|
||||
const pattern = `%${q}%`;
|
||||
@@ -657,14 +688,14 @@ export async function searchLanguages(params: SimpleSearchParams) {
|
||||
db
|
||||
.select()
|
||||
.from(languages)
|
||||
.where(like(languages.name as any, pattern))
|
||||
.where(like(languages.name, 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 }[]>,
|
||||
db.select({ total: sql<number>`count(*)` }).from(languages).where(like(languages.name, pattern)),
|
||||
]);
|
||||
const total = Number(countRows?.[0]?.total ?? 0);
|
||||
return { items: items as any, page, pageSize, total };
|
||||
return { items, page, pageSize, total };
|
||||
}
|
||||
|
||||
export async function searchGenres(params: SimpleSearchParams) {
|
||||
@@ -676,10 +707,10 @@ export async function searchGenres(params: SimpleSearchParams) {
|
||||
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 }[]>,
|
||||
db.select({ total: sql<number>`count(*)` }).from(genretypes),
|
||||
]);
|
||||
const total = Number(countRows?.[0]?.total ?? 0);
|
||||
return { items: items as any, page, pageSize, total };
|
||||
return { items, page, pageSize, total };
|
||||
}
|
||||
|
||||
const pattern = `%${q}%`;
|
||||
@@ -687,14 +718,14 @@ export async function searchGenres(params: SimpleSearchParams) {
|
||||
db
|
||||
.select()
|
||||
.from(genretypes)
|
||||
.where(like(genretypes.name as any, pattern))
|
||||
.where(like(genretypes.name, 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 }[]>,
|
||||
db.select({ total: sql<number>`count(*)` }).from(genretypes).where(like(genretypes.name, pattern)),
|
||||
]);
|
||||
const total = Number(countRows?.[0]?.total ?? 0);
|
||||
return { items: items as any, page, pageSize, total };
|
||||
return { items, page, pageSize, total };
|
||||
}
|
||||
|
||||
export async function searchMachinetypes(params: SimpleSearchParams) {
|
||||
@@ -706,10 +737,10 @@ export async function searchMachinetypes(params: SimpleSearchParams) {
|
||||
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 }[]>,
|
||||
db.select({ total: sql<number>`count(*)` }).from(machinetypes),
|
||||
]);
|
||||
const total = Number(countRows?.[0]?.total ?? 0);
|
||||
return { items: items as any, page, pageSize, total };
|
||||
return { items, page, pageSize, total };
|
||||
}
|
||||
|
||||
const pattern = `%${q}%`;
|
||||
@@ -717,14 +748,14 @@ export async function searchMachinetypes(params: SimpleSearchParams) {
|
||||
db
|
||||
.select()
|
||||
.from(machinetypes)
|
||||
.where(like(machinetypes.name as any, pattern))
|
||||
.where(like(machinetypes.name, 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 }[]>,
|
||||
db.select({ total: sql<number>`count(*)` }).from(machinetypes).where(like(machinetypes.name, pattern)),
|
||||
]);
|
||||
const total = Number(countRows?.[0]?.total ?? 0);
|
||||
return { items: items as any, page, pageSize, total };
|
||||
const total = Number((countRows as { total: number }[])[0]?.total ?? 0);
|
||||
return { items, page, pageSize, total };
|
||||
}
|
||||
|
||||
export async function entriesByGenre(
|
||||
@@ -737,10 +768,10 @@ export async function entriesByGenre(
|
||||
const hasQ = !!(q && q.trim());
|
||||
|
||||
if (!hasQ) {
|
||||
const countRows = (await db
|
||||
const countRows = await db
|
||||
.select({ total: sql<number>`count(*)` })
|
||||
.from(entries)
|
||||
.where(eq(entries.genretypeId, genreId as any))) as unknown as { total: number }[];
|
||||
.where(eq(entries.genretypeId, genreId));
|
||||
const items = await db
|
||||
.select({
|
||||
id: entries.id,
|
||||
@@ -752,21 +783,21 @@ export async function entriesByGenre(
|
||||
languageName: languages.name,
|
||||
})
|
||||
.from(entries)
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId as any))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId as any))
|
||||
.where(eq(entries.genretypeId, genreId as any))
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId))
|
||||
.where(eq(entries.genretypeId, genreId))
|
||||
.orderBy(entries.title)
|
||||
.limit(pageSize)
|
||||
.offset(offset);
|
||||
return { items: items as any, page, pageSize, total: Number(countRows?.[0]?.total ?? 0) };
|
||||
return { items, page, pageSize, total: Number(countRows?.[0]?.total ?? 0) };
|
||||
}
|
||||
|
||||
const pattern = `%${q!.toLowerCase().replace(/[^a-z0-9]+/g, "")}%`;
|
||||
const countRows = await db
|
||||
.select({ total: sql<number>`count(distinct ${entries.id})` })
|
||||
.from(entries)
|
||||
.where(and(eq(entries.genretypeId, genreId as any), sql`id in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`) as any);
|
||||
const total = Number((countRows as any)[0]?.total ?? 0);
|
||||
.where(and(eq(entries.genretypeId, genreId), sql`id in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`));
|
||||
const total = Number(countRows[0]?.total ?? 0);
|
||||
const items = await db
|
||||
.select({
|
||||
id: entries.id,
|
||||
@@ -778,14 +809,14 @@ export async function entriesByGenre(
|
||||
languageName: languages.name,
|
||||
})
|
||||
.from(entries)
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId as any))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId as any))
|
||||
.where(and(eq(entries.genretypeId, genreId as any), sql`id in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`) as any)
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId))
|
||||
.where(and(eq(entries.genretypeId, genreId), sql`id in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`))
|
||||
.groupBy(entries.id)
|
||||
.orderBy(entries.title)
|
||||
.limit(pageSize)
|
||||
.offset(offset);
|
||||
return { items: items as any, page, pageSize, total };
|
||||
return { items, page, pageSize, total };
|
||||
}
|
||||
|
||||
export async function entriesByLanguage(
|
||||
@@ -798,10 +829,10 @@ export async function entriesByLanguage(
|
||||
const hasQ = !!(q && q.trim());
|
||||
|
||||
if (!hasQ) {
|
||||
const countRows = (await db
|
||||
const countRows = await db
|
||||
.select({ total: sql<number>`count(*)` })
|
||||
.from(entries)
|
||||
.where(eq(entries.languageId, langId as any))) as unknown as { total: number }[];
|
||||
.where(eq(entries.languageId, langId));
|
||||
const items = await db
|
||||
.select({
|
||||
id: entries.id,
|
||||
@@ -813,21 +844,21 @@ export async function entriesByLanguage(
|
||||
languageName: languages.name,
|
||||
})
|
||||
.from(entries)
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId as any))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId as any))
|
||||
.where(eq(entries.languageId, langId as any))
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId))
|
||||
.where(eq(entries.languageId, langId))
|
||||
.orderBy(entries.title)
|
||||
.limit(pageSize)
|
||||
.offset(offset);
|
||||
return { items: items as any, page, pageSize, total: Number(countRows?.[0]?.total ?? 0) };
|
||||
return { items, page, pageSize, total: Number(countRows?.[0]?.total ?? 0) };
|
||||
}
|
||||
|
||||
const pattern = `%${q!.toLowerCase().replace(/[^a-z0-9]+/g, "")}%`;
|
||||
const countRows = await db
|
||||
.select({ total: sql<number>`count(distinct ${entries.id})` })
|
||||
.from(entries)
|
||||
.where(and(eq(entries.languageId, langId as any), sql`id in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`) as any);
|
||||
const total = Number((countRows as any)[0]?.total ?? 0);
|
||||
.where(and(eq(entries.languageId, langId), sql`id in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`));
|
||||
const total = Number(countRows[0]?.total ?? 0);
|
||||
const items = await db
|
||||
.select({
|
||||
id: entries.id,
|
||||
@@ -839,14 +870,14 @@ export async function entriesByLanguage(
|
||||
languageName: languages.name,
|
||||
})
|
||||
.from(entries)
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId as any))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId as any))
|
||||
.where(and(eq(entries.languageId, langId as any), sql`id in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`) as any)
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId))
|
||||
.where(and(eq(entries.languageId, langId), sql`id in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`))
|
||||
.groupBy(entries.id)
|
||||
.orderBy(entries.title)
|
||||
.limit(pageSize)
|
||||
.offset(offset);
|
||||
return { items: items as any, page, pageSize, total };
|
||||
return { items, page, pageSize, total };
|
||||
}
|
||||
|
||||
export async function entriesByMachinetype(
|
||||
@@ -859,10 +890,10 @@ export async function entriesByMachinetype(
|
||||
const hasQ = !!(q && q.trim());
|
||||
|
||||
if (!hasQ) {
|
||||
const countRows = (await db
|
||||
const countRows = await db
|
||||
.select({ total: sql<number>`count(*)` })
|
||||
.from(entries)
|
||||
.where(eq(entries.machinetypeId, mtId as any))) as unknown as { total: number }[];
|
||||
.where(eq(entries.machinetypeId, mtId));
|
||||
const items = await db
|
||||
.select({
|
||||
id: entries.id,
|
||||
@@ -874,21 +905,21 @@ export async function entriesByMachinetype(
|
||||
languageName: languages.name,
|
||||
})
|
||||
.from(entries)
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId as any))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId as any))
|
||||
.where(eq(entries.machinetypeId, mtId as any))
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId))
|
||||
.where(eq(entries.machinetypeId, mtId))
|
||||
.orderBy(entries.title)
|
||||
.limit(pageSize)
|
||||
.offset(offset);
|
||||
return { items: items as any, page, pageSize, total: Number(countRows?.[0]?.total ?? 0) };
|
||||
return { items, page, pageSize, total: Number(countRows?.[0]?.total ?? 0) };
|
||||
}
|
||||
|
||||
const pattern = `%${q!.toLowerCase().replace(/[^a-z0-9]+/g, "")}%`;
|
||||
const countRows = await db
|
||||
.select({ total: sql<number>`count(distinct ${entries.id})` })
|
||||
.from(entries)
|
||||
.where(and(eq(entries.machinetypeId, mtId as any), sql`id in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`) as any);
|
||||
const total = Number((countRows as any)[0]?.total ?? 0);
|
||||
.where(and(eq(entries.machinetypeId, mtId), sql`id in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`));
|
||||
const total = Number(countRows[0]?.total ?? 0);
|
||||
const items = await db
|
||||
.select({
|
||||
id: entries.id,
|
||||
@@ -900,14 +931,14 @@ export async function entriesByMachinetype(
|
||||
languageName: languages.name,
|
||||
})
|
||||
.from(entries)
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId as any))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId as any))
|
||||
.where(and(eq(entries.machinetypeId, mtId as any), sql`id in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`) as any)
|
||||
.leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId))
|
||||
.leftJoin(languages, eq(languages.id, entries.languageId))
|
||||
.where(and(eq(entries.machinetypeId, mtId), sql`id in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`))
|
||||
.groupBy(entries.id)
|
||||
.orderBy(entries.title)
|
||||
.limit(pageSize)
|
||||
.offset(offset);
|
||||
return { items: items as any, page, pageSize, total };
|
||||
return { items, page, pageSize, total };
|
||||
}
|
||||
|
||||
// ----- Facets for search -----
|
||||
@@ -917,7 +948,7 @@ export async function getEntryFacets(params: SearchParams): Promise<EntryFacets>
|
||||
const pattern = q ? `%${q.toLowerCase().replace(/[^a-z0-9]+/g, "")}%` : null;
|
||||
|
||||
// Build base WHERE SQL snippet considering q + filters
|
||||
const whereParts: any[] = [];
|
||||
const whereParts: Array<ReturnType<typeof sql>> = [];
|
||||
if (pattern) {
|
||||
whereParts.push(sql`id in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`);
|
||||
}
|
||||
@@ -925,7 +956,7 @@ export async function getEntryFacets(params: SearchParams): Promise<EntryFacets>
|
||||
if (params.languageId) whereParts.push(sql`${entries.languageId} = ${params.languageId}`);
|
||||
if (params.machinetypeId) whereParts.push(sql`${entries.machinetypeId} = ${params.machinetypeId}`);
|
||||
|
||||
const whereSql = whereParts.length ? sql.join([sql`where `, sql.join(whereParts as any, sql` and `)], sql``) : sql``;
|
||||
const whereSql = whereParts.length ? sql.join([sql`where `, sql.join(whereParts, sql` and `)], sql``) : sql``;
|
||||
|
||||
// Genres facet
|
||||
const genresRows = await db.execute(sql`
|
||||
@@ -935,7 +966,7 @@ export async function getEntryFacets(params: SearchParams): Promise<EntryFacets>
|
||||
${whereSql}
|
||||
group by e.genretype_id, gt.text
|
||||
order by count desc, name asc
|
||||
`) as any;
|
||||
`);
|
||||
|
||||
// Languages facet
|
||||
const langRows = await db.execute(sql`
|
||||
@@ -945,7 +976,7 @@ export async function getEntryFacets(params: SearchParams): Promise<EntryFacets>
|
||||
${whereSql}
|
||||
group by e.language_id, l.text
|
||||
order by count desc, name asc
|
||||
`) as any;
|
||||
`);
|
||||
|
||||
// Machinetypes facet
|
||||
const mtRows = await db.execute(sql`
|
||||
@@ -955,12 +986,19 @@ export async function getEntryFacets(params: SearchParams): Promise<EntryFacets>
|
||||
${whereSql}
|
||||
group by e.machinetype_id, m.text
|
||||
order by count desc, name asc
|
||||
`) as any;
|
||||
`);
|
||||
|
||||
type FacetRow = { id: number | string | null; name: string | null; count: number | string };
|
||||
return {
|
||||
genres: (genresRows as any[]).map((r: any) => ({ id: Number(r.id), name: r.name ?? "(none)", count: Number(r.count) })).filter((r) => !!r.id),
|
||||
languages: (langRows as any[]).map((r: any) => ({ id: String(r.id), name: r.name ?? "(none)", count: Number(r.count) })).filter((r) => !!r.id),
|
||||
machinetypes: (mtRows as any[]).map((r: any) => ({ id: Number(r.id), name: r.name ?? "(none)", count: Number(r.count) })).filter((r) => !!r.id),
|
||||
genres: (genresRows as unknown as FacetRow[])
|
||||
.map((r) => ({ id: Number(r.id), name: r.name ?? "(none)", count: Number(r.count) }))
|
||||
.filter((r) => !!r.id),
|
||||
languages: (langRows as unknown as FacetRow[])
|
||||
.map((r) => ({ id: String(r.id), name: r.name ?? "(none)", count: Number(r.count) }))
|
||||
.filter((r) => !!r.id),
|
||||
machinetypes: (mtRows as unknown as FacetRow[])
|
||||
.map((r) => ({ id: Number(r.id), name: r.name ?? "(none)", count: Number(r.count) }))
|
||||
.filter((r) => !!r.id),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -996,20 +1034,20 @@ export async function searchReleases(params: ReleaseSearchParams): Promise<Paged
|
||||
const offset = (page - 1) * pageSize;
|
||||
|
||||
// Build WHERE conditions in Drizzle QB
|
||||
const wherePartsQB: any[] = [];
|
||||
const wherePartsQB: Array<ReturnType<typeof sql>> = [];
|
||||
if (q) {
|
||||
const pattern = `%${q.toLowerCase().replace(/[^a-z0-9]+/g, "")}%`;
|
||||
wherePartsQB.push(sql`${releases.entryId} in (select ${searchByTitles.entryId} from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`);
|
||||
}
|
||||
if (params.year != null) {
|
||||
wherePartsQB.push(eq(releases.releaseYear as any, params.year as any));
|
||||
wherePartsQB.push(eq(releases.releaseYear, params.year));
|
||||
}
|
||||
|
||||
// Optional filters via downloads table: use EXISTS for performance and correctness
|
||||
// IMPORTANT: when hand-writing SQL with an aliased table, we must render
|
||||
// "from downloads as d" explicitly; using only the alias identifier ("d")
|
||||
// would produce "from `d`" which MySQL interprets as a literal table.
|
||||
const dlConds: any[] = [];
|
||||
const dlConds: Array<ReturnType<typeof sql>> = [];
|
||||
if (params.dLanguageId) dlConds.push(sql`d.language_id = ${params.dLanguageId}`);
|
||||
if (params.dMachinetypeId != null) dlConds.push(sql`d.machinetype_id = ${params.dMachinetypeId}`);
|
||||
if (params.filetypeId != null) dlConds.push(sql`d.filetype_id = ${params.filetypeId}`);
|
||||
@@ -1024,34 +1062,41 @@ export async function searchReleases(params: ReleaseSearchParams): Promise<Paged
|
||||
sql`d.release_seq = ${releases.releaseSeq}`,
|
||||
...dlConds,
|
||||
];
|
||||
wherePartsQB.push(
|
||||
sql`exists (select 1 from ${downloads} as d where ${sql.join(baseConds as any, sql` and `)})`
|
||||
);
|
||||
wherePartsQB.push(sql`exists (select 1 from ${downloads} as d where ${sql.join(baseConds, sql` and `)})`);
|
||||
}
|
||||
const whereExpr = wherePartsQB.length ? and(...(wherePartsQB as any)) : undefined;
|
||||
const whereExpr = wherePartsQB.length ? and(...wherePartsQB) : undefined;
|
||||
|
||||
// Count total
|
||||
const countRows = (await db
|
||||
const countRows = await db
|
||||
.select({ total: sql<number>`count(*)` })
|
||||
.from(releases)
|
||||
.where(whereExpr as any)) as unknown as { total: number }[];
|
||||
.where(whereExpr ?? sql`true`);
|
||||
const total = Number(countRows?.[0]?.total ?? 0);
|
||||
|
||||
// Rows via Drizzle QB to avoid tuple/field leakage
|
||||
const orderByParts: any[] = [];
|
||||
let orderBy1;
|
||||
let orderBy2;
|
||||
let orderBy3;
|
||||
switch (params.sort) {
|
||||
case "year_asc":
|
||||
orderByParts.push(asc(releases.releaseYear as any), asc(releases.entryId as any), asc(releases.releaseSeq as any));
|
||||
orderBy1 = asc(releases.releaseYear);
|
||||
orderBy2 = asc(releases.entryId);
|
||||
orderBy3 = asc(releases.releaseSeq);
|
||||
break;
|
||||
case "title":
|
||||
orderByParts.push(asc(entries.title as any), desc(releases.releaseYear as any), asc(releases.releaseSeq as any));
|
||||
orderBy1 = asc(entries.title);
|
||||
orderBy2 = desc(releases.releaseYear);
|
||||
orderBy3 = asc(releases.releaseSeq);
|
||||
break;
|
||||
case "entry_id_desc":
|
||||
orderByParts.push(desc(releases.entryId as any), desc(releases.releaseSeq as any));
|
||||
orderBy1 = desc(releases.entryId);
|
||||
orderBy2 = desc(releases.releaseSeq);
|
||||
break;
|
||||
case "year_desc":
|
||||
default:
|
||||
orderByParts.push(desc(releases.releaseYear as any), desc(releases.entryId as any), desc(releases.releaseSeq as any));
|
||||
orderBy1 = desc(releases.releaseYear);
|
||||
orderBy2 = desc(releases.entryId);
|
||||
orderBy3 = desc(releases.releaseSeq);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1063,14 +1108,14 @@ export async function searchReleases(params: ReleaseSearchParams): Promise<Paged
|
||||
year: releases.releaseYear,
|
||||
})
|
||||
.from(releases)
|
||||
.leftJoin(entries, eq(entries.id as any, releases.entryId as any))
|
||||
.where(whereExpr as any)
|
||||
.orderBy(...(orderByParts as any))
|
||||
.leftJoin(entries, eq(entries.id, releases.entryId))
|
||||
.where(whereExpr ?? sql`true`)
|
||||
.orderBy(orderBy1!, ...(orderBy2 ? [orderBy2] : []), ...(orderBy3 ? [orderBy3] : []))
|
||||
.limit(pageSize)
|
||||
.offset(offset);
|
||||
|
||||
// Ensure plain primitives
|
||||
const items: ReleaseListItem[] = rowsQB.map((r: any) => ({
|
||||
const items: ReleaseListItem[] = rowsQB.map((r) => ({
|
||||
entryId: Number(r.entryId),
|
||||
releaseSeq: Number(r.releaseSeq),
|
||||
entryTitle: r.entryTitle ?? "",
|
||||
|
||||
Reference in New Issue
Block a user