Add an append-only ledger of entitlement set rule changes with per-pool effect rows, a preview-and-commit rule change flow, and an automatic drain that settles deferred recomputations. Rules gain a tier reduction policy, resource keys declare over-limit behavior, and the materializer now lowers limits when a rule stops applying. Add entitlement set rule change ledger and preview flow Add an append-only ledger of entitlement set rule changes with a preview-and-commit operator flow. Rule writes now go through an enclosed `core.commit_rule_change` function that files an act row and one obligation per carrying pool, with a drain workflow settling deferred recomputations. The preview dry-runs the materializer with a rule overlay and renders per-pool buckets, reduction-policy disclosures, and provider over-limit consequences. Materializing transactions take a shared advisory rendezvous that rule changes hold exclusively, enforced by a possession assertion. Add History and Entitlement changes surfaces, a rule-less warning on five product-selection surfaces, and a `tier_reduction_policy` column that gates FedWiki parking.
393 lines
12 KiB
Go
393 lines
12 KiB
Go
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Commercial
|
|
// SPDX-FileCopyrightText: 2025-2026 Christian Galo
|
|
|
|
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.29.0
|
|
// source: pool_provisions.sql
|
|
|
|
package entitlements
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
const countCarryingPoolsAtOrOverLimit = `-- name: CountCarryingPoolsAtOrOverLimit :one
|
|
SELECT COUNT(DISTINCT pp.pool_id)::BIGINT AS pool_count
|
|
FROM core.pool_provisions pp
|
|
JOIN core.numeric_entitlements ne ON ne.pool_id = pp.pool_id
|
|
JOIN core.numeric_entitlement_usage u ON u.entitlement_id = ne.entitlement_id
|
|
WHERE pp.entitlement_set_id = $1
|
|
AND pp.status = 'active'
|
|
AND ne.resource_key = $2
|
|
AND u.current_usage >= ne.resource_limit
|
|
`
|
|
|
|
type CountCarryingPoolsAtOrOverLimitParams struct {
|
|
SetID string `json:"set_id"`
|
|
ResourceKey string `json:"resource_key"`
|
|
}
|
|
|
|
// Carrying pools whose recorded usage of one key has reached or passed the
|
|
// pool's materialized limit: the aggregate-mode preview's one exact fact.
|
|
func (q *Queries) CountCarryingPoolsAtOrOverLimit(ctx context.Context, arg CountCarryingPoolsAtOrOverLimitParams) (int64, error) {
|
|
row := q.db.QueryRowContext(ctx, countCarryingPoolsAtOrOverLimit, arg.SetID, arg.ResourceKey)
|
|
var pool_count int64
|
|
err := row.Scan(&pool_count)
|
|
return pool_count, err
|
|
}
|
|
|
|
const countPoolsCarryingSet = `-- name: CountPoolsCarryingSet :one
|
|
SELECT COUNT(DISTINCT pp.pool_id)::BIGINT AS pool_count,
|
|
COUNT(DISTINCT rp.org_id)::BIGINT AS org_count
|
|
FROM core.pool_provisions pp
|
|
JOIN core.resource_pools rp ON rp.pool_id = pp.pool_id
|
|
WHERE pp.entitlement_set_id = $1 AND pp.status = 'active'
|
|
`
|
|
|
|
type CountPoolsCarryingSetRow struct {
|
|
PoolCount int64 `json:"pool_count"`
|
|
OrgCount int64 `json:"org_count"`
|
|
}
|
|
|
|
func (q *Queries) CountPoolsCarryingSet(ctx context.Context, entitlementSetID string) (CountPoolsCarryingSetRow, error) {
|
|
row := q.db.QueryRowContext(ctx, countPoolsCarryingSet, entitlementSetID)
|
|
var i CountPoolsCarryingSetRow
|
|
err := row.Scan(&i.PoolCount, &i.OrgCount)
|
|
return i, err
|
|
}
|
|
|
|
const countSuspendedOnlyPoolsCarryingSet = `-- name: CountSuspendedOnlyPoolsCarryingSet :one
|
|
SELECT COUNT(*)::BIGINT AS pool_count FROM (
|
|
SELECT pp.pool_id
|
|
FROM core.pool_provisions pp
|
|
WHERE pp.entitlement_set_id = $1
|
|
GROUP BY pp.pool_id
|
|
HAVING BOOL_OR(pp.status = 'suspended') AND NOT BOOL_OR(pp.status = 'active')
|
|
) s
|
|
`
|
|
|
|
// Pools holding the set only through suspended provisions: they carry nothing
|
|
// today, so a change does not reach them until the provision resumes.
|
|
func (q *Queries) CountSuspendedOnlyPoolsCarryingSet(ctx context.Context, entitlementSetID string) (int64, error) {
|
|
row := q.db.QueryRowContext(ctx, countSuspendedOnlyPoolsCarryingSet, entitlementSetID)
|
|
var pool_count int64
|
|
err := row.Scan(&pool_count)
|
|
return pool_count, err
|
|
}
|
|
|
|
const getActivePoolProvisionsByPoolID = `-- name: GetActivePoolProvisionsByPoolID :many
|
|
SELECT provision_id, pool_id, billing_account_id, subscription_id, purchase_id, grant_id, quantity, status, activated_at, suspended_at, ended_at, created_at, updated_at, entitlement_set_id, product_id FROM core.pool_provisions
|
|
WHERE pool_id = $1 AND status = 'active'
|
|
ORDER BY created_at ASC
|
|
`
|
|
|
|
func (q *Queries) GetActivePoolProvisionsByPoolID(ctx context.Context, poolID string) ([]PoolProvision, error) {
|
|
rows, err := q.db.QueryContext(ctx, getActivePoolProvisionsByPoolID, poolID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []PoolProvision{}
|
|
for rows.Next() {
|
|
var i PoolProvision
|
|
if err := rows.Scan(
|
|
&i.ProvisionID,
|
|
&i.PoolID,
|
|
&i.BillingAccountID,
|
|
&i.SubscriptionID,
|
|
&i.PurchaseID,
|
|
&i.GrantID,
|
|
&i.Quantity,
|
|
&i.Status,
|
|
&i.ActivatedAt,
|
|
&i.SuspendedAt,
|
|
&i.EndedAt,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.EntitlementSetID,
|
|
&i.ProductID,
|
|
); 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 getLivePoolProvisionsByProductID = `-- name: GetLivePoolProvisionsByProductID :many
|
|
SELECT provision_id, pool_id, billing_account_id, subscription_id, purchase_id, grant_id, quantity, status, activated_at, suspended_at, ended_at, created_at, updated_at, entitlement_set_id, product_id FROM core.pool_provisions
|
|
WHERE product_id = $1 AND status <> 'ended'
|
|
ORDER BY created_at ASC
|
|
`
|
|
|
|
// Live (non-ended) provisions delivering a product. Tier add/remove aligns
|
|
// each of these to the product's new conferral shape.
|
|
func (q *Queries) GetLivePoolProvisionsByProductID(ctx context.Context, productID string) ([]PoolProvision, error) {
|
|
rows, err := q.db.QueryContext(ctx, getLivePoolProvisionsByProductID, productID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []PoolProvision{}
|
|
for rows.Next() {
|
|
var i PoolProvision
|
|
if err := rows.Scan(
|
|
&i.ProvisionID,
|
|
&i.PoolID,
|
|
&i.BillingAccountID,
|
|
&i.SubscriptionID,
|
|
&i.PurchaseID,
|
|
&i.GrantID,
|
|
&i.Quantity,
|
|
&i.Status,
|
|
&i.ActivatedAt,
|
|
&i.SuspendedAt,
|
|
&i.EndedAt,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.EntitlementSetID,
|
|
&i.ProductID,
|
|
); 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 getLivePoolProvisionsBySubscriptionID = `-- name: GetLivePoolProvisionsBySubscriptionID :many
|
|
SELECT provision_id, pool_id, billing_account_id, subscription_id, purchase_id, grant_id, quantity, status, activated_at, suspended_at, ended_at, created_at, updated_at, entitlement_set_id, product_id FROM core.pool_provisions
|
|
WHERE subscription_id = $1 AND status <> 'ended'
|
|
ORDER BY created_at ASC
|
|
`
|
|
|
|
// Live (non-ended) provisions of a subscription, one per product. Reconcile
|
|
// diffs these against the subscription's desired-by-product line items.
|
|
func (q *Queries) GetLivePoolProvisionsBySubscriptionID(ctx context.Context, subscriptionID uuid.NullUUID) ([]PoolProvision, error) {
|
|
rows, err := q.db.QueryContext(ctx, getLivePoolProvisionsBySubscriptionID, subscriptionID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []PoolProvision{}
|
|
for rows.Next() {
|
|
var i PoolProvision
|
|
if err := rows.Scan(
|
|
&i.ProvisionID,
|
|
&i.PoolID,
|
|
&i.BillingAccountID,
|
|
&i.SubscriptionID,
|
|
&i.PurchaseID,
|
|
&i.GrantID,
|
|
&i.Quantity,
|
|
&i.Status,
|
|
&i.ActivatedAt,
|
|
&i.SuspendedAt,
|
|
&i.EndedAt,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.EntitlementSetID,
|
|
&i.ProductID,
|
|
); 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 getPoolProvisionByGrantID = `-- name: GetPoolProvisionByGrantID :one
|
|
SELECT provision_id, pool_id, billing_account_id, subscription_id, purchase_id, grant_id, quantity, status, activated_at, suspended_at, ended_at, created_at, updated_at, entitlement_set_id, product_id FROM core.pool_provisions
|
|
WHERE grant_id = $1
|
|
`
|
|
|
|
func (q *Queries) GetPoolProvisionByGrantID(ctx context.Context, grantID uuid.NullUUID) (PoolProvision, error) {
|
|
row := q.db.QueryRowContext(ctx, getPoolProvisionByGrantID, grantID)
|
|
var i PoolProvision
|
|
err := row.Scan(
|
|
&i.ProvisionID,
|
|
&i.PoolID,
|
|
&i.BillingAccountID,
|
|
&i.SubscriptionID,
|
|
&i.PurchaseID,
|
|
&i.GrantID,
|
|
&i.Quantity,
|
|
&i.Status,
|
|
&i.ActivatedAt,
|
|
&i.SuspendedAt,
|
|
&i.EndedAt,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.EntitlementSetID,
|
|
&i.ProductID,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getPoolProvisionByProvisionID = `-- name: GetPoolProvisionByProvisionID :one
|
|
SELECT provision_id, pool_id, billing_account_id, subscription_id, purchase_id, grant_id, quantity, status, activated_at, suspended_at, ended_at, created_at, updated_at, entitlement_set_id, product_id FROM core.pool_provisions
|
|
WHERE provision_id = $1
|
|
`
|
|
|
|
func (q *Queries) GetPoolProvisionByProvisionID(ctx context.Context, provisionID string) (PoolProvision, error) {
|
|
row := q.db.QueryRowContext(ctx, getPoolProvisionByProvisionID, provisionID)
|
|
var i PoolProvision
|
|
err := row.Scan(
|
|
&i.ProvisionID,
|
|
&i.PoolID,
|
|
&i.BillingAccountID,
|
|
&i.SubscriptionID,
|
|
&i.PurchaseID,
|
|
&i.GrantID,
|
|
&i.Quantity,
|
|
&i.Status,
|
|
&i.ActivatedAt,
|
|
&i.SuspendedAt,
|
|
&i.EndedAt,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.EntitlementSetID,
|
|
&i.ProductID,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getPoolProvisionBySubscriptionID = `-- name: GetPoolProvisionBySubscriptionID :one
|
|
SELECT provision_id, pool_id, billing_account_id, subscription_id, purchase_id, grant_id, quantity, status, activated_at, suspended_at, ended_at, created_at, updated_at, entitlement_set_id, product_id FROM core.pool_provisions
|
|
WHERE subscription_id = $1
|
|
`
|
|
|
|
func (q *Queries) GetPoolProvisionBySubscriptionID(ctx context.Context, subscriptionID uuid.NullUUID) (PoolProvision, error) {
|
|
row := q.db.QueryRowContext(ctx, getPoolProvisionBySubscriptionID, subscriptionID)
|
|
var i PoolProvision
|
|
err := row.Scan(
|
|
&i.ProvisionID,
|
|
&i.PoolID,
|
|
&i.BillingAccountID,
|
|
&i.SubscriptionID,
|
|
&i.PurchaseID,
|
|
&i.GrantID,
|
|
&i.Quantity,
|
|
&i.Status,
|
|
&i.ActivatedAt,
|
|
&i.SuspendedAt,
|
|
&i.EndedAt,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.EntitlementSetID,
|
|
&i.ProductID,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getPoolProvisionsByPoolID = `-- name: GetPoolProvisionsByPoolID :many
|
|
|
|
SELECT provision_id, pool_id, billing_account_id, subscription_id, purchase_id, grant_id, quantity, status, activated_at, suspended_at, ended_at, created_at, updated_at, entitlement_set_id, product_id FROM core.pool_provisions
|
|
WHERE pool_id = $1
|
|
ORDER BY created_at ASC
|
|
`
|
|
|
|
// Writes to core.pool_provisions go through the conferral functions
|
|
// (queries/conferral.sql) alone; core_writer holds no direct DML on this
|
|
// table (migration 00005 enclosure). Only read paths live here.
|
|
func (q *Queries) GetPoolProvisionsByPoolID(ctx context.Context, poolID string) ([]PoolProvision, error) {
|
|
rows, err := q.db.QueryContext(ctx, getPoolProvisionsByPoolID, poolID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []PoolProvision{}
|
|
for rows.Next() {
|
|
var i PoolProvision
|
|
if err := rows.Scan(
|
|
&i.ProvisionID,
|
|
&i.PoolID,
|
|
&i.BillingAccountID,
|
|
&i.SubscriptionID,
|
|
&i.PurchaseID,
|
|
&i.GrantID,
|
|
&i.Quantity,
|
|
&i.Status,
|
|
&i.ActivatedAt,
|
|
&i.SuspendedAt,
|
|
&i.EndedAt,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
&i.EntitlementSetID,
|
|
&i.ProductID,
|
|
); 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 listPoolsCarryingSet = `-- name: ListPoolsCarryingSet :many
|
|
SELECT DISTINCT pp.pool_id, rp.org_id, o.name AS org_name
|
|
FROM core.pool_provisions pp
|
|
JOIN core.resource_pools rp ON rp.pool_id = pp.pool_id
|
|
JOIN core.organizations o ON o.org_id = rp.org_id
|
|
WHERE pp.entitlement_set_id = $1 AND pp.status = 'active'
|
|
ORDER BY pp.pool_id ASC
|
|
`
|
|
|
|
type ListPoolsCarryingSetRow struct {
|
|
PoolID string `json:"pool_id"`
|
|
OrgID string `json:"org_id"`
|
|
OrgName string `json:"org_name"`
|
|
}
|
|
|
|
// The carrying population of a set: pools with an active provision of it, one
|
|
// row per pool, ascending by pool_id, which is both the predicate and the lock
|
|
// order a commit takes them in (Decision 143).
|
|
func (q *Queries) ListPoolsCarryingSet(ctx context.Context, entitlementSetID string) ([]ListPoolsCarryingSetRow, error) {
|
|
rows, err := q.db.QueryContext(ctx, listPoolsCarryingSet, entitlementSetID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []ListPoolsCarryingSetRow{}
|
|
for rows.Next() {
|
|
var i ListPoolsCarryingSetRow
|
|
if err := rows.Scan(&i.PoolID, &i.OrgID, &i.OrgName); 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
|
|
}
|