/** * seed-nbs.ts — Push Nārada-bhakti-sūtra JSON data into MongoDB. * * Uses the native MongoDB driver (same pattern as seed-mm.ts) to avoid * Prisma replica-set write requirements. * * NBS is a verse book (like MM) with a single chapter and prose intro segments. * We use volume=0 as the sentinel for "no volumes" on the prose side. * * Collections written: * - book_meta → one doc { book: "nbs", data: } * - verses → 8 verse docs (Sūtras 1-8) * - prose_chapters → 1 intro segment doc (introduction) * * Usage: * npx tsx scripts/seed-nbs.ts */ import dotenv from "dotenv"; import fs from "fs"; import path from "path"; import { MongoClient } from "mongodb"; // Load env dotenv.config({ path: ".env.local" }); dotenv.config({ path: ".env" }); const DATABASE_URL = process.env.DATABASE_URL; if (!DATABASE_URL) { console.error("❌ DATABASE_URL is not set in .env"); process.exit(1); } const BASE_DIR = path.resolve(__dirname, ".."); const NBS_DIR = path.join(BASE_DIR, "lib", "jsons", "books", "nbs"); /** Volume sentinel for books without volumes. */ const NO_VOLUME = 0; // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- function readJson(filePath: string): T { return JSON.parse(fs.readFileSync(filePath, "utf-8")); } /** * Insert documents one at a time with a small delay every N docs. * Uses insertOne to avoid BSON wire-protocol corruption. */ async function insertBatched( col: ReturnType["collection"]>, docs: Record[], ) { for (let i = 0; i < docs.length; i++) { await col.insertOne(docs[i]); if ((i + 1) % 100 === 0) { await new Promise((r) => setTimeout(r, 100)); } } } // --------------------------------------------------------------------------- // Types for the JSON files // --------------------------------------------------------------------------- type NbsIntroJson = { book: string; title: string; author: string; year: number; description: string; totalChapters: number; chapters: { number: number; title: string; totalVerses: number }[]; }; type NbsVerseJson = { book_title: string; chapter: number; verse: number; reference: string; devanagari: string; transliteration: string; synonyms: { word: string; meanings: string[] }[]; translation: string; purport: string[]; }; type NbsIntroSegmentJson = { slug: string; title: string; type: string; book: string; order: number; paragraphs: string[]; }; // --------------------------------------------------------------------------- // Seed function // --------------------------------------------------------------------------- async function seedNbs(db: ReturnType) { const introPath = path.join(NBS_DIR, "intro.json"); if (!fs.existsSync(introPath)) { console.error("❌ NBS intro.json not found at", introPath); process.exit(1); } const intro = readJson(introPath); // ---- 1. Book meta ---- const metaCol = db.collection("book_meta"); await metaCol.deleteMany({ book: "nbs" }); await metaCol.insertOne({ book: "nbs", data: intro }); console.log(" 📖 NBS book meta inserted"); // ---- 2. Verses ---- const versesCol = db.collection("verses"); await versesCol.deleteMany({ book: "nbs" }); const verseDocs: Record[] = []; // Verse files: chapters/01/verses/01.json through 08.json const versesDir = path.join(NBS_DIR, "chapters", "01", "verses"); if (!fs.existsSync(versesDir)) { console.error("❌ NBS verses directory not found at", versesDir); process.exit(1); } const verseFiles = fs .readdirSync(versesDir) .filter((f) => f.endsWith(".json")) .sort(); for (const file of verseFiles) { const filePath = path.join(versesDir, file); if (!fs.existsSync(filePath)) { console.warn(` ⚠️ Verse file not found, skipping: ${file}`); continue; } const v = readJson(filePath); verseDocs.push({ book: "nbs", division: null, chapter: v.chapter, verse: v.verse, verseEnd: null, reference: v.reference, bookTitle: v.book_title, devanagari: v.devanagari, bengali: null, transliteration: v.transliteration, synonyms: v.synonyms, translation: v.translation, purport: v.purport, }); } console.log(` 📜 Verses prepared: ${verseDocs.length}`); console.log(` Inserting ${verseDocs.length} verse documents...`); await insertBatched(versesCol, verseDocs); const totalVerses = await versesCol.countDocuments({ book: "nbs" }); console.log(` ✅ NBS verses: ${totalVerses} in MongoDB`); // ---- 3. Prose intro segments ---- const proseCol = db.collection("prose_chapters"); await proseCol.deleteMany({ book: "nbs" }); const proseDocs: Record[] = []; const introSegmentFiles = ["introduction.json"]; const introDir = path.join(NBS_DIR, "intro"); for (const file of introSegmentFiles) { const filePath = path.join(introDir, file); if (!fs.existsSync(filePath)) { console.warn(` ⚠️ Intro segment not found, skipping: ${file}`); continue; } const seg = readJson(filePath); proseDocs.push({ book: "nbs", volume: NO_VOLUME, chapter: null, title: seg.title, type: seg.type || "intro-segment", slug: `intro-${seg.slug}`, order: seg.order, paragraphs: seg.paragraphs, }); } console.log(` 📄 Intro segments prepared: ${proseDocs.length}`); console.log(` Inserting ${proseDocs.length} prose documents...`); await insertBatched(proseCol, proseDocs); const totalProse = await proseCol.countDocuments({ book: "nbs" }); console.log(` ✅ NBS prose: ${totalProse} entries in MongoDB`); } // --------------------------------------------------------------------------- // Main // --------------------------------------------------------------------------- async function main() { console.log("🌱 Seeding Nārada-bhakti-sūtra...\n"); const client = new MongoClient(DATABASE_URL!); await client.connect(); console.log("📡 Connected to MongoDB\n"); const db = client.db(); const start = Date.now(); await seedNbs(db); const elapsed = ((Date.now() - start) / 1000).toFixed(1); console.log(`\n🎉 Done in ${elapsed}s`); await client.close(); } main().catch((err) => { console.error("❌ Seed failed:", err); process.exit(1); });