Files
2026-10-03 20:28:25 +07:00

86 lines
2.1 KiB
Go

package store
import (
"context"
"errors"
"sync"
"5803025020/w04/internal/models"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
)
// ErrUsernameTaken dikembalikan saat Create() gagal karena username sudah dipakai (unique constraint).
var ErrUsernameTaken = errors.New("username already exists")
// ErrUserNotFound dikembalikan saat user dengan username/id yang diminta tidak ada.
var ErrUserNotFound = errors.New("user not found")
type UserStore struct {
conn *pgx.Conn
mu *sync.Mutex
}
func NewUserStore(conn *pgx.Conn, optMu ...*sync.Mutex) *UserStore {
var mu *sync.Mutex
if len(optMu) > 0 && optMu[0] != nil {
mu = optMu[0]
} else {
mu = &sync.Mutex{}
}
return &UserStore{conn: conn, mu: mu}
}
func (s *UserStore) Create(ctx context.Context, user *models.User) error {
s.mu.Lock()
defer s.mu.Unlock()
if user.ID == "" {
user.ID = uuid.New().String()
}
query := `INSERT INTO users (id, username, password_hash) VALUES ($1, $2, $3)`
_, err := s.conn.Exec(ctx, query, user.ID, user.Username, user.PasswordHash)
if err != nil {
var pgErr *pgconn.PgError
if errors.As(err, &pgErr) && pgErr.Code == "23505" {
return ErrUsernameTaken
}
return err
}
return nil
}
func (s *UserStore) GetByUsername(ctx context.Context, username string) (*models.User, error) {
s.mu.Lock()
defer s.mu.Unlock()
var u models.User
query := `SELECT id, username, password_hash FROM users WHERE username = $1`
err := s.conn.QueryRow(ctx, query, username).Scan(&u.ID, &u.Username, &u.PasswordHash)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return nil, ErrUserNotFound
}
return nil, err
}
return &u, nil
}
func (s *UserStore) GetByID(ctx context.Context, id string) (*models.User, error) {
s.mu.Lock()
defer s.mu.Unlock()
var u models.User
query := `SELECT id, username, password_hash FROM users WHERE id = $1`
err := s.conn.QueryRow(ctx, query, id).Scan(&u.ID, &u.Username, &u.PasswordHash)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return nil, ErrUserNotFound
}
return nil, err
}
return &u, nil
}