admin_event_store.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. package postgres
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "github.com/jackc/pgx/v5"
  7. )
  8. type Tenant struct {
  9. ID string
  10. TenantCode string
  11. Name string
  12. Status string
  13. }
  14. type AdminEventRecord struct {
  15. ID string
  16. PublicID string
  17. TenantID *string
  18. TenantCode *string
  19. TenantName *string
  20. Slug string
  21. DisplayName string
  22. Summary *string
  23. Status string
  24. CurrentReleaseID *string
  25. CurrentReleasePubID *string
  26. ConfigLabel *string
  27. ManifestURL *string
  28. ManifestChecksum *string
  29. RouteCode *string
  30. }
  31. type CreateAdminEventParams struct {
  32. PublicID string
  33. TenantID *string
  34. Slug string
  35. DisplayName string
  36. Summary *string
  37. Status string
  38. }
  39. type UpdateAdminEventParams struct {
  40. EventID string
  41. TenantID *string
  42. Slug string
  43. DisplayName string
  44. Summary *string
  45. Status string
  46. ClearTenant bool
  47. }
  48. func (s *Store) GetTenantByCode(ctx context.Context, tenantCode string) (*Tenant, error) {
  49. row := s.pool.QueryRow(ctx, `
  50. SELECT id, tenant_code, name, status
  51. FROM tenants
  52. WHERE tenant_code = $1
  53. LIMIT 1
  54. `, tenantCode)
  55. var item Tenant
  56. err := row.Scan(&item.ID, &item.TenantCode, &item.Name, &item.Status)
  57. if errors.Is(err, pgx.ErrNoRows) {
  58. return nil, nil
  59. }
  60. if err != nil {
  61. return nil, fmt.Errorf("get tenant by code: %w", err)
  62. }
  63. return &item, nil
  64. }
  65. func (s *Store) ListAdminEvents(ctx context.Context, limit int) ([]AdminEventRecord, error) {
  66. if limit <= 0 || limit > 200 {
  67. limit = 50
  68. }
  69. rows, err := s.pool.Query(ctx, `
  70. SELECT
  71. e.id,
  72. e.event_public_id,
  73. e.tenant_id,
  74. t.tenant_code,
  75. t.name,
  76. e.slug,
  77. e.display_name,
  78. e.summary,
  79. e.status,
  80. e.current_release_id,
  81. er.release_public_id,
  82. er.config_label,
  83. er.manifest_url,
  84. er.manifest_checksum_sha256,
  85. er.route_code
  86. FROM events e
  87. LEFT JOIN tenants t ON t.id = e.tenant_id
  88. LEFT JOIN event_releases er ON er.id = e.current_release_id
  89. ORDER BY e.created_at DESC
  90. LIMIT $1
  91. `, limit)
  92. if err != nil {
  93. return nil, fmt.Errorf("list admin events: %w", err)
  94. }
  95. defer rows.Close()
  96. items := []AdminEventRecord{}
  97. for rows.Next() {
  98. item, err := scanAdminEventFromRows(rows)
  99. if err != nil {
  100. return nil, err
  101. }
  102. items = append(items, *item)
  103. }
  104. if err := rows.Err(); err != nil {
  105. return nil, fmt.Errorf("iterate admin events: %w", err)
  106. }
  107. return items, nil
  108. }
  109. func (s *Store) GetAdminEventByPublicID(ctx context.Context, eventPublicID string) (*AdminEventRecord, error) {
  110. row := s.pool.QueryRow(ctx, `
  111. SELECT
  112. e.id,
  113. e.event_public_id,
  114. e.tenant_id,
  115. t.tenant_code,
  116. t.name,
  117. e.slug,
  118. e.display_name,
  119. e.summary,
  120. e.status,
  121. e.current_release_id,
  122. er.release_public_id,
  123. er.config_label,
  124. er.manifest_url,
  125. er.manifest_checksum_sha256,
  126. er.route_code
  127. FROM events e
  128. LEFT JOIN tenants t ON t.id = e.tenant_id
  129. LEFT JOIN event_releases er ON er.id = e.current_release_id
  130. WHERE e.event_public_id = $1
  131. LIMIT 1
  132. `, eventPublicID)
  133. return scanAdminEvent(row)
  134. }
  135. func (s *Store) CreateAdminEvent(ctx context.Context, tx Tx, params CreateAdminEventParams) (*AdminEventRecord, error) {
  136. row := tx.QueryRow(ctx, `
  137. INSERT INTO events (tenant_id, event_public_id, slug, display_name, summary, status)
  138. VALUES ($1, $2, $3, $4, $5, $6)
  139. RETURNING id, event_public_id, tenant_id, slug, display_name, summary, status, current_release_id
  140. `, params.TenantID, params.PublicID, params.Slug, params.DisplayName, params.Summary, params.Status)
  141. var item AdminEventRecord
  142. if err := row.Scan(
  143. &item.ID,
  144. &item.PublicID,
  145. &item.TenantID,
  146. &item.Slug,
  147. &item.DisplayName,
  148. &item.Summary,
  149. &item.Status,
  150. &item.CurrentReleaseID,
  151. ); err != nil {
  152. return nil, fmt.Errorf("create admin event: %w", err)
  153. }
  154. return &item, nil
  155. }
  156. func (s *Store) UpdateAdminEvent(ctx context.Context, tx Tx, params UpdateAdminEventParams) (*AdminEventRecord, error) {
  157. row := tx.QueryRow(ctx, `
  158. UPDATE events
  159. SET tenant_id = CASE WHEN $7 THEN NULL ELSE $2 END,
  160. slug = $3,
  161. display_name = $4,
  162. summary = $5,
  163. status = $6
  164. WHERE id = $1
  165. RETURNING id, event_public_id, tenant_id, slug, display_name, summary, status, current_release_id
  166. `, params.EventID, params.TenantID, params.Slug, params.DisplayName, params.Summary, params.Status, params.ClearTenant)
  167. var item AdminEventRecord
  168. if err := row.Scan(
  169. &item.ID,
  170. &item.PublicID,
  171. &item.TenantID,
  172. &item.Slug,
  173. &item.DisplayName,
  174. &item.Summary,
  175. &item.Status,
  176. &item.CurrentReleaseID,
  177. ); err != nil {
  178. return nil, fmt.Errorf("update admin event: %w", err)
  179. }
  180. return &item, nil
  181. }
  182. func scanAdminEvent(row pgx.Row) (*AdminEventRecord, error) {
  183. var item AdminEventRecord
  184. err := row.Scan(
  185. &item.ID,
  186. &item.PublicID,
  187. &item.TenantID,
  188. &item.TenantCode,
  189. &item.TenantName,
  190. &item.Slug,
  191. &item.DisplayName,
  192. &item.Summary,
  193. &item.Status,
  194. &item.CurrentReleaseID,
  195. &item.CurrentReleasePubID,
  196. &item.ConfigLabel,
  197. &item.ManifestURL,
  198. &item.ManifestChecksum,
  199. &item.RouteCode,
  200. )
  201. if errors.Is(err, pgx.ErrNoRows) {
  202. return nil, nil
  203. }
  204. if err != nil {
  205. return nil, fmt.Errorf("scan admin event: %w", err)
  206. }
  207. return &item, nil
  208. }
  209. func scanAdminEventFromRows(rows pgx.Rows) (*AdminEventRecord, error) {
  210. var item AdminEventRecord
  211. err := rows.Scan(
  212. &item.ID,
  213. &item.PublicID,
  214. &item.TenantID,
  215. &item.TenantCode,
  216. &item.TenantName,
  217. &item.Slug,
  218. &item.DisplayName,
  219. &item.Summary,
  220. &item.Status,
  221. &item.CurrentReleaseID,
  222. &item.CurrentReleasePubID,
  223. &item.ConfigLabel,
  224. &item.ManifestURL,
  225. &item.ManifestChecksum,
  226. &item.RouteCode,
  227. )
  228. if err != nil {
  229. return nil, fmt.Errorf("scan admin event row: %w", err)
  230. }
  231. return &item, nil
  232. }