2
0

api_contract.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package gorm
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "github.com/google/uuid"
  7. "github.com/porter-dev/porter/internal/models"
  8. "github.com/porter-dev/porter/internal/repository"
  9. "github.com/porter-dev/porter/internal/telemetry"
  10. "gorm.io/gorm"
  11. )
  12. // APIContractRepository uses gorm.DB for querying the database
  13. type APIContractRepository struct {
  14. db *gorm.DB
  15. }
  16. // NewAPIContractRevisioner creates an APIRevision connection
  17. func NewAPIContractRevisioner(db *gorm.DB) repository.APIContractRevisioner {
  18. return &APIContractRepository{db}
  19. }
  20. // Insert creates a new record in the api_contract_revisions table
  21. func (cr APIContractRepository) Insert(ctx context.Context, conf models.APIContractRevision) (models.APIContractRevision, error) {
  22. if conf.ID == uuid.Nil {
  23. conf.ID = uuid.New()
  24. }
  25. tx := cr.db.Create(&conf)
  26. if tx.Error != nil {
  27. return conf, tx.Error
  28. }
  29. return conf, nil
  30. }
  31. // List returns a list of api contract revisions sorted by created date for a given projectID.
  32. // If clusterID is not specified (set to 0), this will return all revisions for a given project
  33. // If latest is true, it will only return the latest revision for each contract
  34. func (cr APIContractRepository) List(ctx context.Context, projectID uint, filters ...repository.APIContractRevisionFilters) ([]*models.APIContractRevision, error) {
  35. ctx, span := telemetry.NewSpan(ctx, "list-api-contract-revisions")
  36. defer span.End()
  37. var opts repository.APIContractRevisionFilter
  38. for _, opt := range filters {
  39. opt(&opts)
  40. }
  41. telemetry.WithAttributes(span,
  42. telemetry.AttributeKV{Key: "project-id", Value: projectID},
  43. telemetry.AttributeKV{Key: "cluster-id", Value: opts.ClusterID},
  44. telemetry.AttributeKV{Key: "latest", Value: opts.Latest},
  45. )
  46. if projectID == 0 {
  47. return nil, telemetry.Error(ctx, span, nil, "project id cannot be 0")
  48. }
  49. if opts.Latest {
  50. return cr.Latest(ctx, projectID, filters...)
  51. }
  52. var confs []*models.APIContractRevision
  53. query := cr.db.Model(&models.APIContractRevision{}).Where("project_id = ?", projectID)
  54. if opts.ClusterID != 0 {
  55. query = query.Where("cluster_id = ?", opts.ClusterID)
  56. }
  57. if err := query.Find(&confs).Error; err != nil {
  58. return nil, err
  59. }
  60. return confs, nil
  61. }
  62. // Delete deleted a record in the api_contract_revisions table
  63. func (cr APIContractRepository) Delete(ctx context.Context, projectID uint, clusterID uint, revisionID uuid.UUID) error {
  64. conf := models.APIContractRevision{
  65. ID: revisionID,
  66. ProjectID: int(projectID),
  67. }
  68. if clusterID != 0 {
  69. conf.ClusterID = int(clusterID)
  70. }
  71. tx := cr.db.Delete(&conf)
  72. if tx.Error != nil {
  73. return tx.Error
  74. }
  75. return nil
  76. }
  77. // Get returns a record in the api_contract_revisions table
  78. func (cr APIContractRepository) Get(ctx context.Context, revisionID uuid.UUID) (models.APIContractRevision, error) {
  79. if revisionID == uuid.Nil {
  80. return models.APIContractRevision{}, errors.New("invalid contract revision id supplied")
  81. }
  82. var acr models.APIContractRevision
  83. tx := cr.db.Find(&acr, "id = ?", revisionID.String())
  84. if tx.Error != nil {
  85. return models.APIContractRevision{}, fmt.Errorf("no contract revision found for id %s: %w", revisionID, tx.Error)
  86. }
  87. return acr, nil
  88. }
  89. // Latest returns the latest version for each contract specified by filters, ignoring any deleted_at
  90. func (cr APIContractRepository) Latest(ctx context.Context, projectID uint, filters ...repository.APIContractRevisionFilters) ([]*models.APIContractRevision, error) {
  91. ctx, span := telemetry.NewSpan(ctx, "list-latest-api-contract-revisions")
  92. defer span.End()
  93. var confs []*models.APIContractRevision
  94. var opts repository.APIContractRevisionFilter
  95. for _, opt := range filters {
  96. opt(&opts)
  97. }
  98. queryString := `
  99. SELECT DISTINCT ON (cluster_id) *
  100. FROM api_contract_revisions
  101. WHERE project_id = ? AND deleted_at IS NULL
  102. ORDER BY cluster_id, created_at DESC
  103. `
  104. args := []any{projectID}
  105. if opts.ClusterID != 0 {
  106. queryString = `
  107. SELECT DISTINCT ON (cluster_id) *
  108. FROM api_contract_revisions
  109. WHERE project_id = ? AND cluster_id = ? AND deleted_at IS NULL
  110. ORDER BY cluster_id, created_at DESC
  111. `
  112. args = append(args, opts.ClusterID)
  113. }
  114. tx := cr.db.Raw(queryString, args...).Scan(&confs)
  115. if tx.Error != nil {
  116. return nil, telemetry.Error(ctx, span, tx.Error, "error getting latest api contract revisions")
  117. }
  118. return confs, nil
  119. }