118 lines
4.4 KiB
Go
118 lines
4.4 KiB
Go
package postgres
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"gis/internal/domain"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
// DatasetGroupRepository persists dataset groups in Postgres.
|
|
type DatasetGroupRepository struct{ pool *pgxpool.Pool }
|
|
|
|
// NewDatasetGroupRepository returns a DatasetGroupRepository backed by pool.
|
|
func NewDatasetGroupRepository(pool *pgxpool.Pool) *DatasetGroupRepository {
|
|
return &DatasetGroupRepository{pool: pool}
|
|
}
|
|
|
|
const datasetGroupColumns = `id, code, name, description, sld_storage_key, sld_filename, sld_content_type, created_at, updated_at`
|
|
|
|
func scanDatasetGroup(row pgx.Row) (domain.DatasetGroup, error) {
|
|
var g domain.DatasetGroup
|
|
err := row.Scan(&g.ID, &g.Code, &g.Name, &g.Description, &g.SldStorageKey, &g.SldFilename, &g.SldContentType, &g.CreatedAt, &g.UpdatedAt)
|
|
return g, err
|
|
}
|
|
|
|
// Create inserts a new dataset group and returns the stored row.
|
|
func (r *DatasetGroupRepository) Create(ctx context.Context, g domain.DatasetGroup) (domain.DatasetGroup, error) {
|
|
row := r.pool.QueryRow(ctx,
|
|
`INSERT INTO dataset_groups (code, name, description) VALUES ($1, $2, $3) RETURNING `+datasetGroupColumns,
|
|
g.Code, g.Name, g.Description)
|
|
out, err := scanDatasetGroup(row)
|
|
return out, mapError(err)
|
|
}
|
|
|
|
// GetByID returns the group with the given id.
|
|
func (r *DatasetGroupRepository) GetByID(ctx context.Context, id uuid.UUID) (domain.DatasetGroup, error) {
|
|
out, err := scanDatasetGroup(r.pool.QueryRow(ctx, `SELECT `+datasetGroupColumns+` FROM dataset_groups WHERE id = $1`, id))
|
|
return out, mapError(err)
|
|
}
|
|
|
|
// GetByCode returns the group with the given (unique) code.
|
|
func (r *DatasetGroupRepository) GetByCode(ctx context.Context, code string) (domain.DatasetGroup, error) {
|
|
out, err := scanDatasetGroup(r.pool.QueryRow(ctx, `SELECT `+datasetGroupColumns+` FROM dataset_groups WHERE code = $1`, code))
|
|
return out, mapError(err)
|
|
}
|
|
|
|
// List returns a page of groups ordered by code; code (exact) is optional.
|
|
func (r *DatasetGroupRepository) List(ctx context.Context, code *string, limit, offset int) ([]domain.DatasetGroup, error) {
|
|
where, args := groupWhere(code)
|
|
args = append(args, limit, offset)
|
|
rows, err := r.pool.Query(ctx, fmt.Sprintf(`SELECT %s FROM dataset_groups%s ORDER BY code LIMIT $%d OFFSET $%d`,
|
|
datasetGroupColumns, where, len(args)-1, len(args)), args...)
|
|
if err != nil {
|
|
return nil, mapError(err)
|
|
}
|
|
defer rows.Close()
|
|
out := make([]domain.DatasetGroup, 0)
|
|
for rows.Next() {
|
|
g, err := scanDatasetGroup(rows)
|
|
if err != nil {
|
|
return nil, mapError(err)
|
|
}
|
|
out = append(out, g)
|
|
}
|
|
return out, mapError(rows.Err())
|
|
}
|
|
|
|
// Count returns how many groups match the optional code filter.
|
|
func (r *DatasetGroupRepository) Count(ctx context.Context, code *string) (int, error) {
|
|
where, args := groupWhere(code)
|
|
var n int
|
|
err := r.pool.QueryRow(ctx, `SELECT count(*) FROM dataset_groups`+where, args...).Scan(&n)
|
|
return n, mapError(err)
|
|
}
|
|
|
|
// groupWhere builds the optional exact-code WHERE clause and its arguments.
|
|
func groupWhere(code *string) (string, []any) {
|
|
if code == nil {
|
|
return "", nil
|
|
}
|
|
return " WHERE code = $1", []any{*code}
|
|
}
|
|
|
|
// Update replaces a group's editable fields and returns the stored row.
|
|
func (r *DatasetGroupRepository) Update(ctx context.Context, g domain.DatasetGroup) (domain.DatasetGroup, error) {
|
|
row := r.pool.QueryRow(ctx,
|
|
`UPDATE dataset_groups SET code = $2, name = $3, description = $4, updated_at = now() WHERE id = $1 RETURNING `+datasetGroupColumns,
|
|
g.ID, g.Code, g.Name, g.Description)
|
|
out, err := scanDatasetGroup(row)
|
|
return out, mapError(err)
|
|
}
|
|
|
|
// Delete removes a group. Returns domain.ErrNotFound if absent and
|
|
// domain.ErrConflict (via the FK) if datasets still reference it.
|
|
func (r *DatasetGroupRepository) Delete(ctx context.Context, id uuid.UUID) error {
|
|
tag, err := r.pool.Exec(ctx, `DELETE FROM dataset_groups WHERE id = $1`, id)
|
|
if err != nil {
|
|
return mapError(err)
|
|
}
|
|
if tag.RowsAffected() == 0 {
|
|
return domain.ErrNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SetSLD points the group at a stored SLD style object.
|
|
func (r *DatasetGroupRepository) SetSLD(ctx context.Context, id uuid.UUID, key, filename, contentType string) (domain.DatasetGroup, error) {
|
|
row := r.pool.QueryRow(ctx,
|
|
`UPDATE dataset_groups SET sld_storage_key = $2, sld_filename = $3, sld_content_type = $4, updated_at = now() WHERE id = $1 RETURNING `+datasetGroupColumns,
|
|
id, key, filename, contentType)
|
|
out, err := scanDatasetGroup(row)
|
|
return out, mapError(err)
|
|
}
|