Files
MealQuest/internal/db/dinners.sql.go
T
dev_agentandClaude Opus 5.5 d6d82e8368
CI / ci (push) Successful in 2m37s
CI / ci (pull_request) Successful in 2m18s
Ground new Regulars in the background and add recipe fix-up API
Creating a Regular now enqueues a ground_dinner job and returns at once
with its grounding_job_id. The job grounds the dinner's recipe_url with
GroundURL, else its name with Ground, and sets grounding_status grounded
(recipe, photo, method, minutes, difficulty) or failed with a
grounding_error reason code (migration 0009). It writes only a dinner
still pending, so a fix made meanwhile wins.

GET /api/v1/dinners/{id}/recipe-candidates returns up to 3 ranked
candidates {candidate_id, title, site_name, photo_url, minutes} without
downloading photos or running the model. POST /api/v1/dinners/{id}/ground
takes exactly one of {candidate_id}, {recipe_url} or {manual: {...}} and
sets grounded or manual.

PhotoCache takes an ImageFetcher interface and recipestest provides fakes
so other packages can test grounding with fake search, fetch and model.
main wires the Grounder with normalize_recipe over the AI settings.

Maestro task: 0cbaa5bf-8be4-4cbd-aab2-891e7f1bc2b5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 16:14:31 -04:00

557 lines
13 KiB
Go

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: dinners.sql
package db
import (
"context"
"database/sql"
)
const archiveDinner = `-- name: ArchiveDinner :one
UPDATE dinners
SET status = 'archived',
updated_by = ?,
updated_at = ?
WHERE id = ?
RETURNING id, name, normalized_name, status, origin, method, minutes_total, difficulty, cuisine, is_favorite, recipe_id, photo_id, grounding_status, updated_by, created_at, updated_at, recipe_url, grounding_error
`
type ArchiveDinnerParams struct {
UpdatedBy sql.NullString
UpdatedAt string
ID string
}
// An unknown id returns sql.ErrNoRows.
func (q *Queries) ArchiveDinner(ctx context.Context, arg ArchiveDinnerParams) (Dinner, error) {
row := q.db.QueryRowContext(ctx, archiveDinner, arg.UpdatedBy, arg.UpdatedAt, arg.ID)
var i Dinner
err := row.Scan(
&i.ID,
&i.Name,
&i.NormalizedName,
&i.Status,
&i.Origin,
&i.Method,
&i.MinutesTotal,
&i.Difficulty,
&i.Cuisine,
&i.IsFavorite,
&i.RecipeID,
&i.PhotoID,
&i.GroundingStatus,
&i.UpdatedBy,
&i.CreatedAt,
&i.UpdatedAt,
&i.RecipeUrl,
&i.GroundingError,
)
return i, err
}
const createDinner = `-- name: CreateDinner :one
INSERT INTO dinners (
id, name, normalized_name, status, origin, method, minutes_total,
difficulty, cuisine, is_favorite, recipe_id, recipe_url, photo_id,
grounding_status, updated_by, created_at, updated_at
) VALUES (
?, ?, ?, ?, ?, ?, ?,
?, ?, ?, ?, ?, ?,
?, ?, ?, ?
)
RETURNING id, name, normalized_name, status, origin, method, minutes_total, difficulty, cuisine, is_favorite, recipe_id, photo_id, grounding_status, updated_by, created_at, updated_at, recipe_url, grounding_error
`
type CreateDinnerParams struct {
ID string
Name string
NormalizedName string
Status string
Origin string
Method sql.NullString
MinutesTotal sql.NullInt64
Difficulty sql.NullString
Cuisine sql.NullString
IsFavorite int64
RecipeID sql.NullString
RecipeUrl sql.NullString
PhotoID sql.NullString
GroundingStatus string
UpdatedBy sql.NullString
CreatedAt string
UpdatedAt string
}
func (q *Queries) CreateDinner(ctx context.Context, arg CreateDinnerParams) (Dinner, error) {
row := q.db.QueryRowContext(ctx, createDinner,
arg.ID,
arg.Name,
arg.NormalizedName,
arg.Status,
arg.Origin,
arg.Method,
arg.MinutesTotal,
arg.Difficulty,
arg.Cuisine,
arg.IsFavorite,
arg.RecipeID,
arg.RecipeUrl,
arg.PhotoID,
arg.GroundingStatus,
arg.UpdatedBy,
arg.CreatedAt,
arg.UpdatedAt,
)
var i Dinner
err := row.Scan(
&i.ID,
&i.Name,
&i.NormalizedName,
&i.Status,
&i.Origin,
&i.Method,
&i.MinutesTotal,
&i.Difficulty,
&i.Cuisine,
&i.IsFavorite,
&i.RecipeID,
&i.PhotoID,
&i.GroundingStatus,
&i.UpdatedBy,
&i.CreatedAt,
&i.UpdatedAt,
&i.RecipeUrl,
&i.GroundingError,
)
return i, err
}
const failPendingDinnerGrounding = `-- name: FailPendingDinnerGrounding :execrows
UPDATE dinners
SET grounding_status = 'failed',
grounding_error = ?,
updated_at = ?
WHERE id = ? AND grounding_status = 'pending'
`
type FailPendingDinnerGroundingParams struct {
GroundingError sql.NullString
UpdatedAt string
ID string
}
// Records why the background grounding of a dinner still pending failed; a
// dinner grounded some other way meanwhile is left as it is (0 rows).
func (q *Queries) FailPendingDinnerGrounding(ctx context.Context, arg FailPendingDinnerGroundingParams) (int64, error) {
result, err := q.db.ExecContext(ctx, failPendingDinnerGrounding, arg.GroundingError, arg.UpdatedAt, arg.ID)
if err != nil {
return 0, err
}
return result.RowsAffected()
}
const getDinner = `-- name: GetDinner :one
SELECT id, name, normalized_name, status, origin, method, minutes_total, difficulty, cuisine, is_favorite, recipe_id, photo_id, grounding_status, updated_by, created_at, updated_at, recipe_url, grounding_error FROM dinners
WHERE id = ?
`
func (q *Queries) GetDinner(ctx context.Context, id string) (Dinner, error) {
row := q.db.QueryRowContext(ctx, getDinner, id)
var i Dinner
err := row.Scan(
&i.ID,
&i.Name,
&i.NormalizedName,
&i.Status,
&i.Origin,
&i.Method,
&i.MinutesTotal,
&i.Difficulty,
&i.Cuisine,
&i.IsFavorite,
&i.RecipeID,
&i.PhotoID,
&i.GroundingStatus,
&i.UpdatedBy,
&i.CreatedAt,
&i.UpdatedAt,
&i.RecipeUrl,
&i.GroundingError,
)
return i, err
}
const groundDinner = `-- name: GroundDinner :one
UPDATE dinners
SET recipe_id = ?,
photo_id = ?,
method = ?,
minutes_total = ?,
difficulty = ?,
grounding_status = ?,
grounding_error = NULL,
updated_by = ?,
updated_at = ?
WHERE id = ?
RETURNING id, name, normalized_name, status, origin, method, minutes_total, difficulty, cuisine, is_favorite, recipe_id, photo_id, grounding_status, updated_by, created_at, updated_at, recipe_url, grounding_error
`
type GroundDinnerParams struct {
RecipeID sql.NullString
PhotoID sql.NullString
Method sql.NullString
MinutesTotal sql.NullInt64
Difficulty sql.NullString
GroundingStatus string
UpdatedBy sql.NullString
UpdatedAt string
ID string
}
// Records a dinner's grounding (grounded or manual) and clears any
// grounding_error. An unknown id returns sql.ErrNoRows.
func (q *Queries) GroundDinner(ctx context.Context, arg GroundDinnerParams) (Dinner, error) {
row := q.db.QueryRowContext(ctx, groundDinner,
arg.RecipeID,
arg.PhotoID,
arg.Method,
arg.MinutesTotal,
arg.Difficulty,
arg.GroundingStatus,
arg.UpdatedBy,
arg.UpdatedAt,
arg.ID,
)
var i Dinner
err := row.Scan(
&i.ID,
&i.Name,
&i.NormalizedName,
&i.Status,
&i.Origin,
&i.Method,
&i.MinutesTotal,
&i.Difficulty,
&i.Cuisine,
&i.IsFavorite,
&i.RecipeID,
&i.PhotoID,
&i.GroundingStatus,
&i.UpdatedBy,
&i.CreatedAt,
&i.UpdatedAt,
&i.RecipeUrl,
&i.GroundingError,
)
return i, err
}
const groundPendingDinner = `-- name: GroundPendingDinner :execrows
UPDATE dinners
SET recipe_id = ?,
photo_id = ?,
method = ?,
minutes_total = ?,
difficulty = ?,
grounding_status = 'grounded',
grounding_error = NULL,
updated_at = ?
WHERE id = ? AND grounding_status = 'pending'
`
type GroundPendingDinnerParams struct {
RecipeID sql.NullString
PhotoID sql.NullString
Method sql.NullString
MinutesTotal sql.NullInt64
Difficulty sql.NullString
UpdatedAt string
ID string
}
// Records the background grounding of a dinner still pending; a dinner
// grounded some other way meanwhile is left as it is (0 rows).
func (q *Queries) GroundPendingDinner(ctx context.Context, arg GroundPendingDinnerParams) (int64, error) {
result, err := q.db.ExecContext(ctx, groundPendingDinner,
arg.RecipeID,
arg.PhotoID,
arg.Method,
arg.MinutesTotal,
arg.Difficulty,
arg.UpdatedAt,
arg.ID,
)
if err != nil {
return 0, err
}
return result.RowsAffected()
}
const listDinnersByStatus = `-- name: ListDinnersByStatus :many
SELECT id, name, normalized_name, status, origin, method, minutes_total, difficulty, cuisine, is_favorite, recipe_id, photo_id, grounding_status, updated_by, created_at, updated_at, recipe_url, grounding_error FROM dinners
WHERE status = ?
ORDER BY normalized_name, id
`
func (q *Queries) ListDinnersByStatus(ctx context.Context, status string) ([]Dinner, error) {
rows, err := q.db.QueryContext(ctx, listDinnersByStatus, status)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Dinner
for rows.Next() {
var i Dinner
if err := rows.Scan(
&i.ID,
&i.Name,
&i.NormalizedName,
&i.Status,
&i.Origin,
&i.Method,
&i.MinutesTotal,
&i.Difficulty,
&i.Cuisine,
&i.IsFavorite,
&i.RecipeID,
&i.PhotoID,
&i.GroundingStatus,
&i.UpdatedBy,
&i.CreatedAt,
&i.UpdatedAt,
&i.RecipeUrl,
&i.GroundingError,
); 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 listUnarchivedDinners = `-- name: ListUnarchivedDinners :many
SELECT id, name, normalized_name, status, origin, method, minutes_total, difficulty, cuisine, is_favorite, recipe_id, photo_id, grounding_status, updated_by, created_at, updated_at, recipe_url, grounding_error FROM dinners
WHERE status <> 'archived'
ORDER BY id
`
// Every dinner a new or renamed dinner must not repeat.
func (q *Queries) ListUnarchivedDinners(ctx context.Context) ([]Dinner, error) {
rows, err := q.db.QueryContext(ctx, listUnarchivedDinners)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Dinner
for rows.Next() {
var i Dinner
if err := rows.Scan(
&i.ID,
&i.Name,
&i.NormalizedName,
&i.Status,
&i.Origin,
&i.Method,
&i.MinutesTotal,
&i.Difficulty,
&i.Cuisine,
&i.IsFavorite,
&i.RecipeID,
&i.PhotoID,
&i.GroundingStatus,
&i.UpdatedBy,
&i.CreatedAt,
&i.UpdatedAt,
&i.RecipeUrl,
&i.GroundingError,
); 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 setDinnerFavorite = `-- name: SetDinnerFavorite :one
UPDATE dinners
SET is_favorite = ?,
updated_by = ?,
updated_at = ?
WHERE id = ?
RETURNING id, name, normalized_name, status, origin, method, minutes_total, difficulty, cuisine, is_favorite, recipe_id, photo_id, grounding_status, updated_by, created_at, updated_at, recipe_url, grounding_error
`
type SetDinnerFavoriteParams struct {
IsFavorite int64
UpdatedBy sql.NullString
UpdatedAt string
ID string
}
// An unknown id returns sql.ErrNoRows.
func (q *Queries) SetDinnerFavorite(ctx context.Context, arg SetDinnerFavoriteParams) (Dinner, error) {
row := q.db.QueryRowContext(ctx, setDinnerFavorite,
arg.IsFavorite,
arg.UpdatedBy,
arg.UpdatedAt,
arg.ID,
)
var i Dinner
err := row.Scan(
&i.ID,
&i.Name,
&i.NormalizedName,
&i.Status,
&i.Origin,
&i.Method,
&i.MinutesTotal,
&i.Difficulty,
&i.Cuisine,
&i.IsFavorite,
&i.RecipeID,
&i.PhotoID,
&i.GroundingStatus,
&i.UpdatedBy,
&i.CreatedAt,
&i.UpdatedAt,
&i.RecipeUrl,
&i.GroundingError,
)
return i, err
}
const toggleDinnerFavorite = `-- name: ToggleDinnerFavorite :one
UPDATE dinners
SET is_favorite = 1 - is_favorite,
updated_by = ?,
updated_at = ?
WHERE id = ?
RETURNING id, name, normalized_name, status, origin, method, minutes_total, difficulty, cuisine, is_favorite, recipe_id, photo_id, grounding_status, updated_by, created_at, updated_at, recipe_url, grounding_error
`
type ToggleDinnerFavoriteParams struct {
UpdatedBy sql.NullString
UpdatedAt string
ID string
}
// An unknown id returns sql.ErrNoRows.
func (q *Queries) ToggleDinnerFavorite(ctx context.Context, arg ToggleDinnerFavoriteParams) (Dinner, error) {
row := q.db.QueryRowContext(ctx, toggleDinnerFavorite, arg.UpdatedBy, arg.UpdatedAt, arg.ID)
var i Dinner
err := row.Scan(
&i.ID,
&i.Name,
&i.NormalizedName,
&i.Status,
&i.Origin,
&i.Method,
&i.MinutesTotal,
&i.Difficulty,
&i.Cuisine,
&i.IsFavorite,
&i.RecipeID,
&i.PhotoID,
&i.GroundingStatus,
&i.UpdatedBy,
&i.CreatedAt,
&i.UpdatedAt,
&i.RecipeUrl,
&i.GroundingError,
)
return i, err
}
const updateDinner = `-- name: UpdateDinner :one
UPDATE dinners
SET name = ?,
normalized_name = ?,
status = ?,
origin = ?,
method = ?,
minutes_total = ?,
difficulty = ?,
cuisine = ?,
recipe_id = ?,
photo_id = ?,
grounding_status = ?,
updated_by = ?,
updated_at = ?
WHERE id = ?
RETURNING id, name, normalized_name, status, origin, method, minutes_total, difficulty, cuisine, is_favorite, recipe_id, photo_id, grounding_status, updated_by, created_at, updated_at, recipe_url, grounding_error
`
type UpdateDinnerParams struct {
Name string
NormalizedName string
Status string
Origin string
Method sql.NullString
MinutesTotal sql.NullInt64
Difficulty sql.NullString
Cuisine sql.NullString
RecipeID sql.NullString
PhotoID sql.NullString
GroundingStatus string
UpdatedBy sql.NullString
UpdatedAt string
ID string
}
// An unknown id returns sql.ErrNoRows.
func (q *Queries) UpdateDinner(ctx context.Context, arg UpdateDinnerParams) (Dinner, error) {
row := q.db.QueryRowContext(ctx, updateDinner,
arg.Name,
arg.NormalizedName,
arg.Status,
arg.Origin,
arg.Method,
arg.MinutesTotal,
arg.Difficulty,
arg.Cuisine,
arg.RecipeID,
arg.PhotoID,
arg.GroundingStatus,
arg.UpdatedBy,
arg.UpdatedAt,
arg.ID,
)
var i Dinner
err := row.Scan(
&i.ID,
&i.Name,
&i.NormalizedName,
&i.Status,
&i.Origin,
&i.Method,
&i.MinutesTotal,
&i.Difficulty,
&i.Cuisine,
&i.IsFavorite,
&i.RecipeID,
&i.PhotoID,
&i.GroundingStatus,
&i.UpdatedBy,
&i.CreatedAt,
&i.UpdatedAt,
&i.RecipeUrl,
&i.GroundingError,
)
return i, err
}