Files
spsays-training/scripts/seed-nbs.ts
T

234 lines
6.5 KiB
TypeScript

/**
* 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: <intro.json> }
* - 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<T>(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<ReturnType<MongoClient["db"]>["collection"]>,
docs: Record<string, unknown>[],
) {
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<MongoClient["db"]>) {
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<NbsIntroJson>(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<string, unknown>[] = [];
// 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<NbsVerseJson>(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<string, unknown>[] = [];
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<NbsIntroSegmentJson>(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);
});