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.

135 lines
2.9 KiB

  1. package mongodb
  2. import (
  3. "context"
  4. "errors"
  5. "git.aiterp.net/rpdata/api/models"
  6. "git.aiterp.net/rpdata/api/repositories"
  7. "github.com/globalsign/mgo"
  8. "github.com/globalsign/mgo/bson"
  9. "strconv"
  10. "strings"
  11. "time"
  12. )
  13. type changeRepository struct {
  14. restoreIDs bool
  15. changes *mgo.Collection
  16. idCounter *counter
  17. }
  18. func (r *changeRepository) Find(ctx context.Context, id string) (*models.Change, error) {
  19. change := new(models.Change)
  20. err := r.changes.FindId(id).One(change)
  21. if err != nil {
  22. return nil, err
  23. }
  24. return change, nil
  25. }
  26. func (r *changeRepository) List(ctx context.Context, filter models.ChangeFilter) ([]*models.Change, error) {
  27. query := bson.M{}
  28. limit := 0
  29. if filter.EarliestDate != nil && !filter.EarliestDate.IsZero() {
  30. query["date"] = bson.M{"$gte": *filter.EarliestDate}
  31. }
  32. if filter.LatestDate != nil && !filter.LatestDate.IsZero() {
  33. dateBson, ok := query["date"].(bson.M)
  34. if !ok {
  35. dateBson = bson.M{}
  36. }
  37. dateBson["$gte"] = *filter.EarliestDate
  38. }
  39. if len(filter.Keys) > 0 {
  40. query["keys"] = bson.M{"$in": filter.Keys}
  41. } else if !r.restoreIDs {
  42. query["listed"] = true
  43. }
  44. if filter.Author != nil && *filter.Author != "" {
  45. query["author"] = *filter.Author
  46. }
  47. if filter.Limit != nil {
  48. limit = *filter.Limit
  49. }
  50. initialSize := 64
  51. if limit > 0 && limit < 256 {
  52. initialSize = limit
  53. }
  54. changes := make([]*models.Change, 0, initialSize)
  55. err := r.changes.Find(query).Sort("-date").Limit(limit).All(&changes)
  56. if err != nil {
  57. return nil, err
  58. }
  59. return changes, nil
  60. }
  61. func (r *changeRepository) Insert(ctx context.Context, change models.Change) (*models.Change, error) {
  62. if !r.restoreIDs || change.ID == "" {
  63. next, err := r.idCounter.Increment(1)
  64. if err != nil {
  65. return nil, err
  66. }
  67. change.ID = "Change_" + strconv.Itoa(next)
  68. } else {
  69. tokens := strings.Split(change.ID, "_")
  70. if len(tokens) != 2 || tokens[0] != "Change" {
  71. return nil, errors.New("Invalid change ID")
  72. }
  73. n, err := strconv.Atoi(tokens[1])
  74. if err != nil {
  75. return nil, err
  76. }
  77. _ = r.idCounter.Bump(n)
  78. }
  79. err := r.changes.Insert(&change)
  80. if err != nil {
  81. return nil, err
  82. }
  83. return &change, nil
  84. }
  85. func (r *changeRepository) Remove(ctx context.Context, change models.Change) error {
  86. return r.changes.RemoveId(change.ID)
  87. }
  88. func newChangeRepository(db *mgo.Database, restoreIDs bool) (repositories.ChangeRepository, error) {
  89. collection := db.C("common.changes")
  90. // Delete the old index if it exists.
  91. _ = collection.DropIndexName("date_1")
  92. err := collection.EnsureIndex(mgo.Index{
  93. Name: "expiry",
  94. Key: []string{"date"},
  95. ExpireAfter: time.Hour * 2400, // 100 days
  96. })
  97. if err != nil {
  98. return nil, err
  99. }
  100. err = collection.EnsureIndexKey("author")
  101. if err != nil {
  102. return nil, err
  103. }
  104. err = collection.EnsureIndexKey("keys")
  105. if err != nil {
  106. return nil, err
  107. }
  108. return &changeRepository{
  109. restoreIDs: restoreIDs,
  110. changes: collection,
  111. idCounter: newCounter(db, "auto_increment", "Change"),
  112. }, nil
  113. }