// Command seed-bg-intro seeds the Bhagavad-gītā front-matter (Dedication, // Foreword, Preface, Introduction, The Disciplic Succession) into the // `prose_chapters` MongoDB collection as intro-segments (book="bg", volume=0). // // The segment JSON is produced by extractor/scripts/bg_intro_extract.py. // // Usage (from the spsays-bff directory, so .env is picked up): // // go run ./cmd/seed-bg-intro // go run ./cmd/seed-bg-intro --dir ../extractor/jsons/books/bg/intro // // It is idempotent: existing bg intro-segments are removed before insert. package main import ( "context" "encoding/json" "flag" "fmt" "os" "path/filepath" "sort" "time" "go.uber.org/zap" "github.com/prabhupadasays/spsays-bff/internal/config" "github.com/prabhupadasays/spsays-bff/internal/repository" ) type introSegment struct { Slug string `json:"slug"` Title string `json:"title"` Type string `json:"type"` Book string `json:"book"` Volume int `json:"volume"` Order int `json:"order"` Paragraphs []string `json:"paragraphs"` } func main() { dir := flag.String("dir", "../extractor/jsons/books/bg/intro", "directory containing bg intro-segment JSON files") flag.Parse() cfg, err := config.Load() if err != nil { fmt.Fprintf(os.Stderr, "failed to load config: %v\n", err) os.Exit(1) } logger, _ := zap.NewDevelopment() defer logger.Sync() sugar := logger.Sugar() mongoDB, err := repository.NewMongoDB(cfg.MongoURI, cfg.MongoDB, logger) if err != nil { sugar.Fatalf("failed to connect to MongoDB: %v", err) } defer mongoDB.Close() entries, err := os.ReadDir(*dir) if err != nil { sugar.Fatalf("failed to read dir %s: %v", *dir, err) } var segments []introSegment var files []string for _, e := range entries { if e.IsDir() || filepath.Ext(e.Name()) != ".json" { continue } files = append(files, e.Name()) } sort.Strings(files) for _, name := range files { raw, err := os.ReadFile(filepath.Join(*dir, name)) if err != nil { sugar.Fatalf("read %s: %v", name, err) } var seg introSegment if err := json.Unmarshal(raw, &seg); err != nil { sugar.Fatalf("parse %s: %v", name, err) } if seg.Book != "bg" || seg.Type != "intro-segment" { sugar.Warnf("skipping %s (book=%q type=%q)", name, seg.Book, seg.Type) continue } segments = append(segments, seg) } if len(segments) == 0 { sugar.Fatal("no bg intro-segments found to seed") } ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() col := mongoDB.Collection("prose_chapters") // Idempotent: clear any previously seeded bg intro-segments. del, err := col.DeleteMany(ctx, map[string]any{ "book": "bg", "type": "intro-segment", }) if err != nil { sugar.Fatalf("delete existing bg intro-segments: %v", err) } sugar.Infof("removed %d existing bg intro-segment(s)", del.DeletedCount) docs := make([]any, 0, len(segments)) for _, seg := range segments { // chapter is intentionally null for intro-segments (matches the // ProseChapterDoc shape used by KB/NoD front matter). docs = append(docs, map[string]any{ "book": "bg", "volume": 0, "chapter": nil, "title": seg.Title, "type": "intro-segment", "slug": seg.Slug, "order": seg.Order, "paragraphs": seg.Paragraphs, }) sugar.Infof(" %s (order %d, %d paragraphs)", seg.Slug, seg.Order, len(seg.Paragraphs)) } res, err := col.InsertMany(ctx, docs) if err != nil { sugar.Fatalf("insert bg intro-segments: %v", err) } sugar.Infof("inserted %d bg intro-segment(s)", len(res.InsertedIDs)) }