package repository import ( "context" "errors" "fmt" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" "github.com/geo-platform/tenant-api/internal/ops/domain" ) var ErrSiteDomainMappingNotFound = errors.New("site domain mapping not found") type SiteDomainMappingRepository struct { pool *pgxpool.Pool } func NewSiteDomainMappingRepository(pool *pgxpool.Pool) *SiteDomainMappingRepository { return &SiteDomainMappingRepository{pool: pool} } const siteDomainMappingColumns = `id, registrable_domain, site_key, site_name, is_active, created_at, updated_at` type SiteDomainMappingFilter struct { Keyword string IsActive *bool Limit int Offset int } type CreateSiteDomainMappingInput struct { RegistrableDomain string SiteKey string SiteName string IsActive bool } type UpdateSiteDomainMappingInput struct { RegistrableDomain string SiteKey string SiteName string IsActive bool } func scanSiteDomainMapping(row pgx.Row) (*domain.SiteDomainMapping, error) { var item domain.SiteDomainMapping err := row.Scan( &item.ID, &item.RegistrableDomain, &item.SiteKey, &item.SiteName, &item.IsActive, &item.CreatedAt, &item.UpdatedAt, ) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return nil, ErrSiteDomainMappingNotFound } return nil, err } return &item, nil } func (r *SiteDomainMappingRepository) List(ctx context.Context, f SiteDomainMappingFilter) ([]domain.SiteDomainMapping, int64, error) { args := []any{} where := "1=1" if f.Keyword != "" { args = append(args, "%"+f.Keyword+"%") where += fmt.Sprintf(" AND (registrable_domain ILIKE $%d OR site_key ILIKE $%d OR site_name ILIKE $%d)", len(args), len(args), len(args)) } if f.IsActive != nil { args = append(args, *f.IsActive) where += fmt.Sprintf(" AND is_active = $%d", len(args)) } var total int64 if err := r.pool.QueryRow(ctx, "SELECT COUNT(*) FROM site_domain_mappings WHERE "+where, args...).Scan(&total); err != nil { return nil, 0, err } limit := f.Limit if limit <= 0 || limit > 200 { limit = 20 } offset := f.Offset if offset < 0 { offset = 0 } args = append(args, limit, offset) limitArg := len(args) - 1 offsetArg := len(args) rows, err := r.pool.Query(ctx, fmt.Sprintf(` SELECT %s FROM site_domain_mappings WHERE %s ORDER BY is_active DESC, registrable_domain ASC, id DESC LIMIT $%d OFFSET $%d`, siteDomainMappingColumns, where, limitArg, offsetArg), args...) if err != nil { return nil, 0, err } defer rows.Close() items := make([]domain.SiteDomainMapping, 0, limit) for rows.Next() { item, scanErr := scanSiteDomainMapping(rows) if scanErr != nil { return nil, 0, scanErr } items = append(items, *item) } return items, total, rows.Err() } func (r *SiteDomainMappingRepository) GetByID(ctx context.Context, id int64) (*domain.SiteDomainMapping, error) { return scanSiteDomainMapping(r.pool.QueryRow(ctx, ` SELECT `+siteDomainMappingColumns+` FROM site_domain_mappings WHERE id = $1`, id)) } func (r *SiteDomainMappingRepository) Create(ctx context.Context, in CreateSiteDomainMappingInput) (*domain.SiteDomainMapping, error) { return scanSiteDomainMapping(r.pool.QueryRow(ctx, ` INSERT INTO site_domain_mappings (registrable_domain, site_key, site_name, is_active) VALUES ($1, $2, $3, $4) RETURNING `+siteDomainMappingColumns, in.RegistrableDomain, in.SiteKey, in.SiteName, in.IsActive)) } func (r *SiteDomainMappingRepository) Update(ctx context.Context, id int64, in UpdateSiteDomainMappingInput) (*domain.SiteDomainMapping, error) { return scanSiteDomainMapping(r.pool.QueryRow(ctx, ` UPDATE site_domain_mappings SET registrable_domain = $1, site_key = $2, site_name = $3, is_active = $4, updated_at = NOW() WHERE id = $5 RETURNING `+siteDomainMappingColumns, in.RegistrableDomain, in.SiteKey, in.SiteName, in.IsActive, id)) } func (r *SiteDomainMappingRepository) SetActive(ctx context.Context, id int64, active bool) (*domain.SiteDomainMapping, error) { return scanSiteDomainMapping(r.pool.QueryRow(ctx, ` UPDATE site_domain_mappings SET is_active = $1, updated_at = NOW() WHERE id = $2 RETURNING `+siteDomainMappingColumns, active, id)) } func (r *SiteDomainMappingRepository) Delete(ctx context.Context, id int64) error { cmd, err := r.pool.Exec(ctx, `DELETE FROM site_domain_mappings WHERE id = $1`, id) if err != nil { return err } if cmd.RowsAffected() == 0 { return ErrSiteDomainMappingNotFound } return nil }