56 lines
1.2 KiB
Go
56 lines
1.2 KiB
Go
package user
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
var ErrUserAlreadyExists = errors.New("user already exists")
|
|
|
|
type User struct {
|
|
ID int64
|
|
Username string
|
|
PasswordHash string
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
type UserRepo struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
func NewUserRepo(db *sql.DB) *UserRepo {
|
|
return &UserRepo{db: db}
|
|
}
|
|
|
|
func (r *UserRepo) Create(ctx context.Context, username string, passwordHash string) error {
|
|
// sqlite 不同版本/驱动对 unique 冲突错误信息不完全一致,用字符串兜底识别。
|
|
_, err := r.db.ExecContext(ctx,
|
|
`INSERT INTO users(username, password_hash) VALUES(?, ?)`,
|
|
username, passwordHash,
|
|
)
|
|
if err != nil {
|
|
msg := strings.ToLower(err.Error())
|
|
if strings.Contains(msg, "unique") || strings.Contains(msg, "constraint failed") {
|
|
return ErrUserAlreadyExists
|
|
}
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *UserRepo) GetByUsername(ctx context.Context, username string) (*User, error) {
|
|
var u User
|
|
row := r.db.QueryRowContext(ctx,
|
|
`SELECT id, username, password_hash, created_at FROM users WHERE username = ?`,
|
|
username,
|
|
)
|
|
if err := row.Scan(&u.ID, &u.Username, &u.PasswordHash, &u.CreatedAt); err != nil {
|
|
return nil, err
|
|
}
|
|
return &u, nil
|
|
}
|
|
|