feat: sva extracted and seeded
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
/**
|
||||
* seed-bs.ts — Push Śrī Brahma-saṁhitā JSON data into MongoDB.
|
||||
*
|
||||
* Uses the native MongoDB driver (same pattern as seed-iso.ts) to avoid
|
||||
* Prisma replica-set write requirements.
|
||||
*
|
||||
* BS is a verse book (like ISO) but also has prose intro segments.
|
||||
* We use volume=0 as the sentinel for "no volumes" on the prose side.
|
||||
*
|
||||
* Collections written:
|
||||
* - book_meta → one doc { book: "bs", data: <intro.json> }
|
||||
* - verses → 62 verse docs (Texts 1-62)
|
||||
* - prose_chapters → 2 intro segment docs (introduction, foreword)
|
||||
*
|
||||
* Usage:
|
||||
* npx tsx scripts/seed-bs.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 BS_DIR = path.join(BASE_DIR, "lib", "jsons", "books", "bs");
|
||||
|
||||
/** 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 BsIntroJson = {
|
||||
book: string;
|
||||
title: string;
|
||||
author: string;
|
||||
year: number;
|
||||
description: string;
|
||||
totalChapters: number;
|
||||
chapters: { number: number; title: string; totalVerses: number }[];
|
||||
};
|
||||
|
||||
type BsVerseJson = {
|
||||
book_title: string;
|
||||
chapter: number;
|
||||
verse: number;
|
||||
reference: string;
|
||||
devanagari: string;
|
||||
transliteration: string;
|
||||
synonyms: { word: string; meanings: string[] }[];
|
||||
translation: string;
|
||||
purport: string[];
|
||||
};
|
||||
|
||||
type BsIntroSegmentJson = {
|
||||
slug: string;
|
||||
title: string;
|
||||
type: string;
|
||||
book: string;
|
||||
order: number;
|
||||
paragraphs: string[];
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Seed function
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function seedBs(db: ReturnType<MongoClient["db"]>) {
|
||||
const introPath = path.join(BS_DIR, "intro.json");
|
||||
if (!fs.existsSync(introPath)) {
|
||||
console.error("❌ BS intro.json not found at", introPath);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const intro = readJson<BsIntroJson>(introPath);
|
||||
|
||||
// ---- 1. Book meta ----
|
||||
const metaCol = db.collection("book_meta");
|
||||
await metaCol.deleteMany({ book: "bs" });
|
||||
await metaCol.insertOne({ book: "bs", data: intro });
|
||||
console.log(" 📖 BS book meta inserted");
|
||||
|
||||
// ---- 2. Verses ----
|
||||
const versesCol = db.collection("verses");
|
||||
await versesCol.deleteMany({ book: "bs" });
|
||||
|
||||
const verseDocs: Record<string, unknown>[] = [];
|
||||
|
||||
// Verse files: chapters/05/verses/01.json through 62.json
|
||||
const versesDir = path.join(BS_DIR, "chapters", "05", "verses");
|
||||
|
||||
if (!fs.existsSync(versesDir)) {
|
||||
console.error("❌ BS 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<BsVerseJson>(filePath);
|
||||
|
||||
verseDocs.push({
|
||||
book: "bs",
|
||||
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: "bs" });
|
||||
console.log(` ✅ BS verses: ${totalVerses} in MongoDB`);
|
||||
|
||||
// ---- 3. Prose intro segments ----
|
||||
const proseCol = db.collection("prose_chapters");
|
||||
await proseCol.deleteMany({ book: "bs" });
|
||||
|
||||
const proseDocs: Record<string, unknown>[] = [];
|
||||
|
||||
const introSegmentFiles = ["introduction.json", "foreword.json"];
|
||||
|
||||
const introDir = path.join(BS_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<BsIntroSegmentJson>(filePath);
|
||||
|
||||
proseDocs.push({
|
||||
book: "bs",
|
||||
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: "bs" });
|
||||
console.log(` ✅ BS prose: ${totalProse} entries in MongoDB`);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Main
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function main() {
|
||||
console.log("🌱 Seeding Śrī Brahma-saṁhitā...\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 seedBs(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);
|
||||
});
|
||||
Reference in New Issue
Block a user