Squash the pre-production migration history into fresh core, fedwiki, and stripe baselines and reduce the canonical source list to those three streams. Update sqlc configs, generated queries, raw SQL, tests, and docs while keeping provider tables schema-qualified. BREAKING: existing local database volumes must be wiped because goose version history restarts from the new baselines.
249 lines
8.0 KiB
Go
249 lines
8.0 KiB
Go
// 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
|
|
}
|