package mongodb import ( "context" "sort" "strings" "git.aiterp.net/rpdata/api/models" "git.aiterp.net/rpdata/api/repositories" "github.com/globalsign/mgo" "go.mongodb.org/mongo-driver/bson" ) type tagRepository struct { stories *mgo.Collection } func newTagRepository(db *mgo.Database) repositories.TagRepository { return &tagRepository{ stories: db.C("story.stories"), } } func (r *tagRepository) Find(ctx context.Context, kind models.TagKind, name string) (*models.Tag, error) { tags := make([]*models.Tag, 0, 1) err := r.stories.Find(bson.M{"listed": true, "tags": bson.M{"kind": kind, "name": name}}).Distinct("tag", &tags) if err != nil { return nil, err } else if len(tags) == 0 { return nil, repositories.ErrNotFound } for _, tag := range tags { if tag.Kind == kind && tag.Name == name { return tag, nil } } return nil, repositories.ErrNotFound } func (r *tagRepository) List(ctx context.Context, filter models.TagFilter) ([]*models.Tag, error) { tags := make([]*models.Tag, 0, 64) query := bson.M{"listed": true, "tags": bson.M{"$ne": nil}} if filter.Kind != nil { query["tags.kind"] = *filter.Kind } err := r.stories.Find(query).Distinct("tags", &tags) if err != nil { return nil, err } if filter.Kind != nil { // While it's unsorted, delete any incorrect tags with replacement. for i := 0; i < len(tags); i++ { if tags[i].Kind != *filter.Kind { tags[i] = tags[len(tags)-1] tags = tags[:len(tags)-1] i-- } } } sort.Slice(tags, func(i, j int) bool { if filter.Kind == nil { kindCmp := strings.Compare(string(tags[i].Kind), string(tags[j].Kind)) if kindCmp != 0 { return kindCmp < 0 } } return strings.Compare(tags[i].Name, tags[j].Name) < 0 }) return tags, nil }