From 208a06c3518094f90be674113a3d7f3d39192d55 Mon Sep 17 00:00:00 2001 From: "D. Rimron-Soutter" Date: Sat, 10 Jan 2026 16:55:12 +0000 Subject: [PATCH] Adding more releases, and sorting SASS --- next.config.ts | 12 + src/app/zxdb/releases/ReleasesExplorer.tsx | 8 +- src/server/repo/zxdb.ts | 351 ++++++++++++++++++++- 3 files changed, 363 insertions(+), 8 deletions(-) diff --git a/next.config.ts b/next.config.ts index db0a372..7a50060 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,6 +1,18 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { + sassOptions: { + // Silence noisy deprecation warnings coming from dependencies like Bootstrap. + quietDeps: true, + // Dart Sass deprecations still trigger via @import; explicitly mute them. + silenceDeprecations: [ + "import", + "global-builtin", + "if-function", + "legacy-js-api", + "color-functions", + ], + }, }; export default nextConfig; diff --git a/src/app/zxdb/releases/ReleasesExplorer.tsx b/src/app/zxdb/releases/ReleasesExplorer.tsx index 80f6e5b..6d15037 100644 --- a/src/app/zxdb/releases/ReleasesExplorer.tsx +++ b/src/app/zxdb/releases/ReleasesExplorer.tsx @@ -307,7 +307,7 @@ export default function ReleasesExplorer({ Entry ID Title - Release # + Release # Year @@ -320,7 +320,11 @@ export default function ReleasesExplorer({ - #{it.releaseSeq} + + + #{it.releaseSeq} + + {it.year ?? -} ))} diff --git a/src/server/repo/zxdb.ts b/src/server/repo/zxdb.ts index 0cc722a..0b43a14 100644 --- a/src/server/repo/zxdb.ts +++ b/src/server/repo/zxdb.ts @@ -14,6 +14,7 @@ import { filetypes, releases, downloads, + scraps, schemetypes, sourcetypes, casetypes, @@ -26,6 +27,7 @@ import { magazines, issues, magrefs, + searchByMagrefs, referencetypes, } from "@/server/schema/zxdb"; @@ -877,7 +879,7 @@ export async function entriesByGenre( const countRows = await db .select({ total: sql`count(distinct ${entries.id})` }) .from(entries) - .where(and(eq(entries.genretypeId, genreId), sql`id in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`)); + .where(and(eq(entries.genretypeId, genreId), 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({ @@ -892,7 +894,7 @@ export async function entriesByGenre( .from(entries) .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})`)) + .where(and(eq(entries.genretypeId, genreId), sql`${entries.id} in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`)) .groupBy(entries.id) .orderBy(entries.title) .limit(pageSize) @@ -938,7 +940,7 @@ export async function entriesByLanguage( const countRows = await db .select({ total: sql`count(distinct ${entries.id})` }) .from(entries) - .where(and(eq(entries.languageId, langId), sql`id in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`)); + .where(and(eq(entries.languageId, langId), 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({ @@ -953,7 +955,7 @@ export async function entriesByLanguage( .from(entries) .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})`)) + .where(and(eq(entries.languageId, langId), sql`${entries.id} in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`)) .groupBy(entries.id) .orderBy(entries.title) .limit(pageSize) @@ -999,7 +1001,7 @@ export async function entriesByMachinetype( const countRows = await db .select({ total: sql`count(distinct ${entries.id})` }) .from(entries) - .where(and(eq(entries.machinetypeId, mtId), sql`id in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`)); + .where(and(eq(entries.machinetypeId, mtId), 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({ @@ -1014,7 +1016,7 @@ export async function entriesByMachinetype( .from(entries) .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})`)) + .where(and(eq(entries.machinetypeId, mtId), sql`${entries.id} in (select entry_id from ${searchByTitles} where ${searchByTitles.entryTitle} like ${pattern})`)) .groupBy(entries.id) .orderBy(entries.title) .limit(pageSize) @@ -1206,6 +1208,343 @@ export async function searchReleases(params: ReleaseSearchParams): Promise; + scraps: Array<{ + id: number; + link: string | null; + size: number | null; + comments: string | null; + rationale: string; + isDemo: boolean; + type: { id: number; name: string }; + language: { id: string | null; name: string | null }; + machinetype: { id: number | null; name: string | null }; + scheme: { id: string | null; name: string | null }; + source: { id: string | null; name: string | null }; + case: { id: string | null; name: string | null }; + year: number | null; + }>; + files: Array<{ + id: number; + link: string; + size: number | null; + md5: string | null; + comments: string | null; + type: { id: number; name: string }; + }>; + magazineRefs: Array<{ + id: number; + issueId: number; + magazineId: number | null; + magazineName: string | null; + referencetypeId: number; + referencetypeName: string | null; + page: number; + isOriginal: number; + scoreGroup: string; + issue: { + dateYear: number | null; + dateMonth: number | null; + dateDay: number | null; + volume: number | null; + number: number | null; + special: string | null; + supplement: string | null; + }; + }>; +} + +export async function getReleaseDetail(entryId: number, releaseSeq: number): Promise { + const rows = await db + .select({ + entryId: releases.entryId, + releaseSeq: releases.releaseSeq, + year: releases.releaseYear, + month: releases.releaseMonth, + day: releases.releaseDay, + currencyId: releases.currencyId, + currencyName: currencies.name, + currencySymbol: currencies.symbol, + currencyPrefix: currencies.prefix, + releasePrice: releases.releasePrice, + budgetPrice: releases.budgetPrice, + microdrivePrice: releases.microdrivePrice, + diskPrice: releases.diskPrice, + cartridgePrice: releases.cartridgePrice, + bookIsbn: releases.bookIsbn, + bookPages: releases.bookPages, + entryTitle: entries.title, + issueId: entries.issueId, + }) + .from(releases) + .leftJoin(entries, eq(entries.id, releases.entryId)) + .leftJoin(currencies, eq(currencies.id, releases.currencyId)) + .where(and(eq(releases.entryId, entryId), eq(releases.releaseSeq, releaseSeq))) + .limit(1); + + const base = rows[0]; + if (!base) return null; + + type DownloadRow = { + id: 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; + }; + type ScrapRow = DownloadRow & { rationale: string }; + + const downloadRows = await db + .select({ + id: downloads.id, + link: downloads.fileLink, + size: downloads.fileSize, + md5: downloads.fileMd5, + comments: downloads.comments, + isDemo: downloads.isDemo, + filetypeId: filetypes.id, + filetypeName: filetypes.name, + dlLangId: downloads.languageId, + dlLangName: languages.name, + dlMachineId: downloads.machinetypeId, + dlMachineName: machinetypes.name, + schemeId: schemetypes.id, + schemeName: schemetypes.name, + sourceId: sourcetypes.id, + sourceName: sourcetypes.name, + caseId: casetypes.id, + caseName: casetypes.name, + year: downloads.releaseYear, + }) + .from(downloads) + .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(and(eq(downloads.entryId, entryId), eq(downloads.releaseSeq, releaseSeq))); + + const scrapRows = await db + .select({ + id: scraps.id, + link: scraps.fileLink, + size: scraps.fileSize, + comments: scraps.comments, + rationale: scraps.rationale, + isDemo: scraps.isDemo, + filetypeId: filetypes.id, + filetypeName: filetypes.name, + dlLangId: scraps.languageId, + dlLangName: languages.name, + dlMachineId: scraps.machinetypeId, + dlMachineName: machinetypes.name, + schemeId: schemetypes.id, + schemeName: schemetypes.name, + sourceId: sourcetypes.id, + sourceName: sourcetypes.name, + caseId: casetypes.id, + caseName: casetypes.name, + year: scraps.releaseYear, + }) + .from(scraps) + .innerJoin(filetypes, eq(filetypes.id, scraps.filetypeId)) + .leftJoin(languages, eq(languages.id, scraps.languageId)) + .leftJoin(machinetypes, eq(machinetypes.id, scraps.machinetypeId)) + .leftJoin(schemetypes, eq(schemetypes.id, scraps.schemetypeId)) + .leftJoin(sourcetypes, eq(sourcetypes.id, scraps.sourcetypeId)) + .leftJoin(casetypes, eq(casetypes.id, scraps.casetypeId)) + .where(and(eq(scraps.entryId, entryId), eq(scraps.releaseSeq, releaseSeq))); + + const fileRows = base.issueId != null ? await db + .select({ + id: files.id, + link: files.fileLink, + size: files.fileSize, + md5: files.fileMd5, + comments: files.comments, + typeId: filetypes.id, + typeName: filetypes.name, + }) + .from(files) + .innerJoin(filetypes, eq(filetypes.id, files.filetypeId)) + .where(eq(files.issueId, base.issueId)) : []; + + const magazineRefs = await db + .select({ + id: magrefs.id, + issueId: magrefs.issueId, + magazineId: magazines.id, + magazineName: magazines.name, + referencetypeId: magrefs.referencetypeId, + referencetypeName: referencetypes.name, + page: magrefs.page, + isOriginal: magrefs.isOriginal, + scoreGroup: magrefs.scoreGroup, + issueDateYear: issues.dateYear, + issueDateMonth: issues.dateMonth, + issueDateDay: issues.dateDay, + issueVolume: issues.volume, + issueNumber: issues.number, + issueSpecial: issues.special, + issueSupplement: issues.supplement, + }) + .from(searchByMagrefs) + .innerJoin(magrefs, eq(magrefs.id, searchByMagrefs.magrefId)) + .leftJoin(issues, eq(issues.id, magrefs.issueId)) + .leftJoin(magazines, eq(magazines.id, issues.magazineId)) + .leftJoin(referencetypes, eq(referencetypes.id, magrefs.referencetypeId)) + .where(eq(searchByMagrefs.entryId, entryId)) + .orderBy( + asc(magazines.name), + asc(issues.dateYear), + asc(issues.dateMonth), + asc(issues.id), + asc(magrefs.page), + asc(magrefs.id), + ); + + return { + entry: { + id: Number(base.entryId), + title: base.entryTitle ?? "", + issueId: base.issueId ?? null, + }, + release: { + entryId: Number(base.entryId), + releaseSeq: Number(base.releaseSeq), + year: base.year != null ? Number(base.year) : null, + month: base.month != null ? Number(base.month) : null, + day: base.day != null ? Number(base.day) : null, + currency: { + id: base.currencyId ?? null, + name: base.currencyName ?? null, + symbol: base.currencySymbol ?? null, + prefix: base.currencyPrefix != null ? Number(base.currencyPrefix) : null, + }, + prices: { + release: base.releasePrice != null ? Number(base.releasePrice) : null, + budget: base.budgetPrice != null ? Number(base.budgetPrice) : null, + microdrive: base.microdrivePrice != null ? Number(base.microdrivePrice) : null, + disk: base.diskPrice != null ? Number(base.diskPrice) : null, + cartridge: base.cartridgePrice != null ? Number(base.cartridgePrice) : null, + }, + book: { + isbn: base.bookIsbn ?? null, + pages: base.bookPages != null ? Number(base.bookPages) : null, + }, + }, + downloads: (downloadRows as DownloadRow[]).map((d) => ({ + id: Number(d.id), + link: d.link, + size: d.size != null ? Number(d.size) : null, + md5: d.md5 ?? null, + comments: d.comments ?? null, + isDemo: !!d.isDemo, + type: { id: Number(d.filetypeId), name: d.filetypeName }, + language: { id: d.dlLangId ?? null, name: d.dlLangName ?? null }, + machinetype: { id: d.dlMachineId != null ? Number(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 ? Number(d.year) : null, + })), + scraps: (scrapRows as ScrapRow[]).map((s) => ({ + id: Number(s.id), + link: s.link ?? null, + size: s.size != null ? Number(s.size) : null, + comments: s.comments ?? null, + rationale: s.rationale ?? "", + isDemo: !!s.isDemo, + type: { id: Number(s.filetypeId), name: s.filetypeName }, + language: { id: s.dlLangId ?? null, name: s.dlLangName ?? null }, + machinetype: { id: s.dlMachineId != null ? Number(s.dlMachineId) : null, name: s.dlMachineName ?? null }, + scheme: { id: s.schemeId ?? null, name: s.schemeName ?? null }, + source: { id: s.sourceId ?? null, name: s.sourceName ?? null }, + case: { id: s.caseId ?? null, name: s.caseName ?? null }, + year: s.year != null ? Number(s.year) : null, + })), + files: fileRows.map((f) => ({ + id: f.id, + link: f.link, + size: f.size ?? null, + md5: f.md5 ?? null, + comments: f.comments ?? null, + type: { id: f.typeId, name: f.typeName }, + })), + magazineRefs: magazineRefs.map((m) => ({ + id: m.id, + issueId: Number(m.issueId), + magazineId: m.magazineId != null ? Number(m.magazineId) : null, + magazineName: m.magazineName ?? null, + referencetypeId: Number(m.referencetypeId), + referencetypeName: m.referencetypeName ?? null, + page: Number(m.page), + isOriginal: Number(m.isOriginal), + scoreGroup: m.scoreGroup ?? "", + issue: { + dateYear: m.issueDateYear != null ? Number(m.issueDateYear) : null, + dateMonth: m.issueDateMonth != null ? Number(m.issueDateMonth) : null, + dateDay: m.issueDateDay != null ? Number(m.issueDateDay) : null, + volume: m.issueVolume != null ? Number(m.issueVolume) : null, + number: m.issueNumber != null ? Number(m.issueNumber) : null, + special: m.issueSpecial ?? null, + supplement: m.issueSupplement ?? null, + }, + })), + }; +} + // ----- Download/lookups simple lists ----- export async function listFiletypes() { return db.select().from(filetypes).orderBy(filetypes.name);