Adopt sqlc for typed Postgres queries behind store entities.

This commit is contained in:
2026-08-22 06:59:56 -07:00
parent c77298411e
commit b519cf6fe5
17 changed files with 1016 additions and 147 deletions
+66
View File
@@ -0,0 +1,66 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: answers.sql
package sqlc
import (
"context"
)
const getAnswer = `-- name: GetAnswer :one
SELECT a.question_id, a.author_id, u.name AS author_name, a.body, a.created_at, a.updated_at
FROM answers a
JOIN users u ON u.id = a.author_id
WHERE a.question_id = $1
`
type GetAnswerRow struct {
QuestionID string
AuthorID string
AuthorName string
Body string
CreatedAt string
UpdatedAt string
}
func (q *Queries) GetAnswer(ctx context.Context, questionID string) (GetAnswerRow, error) {
row := q.db.QueryRowContext(ctx, getAnswer, questionID)
var i GetAnswerRow
err := row.Scan(
&i.QuestionID,
&i.AuthorID,
&i.AuthorName,
&i.Body,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const upsertAnswer = `-- name: UpsertAnswer :exec
INSERT INTO answers (question_id, author_id, body, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (question_id) DO UPDATE
SET body = excluded.body, author_id = excluded.author_id, updated_at = excluded.updated_at
`
type UpsertAnswerParams struct {
QuestionID string
AuthorID string
Body string
CreatedAt string
UpdatedAt string
}
func (q *Queries) UpsertAnswer(ctx context.Context, arg UpsertAnswerParams) error {
_, err := q.db.ExecContext(ctx, upsertAnswer,
arg.QuestionID,
arg.AuthorID,
arg.Body,
arg.CreatedAt,
arg.UpdatedAt,
)
return err
}
+31
View File
@@ -0,0 +1,31 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package sqlc
import (
"context"
"database/sql"
)
type DBTX interface {
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
return &Queries{
db: tx,
}
}
+41
View File
@@ -0,0 +1,41 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package sqlc
type Answer struct {
QuestionID string
AuthorID string
Body string
CreatedAt string
UpdatedAt string
}
type Question struct {
ID string
AuthorID string
Title string
Body string
City string
HuntDate string
Hidden int32
CreatedAt string
}
type User struct {
ID string
Username string
Name string
PasswordHash string
Role string
AvatarUrl string
State string
CreatedAt string
}
type Vote struct {
UserID string
QuestionID string
Value int32
}
+296
View File
@@ -0,0 +1,296 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: questions.sql
package sqlc
import (
"context"
)
const createQuestion = `-- name: CreateQuestion :exec
INSERT INTO questions (id, author_id, title, body, city, hunt_date, hidden, created_at)
VALUES ($1, $2, $3, $4, $5, $6, 0, $7)
`
type CreateQuestionParams struct {
ID string
AuthorID string
Title string
Body string
City string
HuntDate string
CreatedAt string
}
func (q *Queries) CreateQuestion(ctx context.Context, arg CreateQuestionParams) error {
_, err := q.db.ExecContext(ctx, createQuestion,
arg.ID,
arg.AuthorID,
arg.Title,
arg.Body,
arg.City,
arg.HuntDate,
arg.CreatedAt,
)
return err
}
const getQuestion = `-- name: GetQuestion :one
SELECT q.id, q.author_id, u.name AS author_name, q.title, q.body, q.city, q.hunt_date, q.hidden, q.created_at,
COALESCE((SELECT SUM(value) FROM votes WHERE votes.question_id = q.id), 0)::bigint AS score,
CASE WHEN a.question_id IS NULL THEN 0 ELSE 1 END::bigint AS answered,
COALESCE((SELECT value FROM votes WHERE votes.user_id = $1 AND votes.question_id = q.id), 0)::bigint AS user_vote
FROM questions q
JOIN users u ON u.id = q.author_id
LEFT JOIN answers a ON a.question_id = q.id
WHERE q.id = $2
`
type GetQuestionParams struct {
UserID string
ID string
}
type GetQuestionRow struct {
ID string
AuthorID string
AuthorName string
Title string
Body string
City string
HuntDate string
Hidden int32
CreatedAt string
Score int64
Answered int64
UserVote int64
}
func (q *Queries) GetQuestion(ctx context.Context, arg GetQuestionParams) (GetQuestionRow, error) {
row := q.db.QueryRowContext(ctx, getQuestion, arg.UserID, arg.ID)
var i GetQuestionRow
err := row.Scan(
&i.ID,
&i.AuthorID,
&i.AuthorName,
&i.Title,
&i.Body,
&i.City,
&i.HuntDate,
&i.Hidden,
&i.CreatedAt,
&i.Score,
&i.Answered,
&i.UserVote,
)
return i, err
}
const hideQuestion = `-- name: HideQuestion :exec
UPDATE questions
SET hidden = 1
WHERE id = $1
`
func (q *Queries) HideQuestion(ctx context.Context, id string) error {
_, err := q.db.ExecContext(ctx, hideQuestion, id)
return err
}
const listHunt = `-- name: ListHunt :many
SELECT q.id, q.author_id, u.name AS author_name, q.title, q.body, q.city, q.hunt_date, q.hidden, q.created_at,
COALESCE(SUM(v.value), 0)::bigint AS score,
CASE WHEN a.question_id IS NULL THEN 0 ELSE 1 END::bigint AS answered,
COALESCE((SELECT value FROM votes WHERE votes.user_id = $1 AND votes.question_id = q.id), 0)::bigint AS user_vote
FROM questions q
JOIN users u ON u.id = q.author_id
LEFT JOIN votes v ON v.question_id = q.id
LEFT JOIN answers a ON a.question_id = q.id
WHERE q.hunt_date = $2 AND q.hidden = 0
GROUP BY q.id, q.author_id, u.name, q.title, q.body, q.city, q.hunt_date, q.hidden, q.created_at, a.question_id
ORDER BY score DESC, q.created_at ASC
`
type ListHuntParams struct {
UserID string
HuntDate string
}
type ListHuntRow struct {
ID string
AuthorID string
AuthorName string
Title string
Body string
City string
HuntDate string
Hidden int32
CreatedAt string
Score int64
Answered int64
UserVote int64
}
func (q *Queries) ListHunt(ctx context.Context, arg ListHuntParams) ([]ListHuntRow, error) {
rows, err := q.db.QueryContext(ctx, listHunt, arg.UserID, arg.HuntDate)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListHuntRow{}
for rows.Next() {
var i ListHuntRow
if err := rows.Scan(
&i.ID,
&i.AuthorID,
&i.AuthorName,
&i.Title,
&i.Body,
&i.City,
&i.HuntDate,
&i.Hidden,
&i.CreatedAt,
&i.Score,
&i.Answered,
&i.UserVote,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listQuestionsAnsweredBy = `-- name: ListQuestionsAnsweredBy :many
SELECT q.id, q.author_id, u.name AS author_name, q.title, q.body, q.city, q.hunt_date, q.hidden, q.created_at,
COALESCE((SELECT SUM(value) FROM votes WHERE votes.question_id = q.id), 0)::bigint AS score,
1::bigint AS answered,
0::bigint AS user_vote
FROM answers ans
JOIN questions q ON q.id = ans.question_id
JOIN users u ON u.id = q.author_id
WHERE ans.author_id = $1 AND q.hidden = 0
ORDER BY ans.updated_at DESC
`
type ListQuestionsAnsweredByRow struct {
ID string
AuthorID string
AuthorName string
Title string
Body string
City string
HuntDate string
Hidden int32
CreatedAt string
Score int64
Answered int64
UserVote int64
}
func (q *Queries) ListQuestionsAnsweredBy(ctx context.Context, authorID string) ([]ListQuestionsAnsweredByRow, error) {
rows, err := q.db.QueryContext(ctx, listQuestionsAnsweredBy, authorID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListQuestionsAnsweredByRow{}
for rows.Next() {
var i ListQuestionsAnsweredByRow
if err := rows.Scan(
&i.ID,
&i.AuthorID,
&i.AuthorName,
&i.Title,
&i.Body,
&i.City,
&i.HuntDate,
&i.Hidden,
&i.CreatedAt,
&i.Score,
&i.Answered,
&i.UserVote,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listQuestionsByAuthor = `-- name: ListQuestionsByAuthor :many
SELECT q.id, q.author_id, u.name AS author_name, q.title, q.body, q.city, q.hunt_date, q.hidden, q.created_at,
COALESCE((SELECT SUM(value) FROM votes WHERE votes.question_id = q.id), 0)::bigint AS score,
CASE WHEN a.question_id IS NULL THEN 0 ELSE 1 END::bigint AS answered,
0::bigint AS user_vote
FROM questions q
JOIN users u ON u.id = q.author_id
LEFT JOIN answers a ON a.question_id = q.id
WHERE q.author_id = $1 AND q.hidden = 0
ORDER BY q.created_at DESC
`
type ListQuestionsByAuthorRow struct {
ID string
AuthorID string
AuthorName string
Title string
Body string
City string
HuntDate string
Hidden int32
CreatedAt string
Score int64
Answered int64
UserVote int64
}
func (q *Queries) ListQuestionsByAuthor(ctx context.Context, authorID string) ([]ListQuestionsByAuthorRow, error) {
rows, err := q.db.QueryContext(ctx, listQuestionsByAuthor, authorID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListQuestionsByAuthorRow{}
for rows.Next() {
var i ListQuestionsByAuthorRow
if err := rows.Scan(
&i.ID,
&i.AuthorID,
&i.AuthorName,
&i.Title,
&i.Body,
&i.City,
&i.HuntDate,
&i.Hidden,
&i.CreatedAt,
&i.Score,
&i.Answered,
&i.UserVote,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
+222
View File
@@ -0,0 +1,222 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: users.sql
package sqlc
import (
"context"
"database/sql"
)
const countAdmins = `-- name: CountAdmins :one
SELECT COUNT(*)::bigint AS count
FROM users
WHERE role = $1
`
func (q *Queries) CountAdmins(ctx context.Context, role string) (int64, error) {
row := q.db.QueryRowContext(ctx, countAdmins, role)
var count int64
err := row.Scan(&count)
return count, err
}
const createUser = `-- name: CreateUser :exec
INSERT INTO users (id, username, name, password_hash, role, avatar_url, state, created_at)
VALUES ($1, $2, $3, $4, $5, '', '', $6)
`
type CreateUserParams struct {
ID string
Username string
Name string
PasswordHash string
Role string
CreatedAt string
}
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) error {
_, err := q.db.ExecContext(ctx, createUser,
arg.ID,
arg.Username,
arg.Name,
arg.PasswordHash,
arg.Role,
arg.CreatedAt,
)
return err
}
const getUserByID = `-- name: GetUserByID :one
SELECT id, username, name, role, avatar_url, state, created_at
FROM users
WHERE id = $1
`
type GetUserByIDRow struct {
ID string
Username string
Name string
Role string
AvatarUrl string
State string
CreatedAt string
}
func (q *Queries) GetUserByID(ctx context.Context, id string) (GetUserByIDRow, error) {
row := q.db.QueryRowContext(ctx, getUserByID, id)
var i GetUserByIDRow
err := row.Scan(
&i.ID,
&i.Username,
&i.Name,
&i.Role,
&i.AvatarUrl,
&i.State,
&i.CreatedAt,
)
return i, err
}
const getUserByUsername = `-- name: GetUserByUsername :one
SELECT id, username, name, role, avatar_url, state, created_at, password_hash
FROM users
WHERE username = $1
`
type GetUserByUsernameRow struct {
ID string
Username string
Name string
Role string
AvatarUrl string
State string
CreatedAt string
PasswordHash string
}
func (q *Queries) GetUserByUsername(ctx context.Context, username string) (GetUserByUsernameRow, error) {
row := q.db.QueryRowContext(ctx, getUserByUsername, username)
var i GetUserByUsernameRow
err := row.Scan(
&i.ID,
&i.Username,
&i.Name,
&i.Role,
&i.AvatarUrl,
&i.State,
&i.CreatedAt,
&i.PasswordHash,
)
return i, err
}
const getUserRole = `-- name: GetUserRole :one
SELECT role
FROM users
WHERE id = $1
`
func (q *Queries) GetUserRole(ctx context.Context, id string) (string, error) {
row := q.db.QueryRowContext(ctx, getUserRole, id)
var role string
err := row.Scan(&role)
return role, err
}
const listUsers = `-- name: ListUsers :many
SELECT id, username, name, role, avatar_url, state, created_at
FROM users
ORDER BY created_at ASC
`
type ListUsersRow struct {
ID string
Username string
Name string
Role string
AvatarUrl string
State string
CreatedAt string
}
func (q *Queries) ListUsers(ctx context.Context) ([]ListUsersRow, error) {
rows, err := q.db.QueryContext(ctx, listUsers)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListUsersRow{}
for rows.Next() {
var i ListUsersRow
if err := rows.Scan(
&i.ID,
&i.Username,
&i.Name,
&i.Role,
&i.AvatarUrl,
&i.State,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateUserRole = `-- name: UpdateUserRole :execresult
UPDATE users
SET role = $1
WHERE id = $2
`
type UpdateUserRoleParams struct {
Role string
ID string
}
func (q *Queries) UpdateUserRole(ctx context.Context, arg UpdateUserRoleParams) (sql.Result, error) {
return q.db.ExecContext(ctx, updateUserRole, arg.Role, arg.ID)
}
const updateUserState = `-- name: UpdateUserState :exec
UPDATE users
SET state = $1
WHERE id = $2
`
type UpdateUserStateParams struct {
State string
ID string
}
func (q *Queries) UpdateUserState(ctx context.Context, arg UpdateUserStateParams) error {
_, err := q.db.ExecContext(ctx, updateUserState, arg.State, arg.ID)
return err
}
const updateUserStateAndAvatar = `-- name: UpdateUserStateAndAvatar :exec
UPDATE users
SET state = $1, avatar_url = $2
WHERE id = $3
`
type UpdateUserStateAndAvatarParams struct {
State string
AvatarUrl string
ID string
}
func (q *Queries) UpdateUserStateAndAvatar(ctx context.Context, arg UpdateUserStateAndAvatarParams) error {
_, err := q.db.ExecContext(ctx, updateUserStateAndAvatar, arg.State, arg.AvatarUrl, arg.ID)
return err
}
+61
View File
@@ -0,0 +1,61 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: votes.sql
package sqlc
import (
"context"
)
const deleteVote = `-- name: DeleteVote :exec
DELETE FROM votes
WHERE user_id = $1 AND question_id = $2
`
type DeleteVoteParams struct {
UserID string
QuestionID string
}
func (q *Queries) DeleteVote(ctx context.Context, arg DeleteVoteParams) error {
_, err := q.db.ExecContext(ctx, deleteVote, arg.UserID, arg.QuestionID)
return err
}
const getVote = `-- name: GetVote :one
SELECT value
FROM votes
WHERE user_id = $1 AND question_id = $2
`
type GetVoteParams struct {
UserID string
QuestionID string
}
func (q *Queries) GetVote(ctx context.Context, arg GetVoteParams) (int32, error) {
row := q.db.QueryRowContext(ctx, getVote, arg.UserID, arg.QuestionID)
var value int32
err := row.Scan(&value)
return value, err
}
const upsertVote = `-- name: UpsertVote :exec
INSERT INTO votes (user_id, question_id, value)
VALUES ($1, $2, $3)
ON CONFLICT (user_id, question_id) DO UPDATE
SET value = excluded.value
`
type UpsertVoteParams struct {
UserID string
QuestionID string
Value int32
}
func (q *Queries) UpsertVote(ctx context.Context, arg UpsertVoteParams) error {
_, err := q.db.ExecContext(ctx, upsertVote, arg.UserID, arg.QuestionID, arg.Value)
return err
}