package repository import ( "context" "go.mongodb.org/mongo-driver/v2/bson" "go.mongodb.org/mongo-driver/v2/mongo" "go.mongodb.org/mongo-driver/v2/mongo/options" ) type BookRepo struct { meta *mongo.Collection verses *mongo.Collection proseChapters *mongo.Collection } func NewBookRepo(db *MongoDB) *BookRepo { return &BookRepo{ meta: db.Collection("book_meta"), verses: db.Collection("verses"), proseChapters: db.Collection("prose_chapters"), } } // --- Book Meta --- type BookMetaDoc struct { ID bson.ObjectID `bson:"_id" json:"id"` Book string `bson:"book" json:"book"` Data interface{} `bson:"data" json:"data"` } func (r *BookRepo) GetAllBookMetas(ctx context.Context) ([]BookMetaDoc, error) { cursor, err := r.meta.Find(ctx, bson.M{}) if err != nil { return nil, err } defer cursor.Close(ctx) var results []BookMetaDoc if err := cursor.All(ctx, &results); err != nil { return nil, err } return results, nil } func (r *BookRepo) GetBookMeta(ctx context.Context, book string) (*BookMetaDoc, error) { var doc BookMetaDoc err := r.meta.FindOne(ctx, bson.M{"book": book}).Decode(&doc) if err != nil { if err == mongo.ErrNoDocuments { return nil, nil } return nil, err } return &doc, nil } // --- Verses --- type SynonymDoc struct { Word string `bson:"word" json:"word"` Meanings []string `bson:"meanings" json:"meanings"` } type VerseDoc struct { ID bson.ObjectID `bson:"_id" json:"id"` Book string `bson:"book" json:"book"` Division *string `bson:"division,omitempty" json:"division,omitempty"` Chapter int `bson:"chapter" json:"chapter"` Verse int `bson:"verse" json:"verse"` VerseEnd *int `bson:"verseEnd,omitempty" json:"verse_end,omitempty"` Reference string `bson:"reference" json:"reference"` BookTitle string `bson:"bookTitle" json:"book_title"` Devanagari string `bson:"devanagari" json:"devanagari"` Bengali *string `bson:"bengali,omitempty" json:"bengali,omitempty"` Transliteration string `bson:"transliteration" json:"transliteration"` Synonyms []SynonymDoc `bson:"synonyms" json:"synonyms"` Translation string `bson:"translation" json:"translation"` Purport []string `bson:"purport" json:"purport"` } type VerseIndexDoc struct { Verse int `bson:"verse" json:"verse"` VerseEnd *int `bson:"verseEnd,omitempty" json:"verse_end,omitempty"` Reference string `bson:"reference" json:"reference"` } func (r *BookRepo) GetVerseIndex(ctx context.Context, book string, division *string, chapter int) ([]VerseIndexDoc, error) { filter := bson.M{"book": book, "chapter": chapter} if division != nil { filter["division"] = *division } else { filter["division"] = nil } opts := options.Find(). SetSort(bson.M{"verse": 1}). SetProjection(bson.M{"_id": 0, "verse": 1, "verseEnd": 1, "reference": 1}) cursor, err := r.verses.Find(ctx, filter, opts) if err != nil { return nil, err } defer cursor.Close(ctx) var results []VerseIndexDoc if err := cursor.All(ctx, &results); err != nil { return nil, err } return results, nil } func (r *BookRepo) GetVerses(ctx context.Context, book string, division *string, chapter int, page, limit int) ([]VerseDoc, int64, error) { filter := bson.M{"book": book, "chapter": chapter} if division != nil { filter["division"] = *division } else { filter["division"] = nil } total, err := r.verses.CountDocuments(ctx, filter) if err != nil { return nil, 0, err } skip := int64((page - 1) * limit) opts := options.Find(). SetSort(bson.M{"verse": 1}). SetSkip(skip). SetLimit(int64(limit)) cursor, err := r.verses.Find(ctx, filter, opts) if err != nil { return nil, 0, err } defer cursor.Close(ctx) var results []VerseDoc if err := cursor.All(ctx, &results); err != nil { return nil, 0, err } return results, total, nil } func (r *BookRepo) GetSingleVerse(ctx context.Context, book string, division *string, chapter, verse int) (*VerseDoc, error) { filter := bson.M{"book": book, "chapter": chapter, "verse": verse} if division != nil { filter["division"] = *division } else { filter["division"] = nil } var doc VerseDoc err := r.verses.FindOne(ctx, filter).Decode(&doc) if err != nil { if err == mongo.ErrNoDocuments { return nil, nil } return nil, err } return &doc, nil } // --- Prose Chapters --- type ProseChapterDoc struct { ID bson.ObjectID `bson:"_id" json:"id"` Book string `bson:"book" json:"book"` Volume int `bson:"volume" json:"volume"` Chapter *int `bson:"chapter,omitempty" json:"chapter,omitempty"` Title string `bson:"title" json:"title"` Type string `bson:"type" json:"type"` Slug string `bson:"slug" json:"slug"` Order int `bson:"order" json:"order"` Paragraphs []string `bson:"paragraphs" json:"paragraphs"` } func (r *BookRepo) GetProseChapters(ctx context.Context, book string, volume int, chapterType *string) ([]ProseChapterDoc, error) { filter := bson.M{"book": book, "volume": volume} if chapterType != nil { filter["type"] = *chapterType } opts := options.Find().SetSort(bson.M{"order": 1}) cursor, err := r.proseChapters.Find(ctx, filter, opts) if err != nil { return nil, err } defer cursor.Close(ctx) var results []ProseChapterDoc if err := cursor.All(ctx, &results); err != nil { return nil, err } return results, nil } func (r *BookRepo) GetProseChapter(ctx context.Context, book string, volume int, slug string) (*ProseChapterDoc, error) { filter := bson.M{"book": book, "volume": volume, "slug": slug} var doc ProseChapterDoc err := r.proseChapters.FindOne(ctx, filter).Decode(&doc) if err != nil { if err == mongo.ErrNoDocuments { return nil, nil } return nil, err } return &doc, nil }