Files
member-console/internal/entitlements/queries/grants.sql
Christian Galo 7a7f5975eb Track grant lineage and add Extend transition
Introduce extends_grant_id on grants (models, CreateGrant param and
SQL), add
GetGrantLineage recursive query, and enforce same-org/immutability
guards via
migration triggers. Implement TransitionTarget.Extend with validation
and an
extend path that issues a chained grant + provision. Update docs, specs
and
tests accordingly.
2026-04-26 02:38:46 -05:00

47 lines
1.8 KiB
SQL

-- name: CreateGrant :one
INSERT INTO entitlements.grants (product_id, entitlement_set_id, granted_to_org_id, granted_by_person_id, grant_reason, description, quantity, valid_from, valid_until, extends_grant_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING *;
-- name: GetGrantByID :one
SELECT * FROM entitlements.grants
WHERE grant_id = $1;
-- name: ListGrantsByOrgID :many
SELECT * FROM entitlements.grants
WHERE granted_to_org_id = $1
ORDER BY created_at DESC;
-- name: ListAllGrants :many
SELECT * FROM entitlements.grants
ORDER BY created_at DESC;
-- name: RevokeGrant :one
UPDATE entitlements.grants
SET status = 'revoked', revoked_at = NOW(), revoked_by_person_id = $2, revocation_reason = $3
WHERE grant_id = $1 AND status = 'active'
RETURNING *;
-- name: GetGrantLineage :many
-- Walks the ancestry chain of the focal grant via extends_grant_id, returning
-- the focal grant first followed by each ancestor (parent, grandparent, ...)
-- in chain-walk order. Revoked or expired ancestors are included; lineage is
-- about who-came-before, not current validity.
WITH RECURSIVE lineage AS (
SELECT g.*, 0 AS depth FROM entitlements.grants g
WHERE g.grant_id = $1
UNION ALL
SELECT g.*, l.depth + 1 FROM entitlements.grants g
JOIN lineage l ON g.grant_id = l.extends_grant_id
)
SELECT lineage.grant_id, lineage.product_id, lineage.entitlement_set_id,
lineage.granted_to_billing_account_id, lineage.granted_to_org_id,
lineage.granted_to_person_id, lineage.granted_by_person_id,
lineage.grant_reason, lineage.description, lineage.quantity,
lineage.valid_from, lineage.valid_until, lineage.status,
lineage.revoked_at, lineage.revoked_by_person_id,
lineage.revocation_reason, lineage.metadata, lineage.created_at,
lineage.updated_at, lineage.extends_grant_id
FROM lineage
ORDER BY lineage.depth ASC;