Add internal/plan: a draft_week job that drafts the week through the
harness from every Regular and the Quest log dinners no other current or
later plan holds, given the household context and last week's dinners,
and stores it as the week's plan; plan reads with the week label, is_new
and each crock-pot dinner's start_by (dinner time minus minutes_total,
computed on read); and day swaps that recompute is_new and move a synced
plan to changed. Drafting over a synced or changed plan needs confirm, at
enqueue and again when the job stores the week; a redraft keeps each
day's calendar event id.
Serve GET /api/v1/plans/{weekStart}, POST /api/v1/plans/{weekStart}/draft
(202 {job_id}, single-flight per week) and PUT
/api/v1/plans/{weekStart}/days/{date}; a weekStart that is not a Monday
is 400 invalid_week.
Maestro task ea48e650-d510-49cc-8485-0f07174ee731.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
82 lines
2.8 KiB
SQL
82 lines
2.8 KiB
SQL
-- name: GetWeekPlan :one
|
|
-- The plan of the week starting week_start. Returns sql.ErrNoRows when
|
|
-- there is none.
|
|
SELECT * FROM week_plans
|
|
WHERE week_start = ?;
|
|
|
|
-- name: ListPlanDays :many
|
|
-- The days of plan plan_id with their dinners, Monday first. A day with
|
|
-- no dinner is left out.
|
|
SELECT plan_days.date, plan_days.is_new, sqlc.embed(dinners)
|
|
FROM plan_days
|
|
JOIN dinners ON dinners.id = plan_days.dinner_id
|
|
WHERE plan_days.plan_id = ?
|
|
ORDER BY plan_days.date;
|
|
|
|
-- name: CreateWeekPlan :exec
|
|
INSERT INTO week_plans (id, week_start, status, ai_note, created_at, updated_at)
|
|
VALUES (?, ?, 'draft', ?, ?, ?);
|
|
|
|
-- name: RedraftWeekPlan :exec
|
|
-- Records a new draft over plan id: its status and note.
|
|
UPDATE week_plans
|
|
SET status = ?, ai_note = ?, updated_at = ?
|
|
WHERE id = ?;
|
|
|
|
-- name: PutPlanDay :exec
|
|
-- Plans dinner_id on date of plan_id, keeping the day's calendar event id
|
|
-- when the day exists.
|
|
INSERT INTO plan_days (id, plan_id, date, dinner_id, is_new, created_at, updated_at)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
ON CONFLICT (plan_id, date) DO UPDATE
|
|
SET dinner_id = excluded.dinner_id, is_new = excluded.is_new, updated_at = excluded.updated_at;
|
|
|
|
-- name: SwapPlanDay :execrows
|
|
-- Plans dinner_id on an existing day of plan_id; a date the plan does not
|
|
-- have is left as it is (0 rows).
|
|
UPDATE plan_days
|
|
SET dinner_id = ?, is_new = ?, updated_at = ?
|
|
WHERE plan_id = ? AND date = ?;
|
|
|
|
-- name: MarkWeekPlanEdited :exec
|
|
-- Records an edit of plan id: a synced plan becomes changed, any other
|
|
-- keeps its status.
|
|
UPDATE week_plans
|
|
SET status = CASE WHEN status = 'synced' THEN 'changed' ELSE status END,
|
|
updated_at = ?
|
|
WHERE id = ?;
|
|
|
|
-- name: ListDraftPool :many
|
|
-- The dinners a draft of the week starting week_start may plan: every
|
|
-- Regular, and every Quest log dinner no other plan for the week starting
|
|
-- from_week_start or later has on any day.
|
|
SELECT * FROM dinners
|
|
WHERE status = 'regular'
|
|
OR (status = 'quest_log' AND NOT EXISTS (
|
|
SELECT 1 FROM plan_days
|
|
JOIN week_plans ON week_plans.id = plan_days.plan_id
|
|
WHERE plan_days.dinner_id = dinners.id
|
|
AND week_plans.week_start >= sqlc.arg(from_week_start)
|
|
AND week_plans.week_start <> sqlc.arg(week_start)
|
|
))
|
|
ORDER BY normalized_name, id;
|
|
|
|
-- name: ListWeekPlanDinnerIDs :many
|
|
-- The ids of the dinners planned in the week starting week_start, Monday
|
|
-- first.
|
|
SELECT plan_days.dinner_id
|
|
FROM plan_days
|
|
JOIN week_plans ON week_plans.id = plan_days.plan_id
|
|
WHERE week_plans.week_start = ? AND plan_days.dinner_id IS NOT NULL
|
|
ORDER BY plan_days.date;
|
|
|
|
-- name: GetActiveDraftJobID :one
|
|
-- The id of the job of kind queued or running for the week starting
|
|
-- week_start. Returns sql.ErrNoRows when there is none.
|
|
SELECT id FROM jobs
|
|
WHERE kind = sqlc.arg(kind)
|
|
AND status IN ('queued', 'running')
|
|
AND json_extract(payload, '$.week_start') = sqlc.arg(week_start)
|
|
ORDER BY id
|
|
LIMIT 1;
|