You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
210 lines
5.0 KiB
210 lines
5.0 KiB
package mongodb
|
|
|
|
import (
|
|
"context"
|
|
"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"
|
|
)
|
|
|
|
type storyRepository struct {
|
|
stories *mgo.Collection
|
|
chapters *mgo.Collection
|
|
comments *mgo.Collection
|
|
}
|
|
|
|
func newStoryRepository(db *mgo.Database) (repositories.StoryRepository, error) {
|
|
collection := db.C("story.stories")
|
|
|
|
err := collection.EnsureIndexKey("tags")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = collection.EnsureIndexKey("author")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = collection.EnsureIndexKey("updatedDate")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = collection.EnsureIndexKey("fictionalDate")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = collection.EnsureIndexKey("listed")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &storyRepository{
|
|
stories: collection,
|
|
chapters: db.C("story.chapters"),
|
|
comments: db.C("story.comments"),
|
|
}, nil
|
|
}
|
|
|
|
func (r *storyRepository) Find(ctx context.Context, id string) (*models.Story, error) {
|
|
story := new(models.Story)
|
|
err := r.stories.FindId(id).One(story)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return story, nil
|
|
}
|
|
|
|
func (r *storyRepository) List(ctx context.Context, filter models.StoryFilter) ([]*models.Story, error) {
|
|
query := bson.M{}
|
|
if filter.Author != nil {
|
|
query["author"] = *filter.Author
|
|
}
|
|
if filter.Category != nil {
|
|
query["category"] = *filter.Category
|
|
}
|
|
if filter.Open != nil {
|
|
query["open"] = *filter.Open
|
|
}
|
|
if len(filter.Tags) > 0 {
|
|
query["tags"] = bson.M{"$all": filter.Tags}
|
|
}
|
|
if filter.Unlisted != nil {
|
|
query["listed"] = !*filter.Unlisted
|
|
} else {
|
|
query["listed"] = true
|
|
}
|
|
if !filter.EarliestFictionalDate.IsZero() && !filter.LatestFictionalDate.IsZero() {
|
|
query["fictionalDate"] = bson.M{
|
|
"$gte": filter.EarliestFictionalDate,
|
|
"$lte": filter.LatestFictionalDate,
|
|
}
|
|
} else if !filter.EarliestFictionalDate.IsZero() {
|
|
query["fictionalDate"] = bson.M{
|
|
"$gte": filter.EarliestFictionalDate,
|
|
}
|
|
} else if !filter.LatestFictionalDate.IsZero() {
|
|
query["fictionalDate"] = bson.M{
|
|
"$lte": filter.LatestFictionalDate,
|
|
}
|
|
}
|
|
|
|
stories := make([]*models.Story, 0, 32)
|
|
err := r.stories.Find(query).Sort("-updatedDate").Limit(filter.Limit).All(&stories)
|
|
if err != nil {
|
|
if err == mgo.ErrNotFound {
|
|
return stories, nil
|
|
}
|
|
|
|
return nil, err
|
|
}
|
|
|
|
return stories, nil
|
|
}
|
|
|
|
func (r *storyRepository) Insert(ctx context.Context, story models.Story) (*models.Story, error) {
|
|
story.ID = generate.StoryID()
|
|
|
|
err := r.stories.Insert(story)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &story, nil
|
|
}
|
|
|
|
func (r *storyRepository) Update(ctx context.Context, story models.Story, update models.StoryUpdate) (*models.Story, error) {
|
|
updateBson := bson.M{}
|
|
if update.Name != nil {
|
|
updateBson["name"] = *update.Name
|
|
story.Name = *update.Name
|
|
}
|
|
if update.Open != nil {
|
|
updateBson["open"] = *update.Open
|
|
story.Open = *update.Open
|
|
}
|
|
if update.Category != nil {
|
|
updateBson["category"] = *update.Category
|
|
story.Category = *update.Category
|
|
}
|
|
if update.Author != nil {
|
|
updateBson["author"] = *update.Author
|
|
story.Author = *update.Author
|
|
}
|
|
if update.FictionalDate != nil {
|
|
updateBson["fictionalDate"] = *update.FictionalDate
|
|
story.FictionalDate = *update.FictionalDate
|
|
}
|
|
if update.UpdatedDate != nil {
|
|
updateBson["updatedDate"] = *update.UpdatedDate
|
|
story.UpdatedDate = *update.UpdatedDate
|
|
}
|
|
if update.Listed != nil {
|
|
updateBson["listed"] = *update.Listed
|
|
story.Listed = *update.Listed
|
|
}
|
|
|
|
err := r.stories.UpdateId(story.ID, bson.M{"$set": updateBson})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &story, nil
|
|
}
|
|
|
|
func (r *storyRepository) AddTag(ctx context.Context, story models.Story, tag models.Tag) error {
|
|
ci, err := r.stories.UpdateAll(bson.M{"_id": story.ID}, bson.M{"$addToSet": bson.M{"tags": tag}})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if ci.Updated == 0 {
|
|
return repositories.ErrTagExists
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *storyRepository) RemoveTag(ctx context.Context, story models.Story, tag models.Tag) error {
|
|
ci, err := r.stories.UpdateAll(bson.M{"_id": story.ID}, bson.M{"$pull": bson.M{"tags": tag}})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if ci.Updated == 0 {
|
|
return repositories.ErrTagDoesNotExist
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *storyRepository) Delete(ctx context.Context, story models.Story) error {
|
|
err := r.stories.RemoveId(story.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
chapterIds := make([]string, 0, 8)
|
|
err = r.chapters.Find(bson.M{"storyId": story.ID}).Distinct("_id", &chapterIds)
|
|
if err != nil {
|
|
log.Println("Failed to find chapterIds:", err)
|
|
return nil
|
|
}
|
|
if len(chapterIds) > 0 {
|
|
c1, err := r.chapters.RemoveAll(bson.M{"storyId": story.ID})
|
|
if err != nil {
|
|
log.Println("Failed to remove chapters:", err)
|
|
return nil
|
|
}
|
|
|
|
c2, err := r.comments.RemoveAll(bson.M{"chapterId": bson.M{"$in": chapterIds}})
|
|
if err != nil {
|
|
log.Println("Failed to remove comments:", err)
|
|
return nil
|
|
}
|
|
|
|
log.Printf("Removed story %s (%d chapters, %d comments)", story.ID, c1.Removed, c2.Removed)
|
|
}
|
|
|
|
return nil
|
|
}
|