GraphQL API and utilities for the rpdata project
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.

78 lines
1.7 KiB

  1. package mongodb
  2. import (
  3. "context"
  4. "sort"
  5. "strings"
  6. "git.aiterp.net/rpdata/api/models"
  7. "git.aiterp.net/rpdata/api/repositories"
  8. "github.com/globalsign/mgo"
  9. "go.mongodb.org/mongo-driver/bson"
  10. )
  11. type tagRepository struct {
  12. stories *mgo.Collection
  13. }
  14. func newTagRepository(db *mgo.Database) repositories.TagRepository {
  15. return &tagRepository{
  16. stories: db.C("story.stories"),
  17. }
  18. }
  19. func (r *tagRepository) Find(ctx context.Context, kind models.TagKind, name string) (*models.Tag, error) {
  20. tags := make([]*models.Tag, 0, 1)
  21. err := r.stories.Find(bson.M{"listed": true, "tags": bson.M{"kind": kind, "name": name}}).Distinct("tag", &tags)
  22. if err != nil {
  23. return nil, err
  24. } else if len(tags) == 0 {
  25. return nil, repositories.ErrNotFound
  26. }
  27. for _, tag := range tags {
  28. if tag.Kind == kind && tag.Name == name {
  29. return tag, nil
  30. }
  31. }
  32. return nil, repositories.ErrNotFound
  33. }
  34. func (r *tagRepository) List(ctx context.Context, filter models.TagFilter) ([]*models.Tag, error) {
  35. tags := make([]*models.Tag, 0, 64)
  36. query := bson.M{"listed": true, "tags": bson.M{"$ne": nil}}
  37. if filter.Kind != nil {
  38. query["tags.kind"] = *filter.Kind
  39. }
  40. err := r.stories.Find(query).Distinct("tags", &tags)
  41. if err != nil {
  42. return nil, err
  43. }
  44. if filter.Kind != nil {
  45. // While it's unsorted, delete any incorrect tags with replacement.
  46. for i := 0; i < len(tags); i++ {
  47. if tags[i].Kind != *filter.Kind {
  48. tags[i] = tags[len(tags)-1]
  49. tags = tags[:len(tags)-1]
  50. i--
  51. }
  52. }
  53. }
  54. sort.Slice(tags, func(i, j int) bool {
  55. if filter.Kind == nil {
  56. kindCmp := strings.Compare(string(tags[i].Kind), string(tags[j].Kind))
  57. if kindCmp != 0 {
  58. return kindCmp < 0
  59. }
  60. }
  61. return strings.Compare(tags[i].Name, tags[j].Name) < 0
  62. })
  63. return tags, nil
  64. }