go-chi-oapi-codegen-todolist/backend/internal/repository/user_repo.go
2025-04-20 15:58:52 +07:00

157 lines
3.6 KiB
Go

package repository
import (
"context"
"errors"
"github.com/Sosokker/todolist-backend/internal/domain"
db "github.com/Sosokker/todolist-backend/internal/repository/sqlc/generated"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
"github.com/jackc/pgx/v5/pgtype"
)
type pgxUserRepository struct {
q *db.Queries
}
func NewPgxUserRepository(queries *db.Queries) UserRepository {
return &pgxUserRepository{q: queries}
}
// mapDbUserToDomain converts a generated User → domain.User
func mapDbUserToDomain(u db.User) *domain.User {
var googleID *string
if u.GoogleID.Valid {
googleID = &u.GoogleID.String
}
return &domain.User{
ID: u.ID,
Username: u.Username,
Email: u.Email,
PasswordHash: u.PasswordHash,
EmailVerified: u.EmailVerified,
GoogleID: googleID,
CreatedAt: u.CreatedAt,
UpdatedAt: u.UpdatedAt,
}
}
func (r *pgxUserRepository) Create(
ctx context.Context,
user *domain.User,
) (*domain.User, error) {
var pgGoogleID pgtype.Text
if user.GoogleID != nil {
pgGoogleID = pgtype.Text{String: *user.GoogleID, Valid: true}
}
dbUser, err := r.q.CreateUser(ctx, db.CreateUserParams{
Username: user.Username,
Email: user.Email,
PasswordHash: user.PasswordHash,
EmailVerified: user.EmailVerified,
GoogleID: pgGoogleID,
})
if err != nil {
var pgErr *pgconn.PgError
if errors.As(err, &pgErr) && pgErr.Code == "23505" {
return nil, domain.ErrConflict
}
return nil, err
}
return mapDbUserToDomain(dbUser), nil
}
func (r *pgxUserRepository) GetByID(
ctx context.Context,
id uuid.UUID,
) (*domain.User, error) {
dbUser, err := r.q.GetUserByID(ctx, id)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return nil, domain.ErrNotFound
}
return nil, err
}
return mapDbUserToDomain(dbUser), nil
}
func (r *pgxUserRepository) GetByEmail(
ctx context.Context,
email string,
) (*domain.User, error) {
dbUser, err := r.q.GetUserByEmail(ctx, email)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return nil, domain.ErrNotFound
}
return nil, err
}
return mapDbUserToDomain(dbUser), nil
}
func (r *pgxUserRepository) GetByGoogleID(
ctx context.Context,
googleID string,
) (*domain.User, error) {
pgGoogleID := pgtype.Text{String: googleID, Valid: true}
dbUser, err := r.q.GetUserByGoogleID(ctx, pgGoogleID)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return nil, domain.ErrNotFound
}
return nil, err
}
return mapDbUserToDomain(dbUser), nil
}
func (r *pgxUserRepository) Update(
ctx context.Context,
id uuid.UUID,
u *domain.User,
) (*domain.User, error) {
if _, err := r.GetByID(ctx, id); err != nil {
return nil, err
}
var username pgtype.Text
if u.Username != "" {
username = pgtype.Text{String: u.Username, Valid: true}
}
var email pgtype.Text
if u.Email != "" {
email = pgtype.Text{String: u.Email, Valid: true}
}
emailVerified := pgtype.Bool{Bool: u.EmailVerified, Valid: true}
var pgGoogleID pgtype.Text
if u.GoogleID != nil {
pgGoogleID = pgtype.Text{String: *u.GoogleID, Valid: true}
}
dbUser, err := r.q.UpdateUser(ctx, db.UpdateUserParams{
ID: id,
Username: username,
Email: email,
EmailVerified: emailVerified,
GoogleID: pgGoogleID,
})
if err != nil {
var pgErr *pgconn.PgError
if errors.As(err, &pgErr) && pgErr.Code == "23505" {
return nil, domain.ErrConflict
}
return nil, err
}
return mapDbUserToDomain(dbUser), nil
}
func (r *pgxUserRepository) Delete(
ctx context.Context,
id uuid.UUID,
) error {
return r.q.DeleteUser(ctx, id)
}