-- name: CreatePlanLadder :one -- `key` is the optional declarative address (entity-keys §3), root-scoped. -- The operator create form asks for a name only, so a UI-created ladder -- leaves it NULL; a seed or a configuration loader supplies it. INSERT INTO core.plan_ladders (name, description, is_active, key) VALUES ($1, $2, $3, sqlc.narg(key)) RETURNING *; -- name: GetPlanLadderByKey :one -- Root key resolver (entity-keys §5). uq_plan_ladders_key guarantees at most -- one row matches. SELECT * FROM core.plan_ladders WHERE key = $1; -- name: ListPlanLadders :many SELECT * FROM core.plan_ladders ORDER BY sort_order ASC, name ASC; -- name: GetPlanLadderByID :one SELECT * FROM core.plan_ladders WHERE plan_ladder_id = $1; -- name: UpdatePlanLadder :one UPDATE core.plan_ladders SET name = $2, description = $3, is_active = $4 WHERE plan_ladder_id = $1 RETURNING *; -- name: SetPlanLadderSortOrder :exec -- Sets a single ladder's display order. Used by the topology reorder flow, -- which renumbers ladders to a contiguous sequence; sort_order is deliberately -- NOT writable via UpdatePlanLadder so editing a ladder never reorders it. UPDATE core.plan_ladders SET sort_order = $2 WHERE plan_ladder_id = $1; -- name: DeletePlanLadder :exec DELETE FROM core.plan_ladders WHERE plan_ladder_id = $1; -- name: CreatePlanLadderTier :one -- Appends the tier at the end of the ladder: rank self-assigns to MAX+1 in the -- INSERT itself (no read-then-write race). Reorder keeps ranks contiguous -- 0..N-1, so MAX+1 == COUNT; operators position tiers by drag-and-drop. INSERT INTO core.plan_ladder_tiers (plan_ladder_id, product_id, rank) VALUES ($1, $2, ( SELECT COALESCE(MAX(rank) + 1, 0) FROM core.plan_ladder_tiers WHERE plan_ladder_id = $1 )) RETURNING *; -- name: EnsurePlanLadderTier :exec -- Idempotent tier membership for a seed (entity-keys §6 as amended by §9 A1: -- a seed ensures a row exists and never overwrites one). A tier has no key of -- its own: it is a relationship, and its identity is the pair (§2 class E), -- which is also its primary key. Rank self-assigns to MAX+1 exactly as -- CreatePlanLadderTier does, so a caller inserting tiers in ascending order -- gets 0..N-1; a second run conflicts on the pair and does nothing, leaving -- an operator's own reordering alone. INSERT INTO core.plan_ladder_tiers (plan_ladder_id, product_id, rank) VALUES ($1, $2, ( SELECT COALESCE(MAX(rank) + 1, 0) FROM core.plan_ladder_tiers WHERE plan_ladder_id = $1 )) ON CONFLICT (plan_ladder_id, product_id) DO NOTHING; -- name: ListTiersByLadder :many SELECT * FROM core.plan_ladder_tiers WHERE plan_ladder_id = $1 ORDER BY rank ASC; -- name: ListTiersByLadderWithProducts :many SELECT t.plan_ladder_id, t.product_id, t.rank, t.created_at, t.updated_at, p.name AS product_name, p.display_category, p.lifecycle_status FROM core.plan_ladder_tiers t JOIN core.products p ON p.product_id = t.product_id WHERE t.plan_ladder_id = $1 ORDER BY t.rank ASC; -- name: ListLaddersByProduct :many SELECT t.*, l.name AS ladder_name FROM core.plan_ladder_tiers t JOIN core.plan_ladders l ON l.plan_ladder_id = t.plan_ladder_id WHERE t.product_id = $1 ORDER BY l.name ASC; -- name: GetTier :one SELECT * FROM core.plan_ladder_tiers WHERE plan_ladder_id = $1 AND product_id = $2; -- name: GetTierByLadderRank :one SELECT * FROM core.plan_ladder_tiers WHERE plan_ladder_id = $1 AND rank = $2; -- name: ListPlanLaddersWithRankZeroProduct :many -- LEFT JOINs on purpose: a ladder whose rank-0 tier was deleted must still -- appear (product columns NULL) so surfaces that reference it — notably an -- org type's configured default — can show it as broken instead of silently -- dropping it from a dropdown and NULLing the stored value on save. SELECT l.plan_ladder_id, l.name AS ladder_name, l.is_active, t.product_id, p.name AS rank_zero_product_name FROM core.plan_ladders l LEFT JOIN core.plan_ladder_tiers t ON t.plan_ladder_id = l.plan_ladder_id AND t.rank = 0 LEFT JOIN core.products p ON p.product_id = t.product_id ORDER BY l.name ASC; -- name: UpdateTierRank :one UPDATE core.plan_ladder_tiers SET rank = $3 WHERE plan_ladder_id = $1 AND product_id = $2 RETURNING *; -- name: DeleteTier :exec DELETE FROM core.plan_ladder_tiers WHERE plan_ladder_id = $1 AND product_id = $2; -- name: ListSharedTierProducts :many -- Products that are a tier in more than one ladder (the many-to-many made -- legible for the operator topology overview). Returns one row per -- (shared product, ladder) membership, ordered for stable grouping in Go. SELECT t.product_id, p.name AS product_name, t.plan_ladder_id, l.name AS ladder_name, t.rank FROM core.plan_ladder_tiers t JOIN core.products p ON p.product_id = t.product_id JOIN core.plan_ladders l ON l.plan_ladder_id = t.plan_ladder_id WHERE t.product_id IN ( SELECT product_id FROM core.plan_ladder_tiers GROUP BY product_id HAVING COUNT(*) > 1 ) ORDER BY p.name ASC, l.sort_order ASC, l.name ASC; -- name: AnyRankZeroTier :one -- Setup-checklist existence probe: a ladder delivers only through its rank-0 -- tier, so "ladder exists" alone is not the step. SELECT EXISTS(SELECT 1 FROM core.plan_ladder_tiers WHERE rank = 0);