91 lines · 3.4 KB · TypeScript
RawDownload
// Snapshots every published entry from the database back into// `src/data/problems.json` - the curated seed baseline and the repo's// disaster-recovery copy of the catalog.//// The database is the source of truth (community edits and imports live// there), so without periodic exports a fresh `db:seed` could only rebuild// the original launch set. Run `npm run db:export` after significant catalog// changes and commit the result.//// Round-trip safety: the seed upserts curated content by slug and never// touches votes, comments, status or submitter linkage, so exporting and// re-seeding a live database is a no-op for user state. On a FRESH database,// community-submitted entries are recreated as curator entries (the// submitter accounts don't exist there) - acceptable for recovery. import { writeFileSync } from "fs";import { join } from "path";import { PrismaClient } from "@prisma/client"; const prisma = new PrismaClient(); async function main() {  const rows = await prisma.problem.findMany({    where: { status: "published" },    orderBy: { slug: "asc" },    include: {      links: { select: { label: true, url: true }, orderBy: { position: "asc" } },      relationsFrom: {        select: { kind: true, note: true, to: { select: { slug: true } } },        orderBy: { position: "asc" },      },    },  });   const out = rows.map((p) => {    const entry: Record<string, unknown> = {      slug: p.slug,      name: p.name,      shortName: p.shortName,      problemNumber: p.problemNumber,      field: p.field,      fieldGroup: p.fieldGroup,      resolution: p.resolution,      statement: p.statement,      posedBy: p.posedBy,      yearPosed: p.yearPosed,      solveType: p.solveType,      solveDate: p.solveDate,      model: p.model,      modelMaker: p.modelMaker,      humanCollaborators: p.humanCollaborators,      aiRole: p.aiRole,      verification: p.verification,      verificationNote: p.verificationNote,      publication: p.publication,      resolutionMethod: p.resolutionMethod,      citations: p.citations,      citationsPaper: p.citationsPaper,      citationsSource: p.citationsSource,      citationsUrl: p.citationsUrl,      renownLangs: p.renownLangs,      sourceUrl: p.sourceUrl,      sourceName: p.sourceName,    };    // Optional caveat fields are present only on entries that need them,    // matching the documented JSON shape.    if (p.renownNote !== null) entry.renownNote = p.renownNote;    if (p.resultNote !== null) entry.resultNote = p.resultNote;    if (p.ageNote !== null) entry.ageNote = p.ageNote;    if (p.claimIssueNote !== null) entry.claimIssueNote = p.claimIssueNote;    if (p.aiContribution !== null) entry.aiContribution = p.aiContribution;    if (p.significance !== null) entry.significance = p.significance;    if (p.significanceNote !== null) entry.significanceNote = p.significanceNote;    if (Array.isArray(p.links) && p.links.length > 0) entry.links = p.links;    if (p.relationsFrom.length > 0) {      entry.relations = p.relationsFrom.map((r) => ({ to: r.to.slug, kind: r.kind, note: r.note }));    }    return entry;  });   const path = join(__dirname, "..", "src", "data", "problems.json");  writeFileSync(path, JSON.stringify(out, null, 2) + "\n");  console.log(`Exported ${out.length} published entries to src/data/problems.json`);} main()  .catch((error) => {    console.error(error);    process.exit(1);  })  .finally(() => prisma.$disconnect());