package mongodb import ( "context" "errors" "git.aiterp.net/rpdata/api/internal/generate" "git.aiterp.net/rpdata/api/models" "git.aiterp.net/rpdata/api/repositories" "github.com/globalsign/mgo" "github.com/globalsign/mgo/bson" "log" "strings" ) type chapterRepository struct { restoreIDs bool chapters *mgo.Collection comments *mgo.Collection } func newChapterRepository(db *mgo.Database, restoreIDs bool) (repositories.ChapterRepository, error) { collection := db.C("story.chapters") err := collection.EnsureIndexKey("storyId") if err != nil { return nil, err } err = collection.EnsureIndexKey("author") if err != nil { return nil, err } err = collection.EnsureIndexKey("createdDate") if err != nil { return nil, err } return &chapterRepository{ restoreIDs: restoreIDs, chapters: collection, comments: db.C("story.comments"), }, nil } func (r *chapterRepository) Find(ctx context.Context, id string) (*models.Chapter, error) { chapter := new(models.Chapter) err := r.chapters.FindId(id).One(chapter) if err != nil { return nil, err } return chapter, nil } func (r *chapterRepository) List(ctx context.Context, filter models.ChapterFilter) ([]*models.Chapter, error) { query := bson.M{} if filter.StoryID != nil { query["storyId"] = *filter.StoryID } chapters := make([]*models.Chapter, 0, 32) err := r.chapters.Find(query).Sort("createdDate").Limit(filter.Limit).All(&chapters) if err != nil { if err == mgo.ErrNotFound { return chapters, nil } return nil, err } return chapters, nil } func (r *chapterRepository) Insert(ctx context.Context, chapter models.Chapter) (*models.Chapter, error) { if !r.restoreIDs { chapter.ID = generate.ChapterID() } else { if len(chapter.ID) != len(generate.ChapterID()) && strings.HasPrefix(chapter.ID, "S") { return nil, errors.New("invalid story id") } } err := r.chapters.Insert(chapter) if err != nil { return nil, err } return &chapter, nil } func (r *chapterRepository) Update(ctx context.Context, chapter models.Chapter, update models.ChapterUpdate) (*models.Chapter, error) { updateBson := bson.M{} if update.Title != nil { updateBson["title"] = *update.Title chapter.Title = *update.Title } if update.Source != nil { updateBson["source"] = *update.Source chapter.Source = *update.Source } if update.FictionalDate != nil { updateBson["fictionalDate"] = *update.FictionalDate chapter.FictionalDate = *update.FictionalDate } if update.CommentMode != nil { updateBson["commentMode"] = *update.CommentMode chapter.CommentMode = *update.CommentMode } if update.CommentsLocked != nil { updateBson["commentsLocked"] = *update.CommentsLocked chapter.CommentsLocked = *update.CommentsLocked } err := r.chapters.UpdateId(chapter.ID, bson.M{"$set": updateBson}) if err != nil { return nil, err } return &chapter, nil } func (r *chapterRepository) Move(ctx context.Context, chapter models.Chapter, from, to models.Story) (*models.Chapter, error) { err := r.chapters.UpdateId(chapter.ID, bson.M{"$set": bson.M{"storyId": to.ID}}) if err != nil { return nil, err } chapter.StoryID = to.ID return &chapter, nil } func (r *chapterRepository) Delete(ctx context.Context, chapter models.Chapter) error { err := r.chapters.RemoveId(chapter.ID) if err != nil { return err } c, err := r.comments.RemoveAll(bson.M{"chapterId": chapter.ID}) if err != nil { log.Println("Failed to remove comments:", err) return nil } log.Printf("Removed chapter %s (%d comments)", chapter.ID, c.Removed) return nil }