package store import ( "context" "errors" "time" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" ) // PgUserRepository 基于 PostgreSQL 的 UserRepository 实现。 type PgUserRepository struct { pool *pgxpool.Pool } // NewPgUserRepository 创建 PgUserRepository。 func NewPgUserRepository(pool *pgxpool.Pool) *PgUserRepository { return &PgUserRepository{pool: pool} } func (r *PgUserRepository) Create(ctx context.Context, username, passwordHash string) (string, error) { var id string err := r.pool.QueryRow(ctx, `INSERT INTO users (username, password_hash) VALUES ($1, $2) RETURNING id`, username, passwordHash, ).Scan(&id) if err != nil { return "", err } return id, nil } func (r *PgUserRepository) FindByUsername(ctx context.Context, username string) (*User, error) { var u User err := r.pool.QueryRow(ctx, `SELECT id, username, password_hash, created_at, updated_at FROM users WHERE username = $1`, username, ).Scan(&u.ID, &u.Username, &u.PasswordHash, &u.CreatedAt, &u.UpdatedAt) if errors.Is(err, pgx.ErrNoRows) { return nil, ErrUserNotFound } if err != nil { return nil, err } return &u, nil } func (r *PgUserRepository) FindByID(ctx context.Context, id string) (*User, error) { var u User err := r.pool.QueryRow(ctx, `SELECT id, username, password_hash, created_at, updated_at FROM users WHERE id = $1`, id, ).Scan(&u.ID, &u.Username, &u.PasswordHash, &u.CreatedAt, &u.UpdatedAt) if errors.Is(err, pgx.ErrNoRows) { return nil, ErrUserNotFound } if err != nil { return nil, err } return &u, nil } func (r *PgUserRepository) SaveRefreshToken(ctx context.Context, userID, tokenHash string, expiresAt time.Time) error { _, err := r.pool.Exec(ctx, `INSERT INTO refresh_tokens (user_id, token_hash, expires_at) VALUES ($1, $2, $3)`, userID, tokenHash, expiresAt, ) return err } func (r *PgUserRepository) FindRefreshToken(ctx context.Context, tokenHash string) (string, error) { var userID string err := r.pool.QueryRow(ctx, `SELECT user_id FROM refresh_tokens WHERE token_hash = $1 AND expires_at > NOW()`, tokenHash, ).Scan(&userID) if errors.Is(err, pgx.ErrNoRows) { return "", ErrRefreshTokenNotFound } if err != nil { return "", err } return userID, nil } func (r *PgUserRepository) DeleteRefreshToken(ctx context.Context, tokenHash string) error { _, err := r.pool.Exec(ctx, `DELETE FROM refresh_tokens WHERE token_hash = $1`, tokenHash, ) return err } func (r *PgUserRepository) DeleteUserRefreshTokens(ctx context.Context, userID string) error { _, err := r.pool.Exec(ctx, `DELETE FROM refresh_tokens WHERE user_id = $1`, userID, ) return err }