diff --git a/internal/user/queries/users.sql b/internal/user/queries/users.sql index 9bd5c10..c802eb0 100644 --- a/internal/user/queries/users.sql +++ b/internal/user/queries/users.sql @@ -1,2 +1,38 @@ --- name: Ping :one -SELECT 1::int AS ok; +-- name: CreateUser :one +INSERT INTO users (id, email, password_hash, display_name, is_admin) +VALUES ($1, $2, $3, $4, $5) +RETURNING id, email, password_hash, display_name, is_admin, created_at, updated_at; + +-- name: GetUserByEmail :one +SELECT id, email, password_hash, display_name, is_admin, created_at, updated_at +FROM users +WHERE email = $1; + +-- name: GetUserByID :one +SELECT id, email, password_hash, display_name, is_admin, created_at, updated_at +FROM users +WHERE id = $1; + +-- name: CountUsers :one +SELECT COUNT(*)::int FROM users; + +-- name: CreateSession :exec +INSERT INTO user_sessions (id, user_id, token_hash, expires_at) +VALUES ($1, $2, $3, $4); + +-- name: GetSessionByTokenHash :one +SELECT id, user_id, token_hash, expires_at, last_seen_at, created_at +FROM user_sessions +WHERE token_hash = $1 + AND expires_at > now(); + +-- name: TouchSession :exec +UPDATE user_sessions +SET last_seen_at = now() +WHERE token_hash = $1; + +-- name: DeleteSessionByTokenHash :exec +DELETE FROM user_sessions WHERE token_hash = $1; + +-- name: DeleteExpiredSessions :exec +DELETE FROM user_sessions WHERE expires_at <= now(); diff --git a/internal/user/sqlc/users.sql.go b/internal/user/sqlc/users.sql.go index e24f086..c26a84e 100644 --- a/internal/user/sqlc/users.sql.go +++ b/internal/user/sqlc/users.sql.go @@ -7,15 +7,166 @@ package usersqlc import ( "context" + + "github.com/jackc/pgx/v5/pgtype" ) -const ping = `-- name: Ping :one -SELECT 1::int AS ok +const countUsers = `-- name: CountUsers :one +SELECT COUNT(*)::int FROM users ` -func (q *Queries) Ping(ctx context.Context) (int32, error) { - row := q.db.QueryRow(ctx, ping) - var ok int32 - err := row.Scan(&ok) - return ok, err +func (q *Queries) CountUsers(ctx context.Context) (int32, error) { + row := q.db.QueryRow(ctx, countUsers) + var column_1 int32 + err := row.Scan(&column_1) + return column_1, err +} + +const createSession = `-- name: CreateSession :exec +INSERT INTO user_sessions (id, user_id, token_hash, expires_at) +VALUES ($1, $2, $3, $4) +` + +type CreateSessionParams struct { + ID pgtype.UUID `json:"id"` + UserID pgtype.UUID `json:"user_id"` + TokenHash []byte `json:"token_hash"` + ExpiresAt pgtype.Timestamptz `json:"expires_at"` +} + +func (q *Queries) CreateSession(ctx context.Context, arg CreateSessionParams) error { + _, err := q.db.Exec(ctx, createSession, + arg.ID, + arg.UserID, + arg.TokenHash, + arg.ExpiresAt, + ) + return err +} + +const createUser = `-- name: CreateUser :one +INSERT INTO users (id, email, password_hash, display_name, is_admin) +VALUES ($1, $2, $3, $4, $5) +RETURNING id, email, password_hash, display_name, is_admin, created_at, updated_at +` + +type CreateUserParams struct { + ID pgtype.UUID `json:"id"` + Email string `json:"email"` + PasswordHash string `json:"password_hash"` + DisplayName string `json:"display_name"` + IsAdmin bool `json:"is_admin"` +} + +func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, error) { + row := q.db.QueryRow(ctx, createUser, + arg.ID, + arg.Email, + arg.PasswordHash, + arg.DisplayName, + arg.IsAdmin, + ) + var i User + err := row.Scan( + &i.ID, + &i.Email, + &i.PasswordHash, + &i.DisplayName, + &i.IsAdmin, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const deleteExpiredSessions = `-- name: DeleteExpiredSessions :exec +DELETE FROM user_sessions WHERE expires_at <= now() +` + +func (q *Queries) DeleteExpiredSessions(ctx context.Context) error { + _, err := q.db.Exec(ctx, deleteExpiredSessions) + return err +} + +const deleteSessionByTokenHash = `-- name: DeleteSessionByTokenHash :exec +DELETE FROM user_sessions WHERE token_hash = $1 +` + +func (q *Queries) DeleteSessionByTokenHash(ctx context.Context, tokenHash []byte) error { + _, err := q.db.Exec(ctx, deleteSessionByTokenHash, tokenHash) + return err +} + +const getSessionByTokenHash = `-- name: GetSessionByTokenHash :one +SELECT id, user_id, token_hash, expires_at, last_seen_at, created_at +FROM user_sessions +WHERE token_hash = $1 + AND expires_at > now() +` + +func (q *Queries) GetSessionByTokenHash(ctx context.Context, tokenHash []byte) (UserSession, error) { + row := q.db.QueryRow(ctx, getSessionByTokenHash, tokenHash) + var i UserSession + err := row.Scan( + &i.ID, + &i.UserID, + &i.TokenHash, + &i.ExpiresAt, + &i.LastSeenAt, + &i.CreatedAt, + ) + return i, err +} + +const getUserByEmail = `-- name: GetUserByEmail :one +SELECT id, email, password_hash, display_name, is_admin, created_at, updated_at +FROM users +WHERE email = $1 +` + +func (q *Queries) GetUserByEmail(ctx context.Context, email string) (User, error) { + row := q.db.QueryRow(ctx, getUserByEmail, email) + var i User + err := row.Scan( + &i.ID, + &i.Email, + &i.PasswordHash, + &i.DisplayName, + &i.IsAdmin, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getUserByID = `-- name: GetUserByID :one +SELECT id, email, password_hash, display_name, is_admin, created_at, updated_at +FROM users +WHERE id = $1 +` + +func (q *Queries) GetUserByID(ctx context.Context, id pgtype.UUID) (User, error) { + row := q.db.QueryRow(ctx, getUserByID, id) + var i User + err := row.Scan( + &i.ID, + &i.Email, + &i.PasswordHash, + &i.DisplayName, + &i.IsAdmin, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const touchSession = `-- name: TouchSession :exec +UPDATE user_sessions +SET last_seen_at = now() +WHERE token_hash = $1 +` + +func (q *Queries) TouchSession(ctx context.Context, tokenHash []byte) error { + _, err := q.db.Exec(ctx, touchSession, tokenHash) + return err }