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.

184 lines
4.0 KiB

  1. package postgres
  2. import (
  3. "context"
  4. "database/sql"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "git.aiterp.net/rpdata/api/database/postgres/psqlcore"
  9. "git.aiterp.net/rpdata/api/models"
  10. "strconv"
  11. "time"
  12. )
  13. type changeRepository struct {
  14. insertWithIDs bool
  15. db *sql.DB
  16. }
  17. func (r *changeRepository) Find(ctx context.Context, id string) (*models.Change, error) {
  18. row, err := psqlcore.New(r.db).SelectChangeByID(ctx, id)
  19. if err != nil {
  20. return nil, err
  21. }
  22. return r.change(row)
  23. }
  24. func (r *changeRepository) List(ctx context.Context, filter models.ChangeFilter) ([]*models.Change, error) {
  25. params := psqlcore.SelectChangesParams{LimitSize: 100}
  26. if filter.Keys != nil {
  27. params.FilterKeys = true
  28. keys := make([]string, len(filter.Keys))
  29. for i, ck := range filter.Keys {
  30. keys[i] = ck.String()
  31. }
  32. params.Keys = keys
  33. }
  34. if filter.Author != nil {
  35. params.FilterAuthor = true
  36. params.Author = *filter.Author
  37. }
  38. if filter.EarliestDate != nil {
  39. params.FilterEarliestDate = true
  40. params.EarliestDate = filter.EarliestDate.In(time.UTC)
  41. }
  42. if filter.LatestDate != nil {
  43. params.FilterLatestDate = true
  44. params.LatestDate = filter.LatestDate.In(time.UTC)
  45. }
  46. if filter.Limit != nil {
  47. if *filter.Limit <= 0 {
  48. params.LimitSize = 10000
  49. } else {
  50. params.LimitSize = int32(*filter.Limit)
  51. }
  52. }
  53. rows, err := psqlcore.New(r.db).SelectChanges(ctx, params)
  54. if err != nil {
  55. return nil, err
  56. }
  57. return r.changes(rows)
  58. }
  59. func (r *changeRepository) Insert(ctx context.Context, change models.Change) (*models.Change, error) {
  60. tx, err := r.db.BeginTx(ctx, nil)
  61. if err != nil {
  62. return nil, err
  63. }
  64. defer func() { _ = tx.Rollback() }()
  65. q := psqlcore.New(tx)
  66. if !r.insertWithIDs || change.ID == "" {
  67. next, err := q.IncrementCounter(ctx, "data_change_id")
  68. if err != nil {
  69. return nil, err
  70. }
  71. change.ID = fmt.Sprintf("Change_%d", next)
  72. } else {
  73. if len(change.ID) < 8 {
  74. return nil, errors.New("invalid change id")
  75. }
  76. n, err := strconv.Atoi(change.ID[7:])
  77. if err != nil {
  78. return nil, err
  79. }
  80. err = q.BumpCounter(ctx, psqlcore.BumpCounterParams{ID: "data_change_id", Value: int32(n)})
  81. if err != nil {
  82. return nil, err
  83. }
  84. }
  85. data, err := r.dataChange(change)
  86. if err != nil {
  87. return nil, err
  88. }
  89. err = q.InsertChange(ctx, psqlcore.InsertChangeParams(*data))
  90. if err != nil {
  91. return nil, err
  92. }
  93. return &change, tx.Commit()
  94. }
  95. func (r *changeRepository) Remove(ctx context.Context, change models.Change) error {
  96. return psqlcore.New(r.db).DeleteChange(ctx, change.ID)
  97. }
  98. func (r *changeRepository) dataChange(change models.Change) (*psqlcore.DataChange, error) {
  99. objectsJSON, err := json.Marshal(change.ChangeObjectSet)
  100. if err != nil {
  101. return nil, err
  102. }
  103. keys := make([]string, len(change.Keys))
  104. for i, ck := range change.Keys {
  105. keys[i] = ck.String()
  106. }
  107. return &psqlcore.DataChange{
  108. ID: change.ID,
  109. Model: string(change.Model),
  110. Op: change.Op,
  111. Author: change.Author,
  112. Listed: change.Listed,
  113. Date: change.Date.In(time.UTC),
  114. Keys: keys,
  115. Objects: objectsJSON,
  116. }, nil
  117. }
  118. func (r *changeRepository) change(row psqlcore.DataChange) (*models.Change, error) {
  119. objects := models.ChangeObjectSet{}
  120. err := json.Unmarshal(row.Objects, &objects)
  121. if err != nil {
  122. return nil, err
  123. }
  124. keys := make([]models.ChangeKey, len(row.Keys))
  125. for i := range keys {
  126. err := keys[i].Decode(row.Keys[i])
  127. if err != nil {
  128. return nil, err
  129. }
  130. }
  131. model := models.ChangeModel(row.Model)
  132. if !model.IsValid() {
  133. return nil, errors.New("invalid model")
  134. }
  135. return &models.Change{
  136. ID: row.ID,
  137. Model: model,
  138. Op: row.Op,
  139. Author: row.Author,
  140. Listed: row.Listed,
  141. Date: row.Date,
  142. Keys: keys,
  143. ChangeObjectSet: objects,
  144. }, nil
  145. }
  146. func (r *changeRepository) changes(rows []psqlcore.DataChange) ([]*models.Change, error) {
  147. results := make([]*models.Change, len(rows))
  148. for i, row := range rows {
  149. change, err := r.change(row)
  150. if err != nil {
  151. return nil, err
  152. }
  153. results[i] = change
  154. }
  155. return results, nil
  156. }