// Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 // source: subscription_scheduled_changes.sql package billing import ( "context" "database/sql" "time" "github.com/google/uuid" ) const applyScheduledChangesForSubscription = `-- name: ApplyScheduledChangesForSubscription :exec UPDATE core.subscription_scheduled_changes SET status = 'applied' WHERE subscription_id = $1 AND status = 'scheduled' ` // 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. func (q *Queries) ApplyScheduledChangesForSubscription(ctx context.Context, subscriptionID string) error { _, err := q.db.ExecContext(ctx, applyScheduledChangesForSubscription, subscriptionID) return err } const cancelScheduledChange = `-- name: CancelScheduledChange :one UPDATE core.subscription_scheduled_changes SET status = 'canceled' WHERE scheduled_change_id = $1 AND status = 'scheduled' RETURNING scheduled_change_id, subscription_id, change_type, target_price_id, target_quantity, effective_at, effective_trigger, credit_disposition, status, created_at, updated_at ` func (q *Queries) CancelScheduledChange(ctx context.Context, scheduledChangeID string) (SubscriptionScheduledChange, error) { row := q.db.QueryRowContext(ctx, cancelScheduledChange, scheduledChangeID) var i SubscriptionScheduledChange err := row.Scan( &i.ScheduledChangeID, &i.SubscriptionID, &i.ChangeType, &i.TargetPriceID, &i.TargetQuantity, &i.EffectiveAt, &i.EffectiveTrigger, &i.CreditDisposition, &i.Status, &i.CreatedAt, &i.UpdatedAt, ) return i, err } const createScheduledChange = `-- 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 scheduled_change_id, subscription_id, change_type, target_price_id, target_quantity, effective_at, effective_trigger, credit_disposition, status, created_at, updated_at ` type CreateScheduledChangeParams struct { SubscriptionID string `json:"subscription_id"` ChangeType string `json:"change_type"` TargetPriceID uuid.NullUUID `json:"target_price_id"` TargetQuantity sql.NullInt32 `json:"target_quantity"` EffectiveAt time.Time `json:"effective_at"` EffectiveTrigger string `json:"effective_trigger"` CreditDisposition sql.NullString `json:"credit_disposition"` } func (q *Queries) CreateScheduledChange(ctx context.Context, arg CreateScheduledChangeParams) (SubscriptionScheduledChange, error) { row := q.db.QueryRowContext(ctx, createScheduledChange, arg.SubscriptionID, arg.ChangeType, arg.TargetPriceID, arg.TargetQuantity, arg.EffectiveAt, arg.EffectiveTrigger, arg.CreditDisposition, ) var i SubscriptionScheduledChange err := row.Scan( &i.ScheduledChangeID, &i.SubscriptionID, &i.ChangeType, &i.TargetPriceID, &i.TargetQuantity, &i.EffectiveAt, &i.EffectiveTrigger, &i.CreditDisposition, &i.Status, &i.CreatedAt, &i.UpdatedAt, ) return i, err } const getScheduledChangeByID = `-- name: GetScheduledChangeByID :one SELECT scheduled_change_id, subscription_id, change_type, target_price_id, target_quantity, effective_at, effective_trigger, credit_disposition, status, created_at, updated_at FROM core.subscription_scheduled_changes WHERE scheduled_change_id = $1 ` func (q *Queries) GetScheduledChangeByID(ctx context.Context, scheduledChangeID string) (SubscriptionScheduledChange, error) { row := q.db.QueryRowContext(ctx, getScheduledChangeByID, scheduledChangeID) var i SubscriptionScheduledChange err := row.Scan( &i.ScheduledChangeID, &i.SubscriptionID, &i.ChangeType, &i.TargetPriceID, &i.TargetQuantity, &i.EffectiveAt, &i.EffectiveTrigger, &i.CreditDisposition, &i.Status, &i.CreatedAt, &i.UpdatedAt, ) return i, err } const listActiveScheduledChangesBySubscription = `-- name: ListActiveScheduledChangesBySubscription :many SELECT scheduled_change_id, subscription_id, change_type, target_price_id, target_quantity, effective_at, effective_trigger, credit_disposition, status, created_at, updated_at FROM core.subscription_scheduled_changes WHERE subscription_id = $1 AND status = 'scheduled' ORDER BY effective_at ASC ` func (q *Queries) ListActiveScheduledChangesBySubscription(ctx context.Context, subscriptionID string) ([]SubscriptionScheduledChange, error) { rows, err := q.db.QueryContext(ctx, listActiveScheduledChangesBySubscription, subscriptionID) if err != nil { return nil, err } defer rows.Close() items := []SubscriptionScheduledChange{} for rows.Next() { var i SubscriptionScheduledChange if err := rows.Scan( &i.ScheduledChangeID, &i.SubscriptionID, &i.ChangeType, &i.TargetPriceID, &i.TargetQuantity, &i.EffectiveAt, &i.EffectiveTrigger, &i.CreditDisposition, &i.Status, &i.CreatedAt, &i.UpdatedAt, ); 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 listDueScheduledChanges = `-- name: ListDueScheduledChanges :many SELECT scheduled_change_id, subscription_id, change_type, target_price_id, target_quantity, effective_at, effective_trigger, credit_disposition, status, created_at, updated_at FROM core.subscription_scheduled_changes WHERE status = 'scheduled' AND effective_at <= NOW() ORDER BY effective_at ASC ` // 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. func (q *Queries) ListDueScheduledChanges(ctx context.Context) ([]SubscriptionScheduledChange, error) { rows, err := q.db.QueryContext(ctx, listDueScheduledChanges) if err != nil { return nil, err } defer rows.Close() items := []SubscriptionScheduledChange{} for rows.Next() { var i SubscriptionScheduledChange if err := rows.Scan( &i.ScheduledChangeID, &i.SubscriptionID, &i.ChangeType, &i.TargetPriceID, &i.TargetQuantity, &i.EffectiveAt, &i.EffectiveTrigger, &i.CreditDisposition, &i.Status, &i.CreatedAt, &i.UpdatedAt, ); 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 markScheduledChangeApplied = `-- name: MarkScheduledChangeApplied :one UPDATE core.subscription_scheduled_changes SET status = 'applied' WHERE scheduled_change_id = $1 AND status = 'scheduled' RETURNING scheduled_change_id, subscription_id, change_type, target_price_id, target_quantity, effective_at, effective_trigger, credit_disposition, status, created_at, updated_at ` // Idempotency guard / claim: the status transition scheduled->applied is the // claim. A second firer (webhook vs sweeper) gets sql.ErrNoRows and no-ops. func (q *Queries) MarkScheduledChangeApplied(ctx context.Context, scheduledChangeID string) (SubscriptionScheduledChange, error) { row := q.db.QueryRowContext(ctx, markScheduledChangeApplied, scheduledChangeID) var i SubscriptionScheduledChange err := row.Scan( &i.ScheduledChangeID, &i.SubscriptionID, &i.ChangeType, &i.TargetPriceID, &i.TargetQuantity, &i.EffectiveAt, &i.EffectiveTrigger, &i.CreditDisposition, &i.Status, &i.CreatedAt, &i.UpdatedAt, ) return i, err } const supersedeActiveScheduledChanges = `-- name: SupersedeActiveScheduledChanges :exec UPDATE core.subscription_scheduled_changes SET status = 'superseded' WHERE subscription_id = $1 AND status = 'scheduled' ` // A new scheduled change (or an immediate action) supersedes any still-pending // intent on the same subscription. func (q *Queries) SupersedeActiveScheduledChanges(ctx context.Context, subscriptionID string) error { _, err := q.db.ExecContext(ctx, supersedeActiveScheduledChanges, subscriptionID) return err }