-- name: CreateScheduledChange :one INSERT INTO core.subscription_scheduled_changes (subscription_id, change_type, target_price_id, target_quantity, effective_at, effective_trigger, credit_disposition) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *; -- name: GetScheduledChangeByID :one SELECT * FROM core.subscription_scheduled_changes WHERE scheduled_change_id = $1; -- name: ListActiveScheduledChangesBySubscription :many SELECT * FROM core.subscription_scheduled_changes WHERE subscription_id = $1 AND status = 'scheduled' ORDER BY effective_at ASC; -- name: ListDueScheduledChanges :many -- Sweeper backstop: due, not-yet-fired rows. Concurrency safety comes from the -- per-row claim (MarkScheduledChangeApplied), not row locking, so a plain read -- is sufficient. SELECT * FROM core.subscription_scheduled_changes WHERE status = 'scheduled' AND effective_at <= NOW() ORDER BY effective_at ASC; -- name: MarkScheduledChangeApplied :one -- Idempotency guard / claim: the status transition scheduled->applied is the -- claim. A second firer (webhook vs sweeper) gets sql.ErrNoRows and no-ops. UPDATE core.subscription_scheduled_changes SET status = 'applied' WHERE scheduled_change_id = $1 AND status = 'scheduled' RETURNING *; -- name: ApplyScheduledChangesForSubscription :exec -- Webhook-primary closeout: when a subscription actually ends (Stripe fires -- customer.subscription.deleted at period end), mark its still-pending scheduled -- changes applied so the intent ledger reflects what happened. UPDATE core.subscription_scheduled_changes SET status = 'applied' WHERE subscription_id = $1 AND status = 'scheduled'; -- name: CancelScheduledChange :one UPDATE core.subscription_scheduled_changes SET status = 'canceled' WHERE scheduled_change_id = $1 AND status = 'scheduled' RETURNING *; -- name: SupersedeActiveScheduledChanges :exec -- A new scheduled change (or an immediate action) supersedes any still-pending -- intent on the same subscription. UPDATE core.subscription_scheduled_changes SET status = 'superseded' WHERE subscription_id = $1 AND status = 'scheduled';