SPB Git
1.8 KB · 21 lines typescript
1/** BibTeX → references (dedupe by DOI / cite key, same rules as src/lib/research/references.ts importBibtex, which is Next-only). */2import { and, eq, isNull } from "drizzle-orm";3import { db, schema } from "@/db";4import { parseBibtex } from "@/lib/research/bibtex";5import type { ImportCtx } from "./pages";6const R = schema.researchReferences;7export async function importBibtexRefs(ctx: ImportCtx, text: string, pageId: string | null) {8  const parsed = parseBibtex(text);9  const existing = await db.select({ id: R.id, citeKey: R.citeKey, doi: R.doi }).from(R).where(and(eq(R.workspaceId, ctx.workspaceId), isNull(R.deletedAt)));10  const byDoi = new Map(existing.filter((e) => e.doi).map((e) => [e.doi!, e])); const byKey = new Map(existing.map((e) => [e.citeKey.toLowerCase(), e]));11  const created: string[] = []; const skipped: { citeKey: string; reason: string }[] = []; const seen = new Set<string>();12  for (const p of parsed) {13    const dup = (p.doi && byDoi.get(p.doi)) || byKey.get(p.citeKey.toLowerCase());14    if (dup) { skipped.push({ citeKey: p.citeKey, reason: p.doi && byDoi.get(p.doi) ? `DOI already stored as ${dup.citeKey}` : "cite key already exists" }); continue; }15    const sig = p.doi ?? p.citeKey.toLowerCase(); if (seen.has(sig)) { skipped.push({ citeKey: p.citeKey, reason: "duplicate inside file" }); continue; } seen.add(sig);16    const [r] = await db.insert(R).values({ workspaceId: ctx.workspaceId, pageId, citeKey: p.citeKey, entryType: p.entryType, title: p.title, authors: p.authors, year: p.year, journal: p.journal, doi: p.doi, url: p.url, fields: p.fields, verified: "user", bibtex: p.bibtex }).returning({ id: R.id, citeKey: R.citeKey, doi: R.doi });17    created.push(r.id); if (r.doi) byDoi.set(r.doi, r); byKey.set(r.citeKey.toLowerCase(), r); ctx.stats.references++;18  }19  return { created: created.length, skipped, parsed: parsed.length };20}21
Files · main
Menu

Theme