package user import ( "context" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgxpool" ) type Repository interface { List(ctx context.Context) ([]User, error) Create(ctx context.Context, input CreateRequest, passwordHash string) (User, error) Update(ctx context.Context, userID uuid.UUID, input UpdateRequest, passwordHash *string) (User, error) Delete(ctx context.Context, userID uuid.UUID) error SetActive(ctx context.Context, userID uuid.UUID, active bool) error } type PGRepository struct { db *pgxpool.Pool } func NewPGRepository(db *pgxpool.Pool) *PGRepository { return &PGRepository{db: db} } func (r *PGRepository) List(ctx context.Context) ([]User, error) { rows, err := r.db.Query(ctx, ` select u.id, r.id, r.name, u.username::text, u.display_name, coalesce(u.email::text, ''), u.is_active from users u join roles r on r.id = u.role_id where u.deleted_at is null order by u.created_at desc `) if err != nil { return nil, err } defer rows.Close() var users []User for rows.Next() { var item User if err := rows.Scan(&item.ID, &item.RoleID, &item.RoleName, &item.Username, &item.DisplayName, &item.Email, &item.IsActive); err != nil { return nil, err } users = append(users, item) } return users, rows.Err() } func (r *PGRepository) Create(ctx context.Context, input CreateRequest, passwordHash string) (User, error) { const query = ` insert into users (id, role_id, username, display_name, email, password_hash) values ($1, (select id from roles where name = $2), $3, $4, nullif($5, ''), $6) returning id, (select id from roles where name = $2), $2, username::text, display_name, coalesce(email::text, ''), is_active ` item := User{RoleName: input.Role} err := r.db.QueryRow(ctx, query, uuid.New(), input.Role, input.Username, input.DisplayName, input.Email, passwordHash). Scan(&item.ID, &item.RoleID, &item.RoleName, &item.Username, &item.DisplayName, &item.Email, &item.IsActive) return item, err } func (r *PGRepository) SetActive(ctx context.Context, userID uuid.UUID, active bool) error { _, err := r.db.Exec(ctx, `update users set is_active = $2, updated_at = now() where id = $1`, userID, active) return err } func (r *PGRepository) Update(ctx context.Context, userID uuid.UUID, input UpdateRequest, passwordHash *string) (User, error) { const query = ` update users u set role_id = coalesce((select id from roles where name = $2), u.role_id), display_name = coalesce($3, u.display_name), email = case when $4 is null then u.email else nullif($4, '')::citext end, password_hash = coalesce($5, u.password_hash), is_active = coalesce($6, u.is_active), updated_at = now() where u.id = $1 and u.deleted_at is null returning u.id, u.role_id, (select name from roles where id = u.role_id), u.username::text, u.display_name, coalesce(u.email::text, ''), u.is_active ` var item User err := r.db.QueryRow(ctx, query, userID, input.Role, input.DisplayName, input.Email, passwordHash, input.IsActive). Scan(&item.ID, &item.RoleID, &item.RoleName, &item.Username, &item.DisplayName, &item.Email, &item.IsActive) return item, err } func (r *PGRepository) Delete(ctx context.Context, userID uuid.UUID) error { _, err := r.db.Exec(ctx, `update users set deleted_at = now(), updated_at = now() where id = $1 and deleted_at is null`, userID) return err }