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.

140 lines
3.6 KiB

  1. package postgres
  2. import (
  3. "context"
  4. "database/sql"
  5. "database/sql/driver"
  6. "encoding/json"
  7. "errors"
  8. "github.com/gissleh/stufflog/internal/slerrors"
  9. "github.com/gissleh/stufflog/models"
  10. "github.com/jmoiron/sqlx"
  11. )
  12. type projectGroupRepository struct {
  13. db *sqlx.DB
  14. }
  15. func (r *projectGroupRepository) Find(ctx context.Context, id string) (*models.ProjectGroup, error) {
  16. res := projectGroupDBO{}
  17. err := r.db.GetContext(ctx, &res, "SELECT * FROM project_group WHERE project_group_id=$1", id)
  18. if err != nil {
  19. if err == sql.ErrNoRows {
  20. return nil, slerrors.NotFound("Project group")
  21. }
  22. return nil, err
  23. }
  24. return res.ToProjectGroup(), nil
  25. }
  26. func (r *projectGroupRepository) List(ctx context.Context, filter models.ProjectGroupFilter) ([]*models.ProjectGroup, error) {
  27. res := make([]*projectGroupDBO, 0, 16)
  28. err := r.db.SelectContext(ctx, &res, "SELECT * FROM project_group WHERE user_id=$1 ORDER BY abbreviation", filter.UserID)
  29. if err != nil {
  30. if err == sql.ErrNoRows {
  31. return []*models.ProjectGroup{}, nil
  32. }
  33. return nil, err
  34. }
  35. res2 := make([]*models.ProjectGroup, 0, len(res))
  36. for _, pdo := range res {
  37. res2 = append(res2, pdo.ToProjectGroup())
  38. }
  39. return res2, nil
  40. }
  41. func (r *projectGroupRepository) Insert(ctx context.Context, group models.ProjectGroup) error {
  42. _, err := r.db.NamedExecContext(ctx, `
  43. INSERT INTO project_group (
  44. project_group_id, user_id, name, abbreviation, description, category_names
  45. ) VALUES (
  46. :project_group_id, :user_id, :name, :abbreviation, :description, :category_names
  47. )
  48. `, toProjectGroupDBO(group))
  49. if err != nil {
  50. return err
  51. }
  52. return nil
  53. }
  54. func (r *projectGroupRepository) Update(ctx context.Context, group models.ProjectGroup) error {
  55. if group.CategoryNames == nil {
  56. group.CategoryNames = make(map[string]string)
  57. }
  58. _, err := r.db.NamedExecContext(ctx, `
  59. UPDATE project_group SET
  60. name = :name,
  61. abbreviation = :abbreviation,
  62. description = :description,
  63. category_names = :category_names
  64. WHERE project_group_id = :project_group_id
  65. `, toProjectGroupDBO(group))
  66. return err
  67. }
  68. func (r *projectGroupRepository) Delete(ctx context.Context, group models.ProjectGroup) error {
  69. _, err := r.db.ExecContext(ctx, `DELETE FROM project_group WHERE project_group_id=$1`, group.ID)
  70. if err != nil {
  71. return err
  72. }
  73. _, err = r.db.ExecContext(ctx, "UPDATE project SET project_group_id=NULL where project_group_id=$1", group.ID)
  74. if err != nil && err != sql.ErrNoRows {
  75. return err
  76. }
  77. return nil
  78. }
  79. type projectGroupDBO struct {
  80. ID string `db:"project_group_id"`
  81. UserID string `db:"user_id"`
  82. Name string `db:"name"`
  83. Description string `db:"description"`
  84. Abbreviation string `db:"abbreviation"`
  85. CategoryNames jsonMap `db:"category_names"`
  86. }
  87. func (dbo *projectGroupDBO) ToProjectGroup() *models.ProjectGroup {
  88. return &models.ProjectGroup{
  89. ID: dbo.ID,
  90. UserID: dbo.UserID,
  91. Name: dbo.Name,
  92. Description: dbo.Description,
  93. Abbreviation: dbo.Abbreviation,
  94. CategoryNames: dbo.CategoryNames,
  95. }
  96. }
  97. func toProjectGroupDBO(group models.ProjectGroup) projectGroupDBO {
  98. return projectGroupDBO{
  99. ID: group.ID,
  100. UserID: group.UserID,
  101. Name: group.Name,
  102. Description: group.Description,
  103. Abbreviation: group.Abbreviation,
  104. CategoryNames: group.CategoryNames,
  105. }
  106. }
  107. type jsonMap map[string]string
  108. func (m jsonMap) Value() (driver.Value, error) {
  109. return json.Marshal(m)
  110. }
  111. func (m *jsonMap) Scan(value interface{}) error {
  112. b, ok := value.([]byte)
  113. if !ok {
  114. return errors.New("type assertion to []byte failed")
  115. }
  116. return json.Unmarshal(b, m)
  117. }