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