Files
member-console/internal/entitlements/grants.sql.go
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

338 lines
11 KiB
Go

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.29.0
// source: grants.sql
package entitlements
import (
"context"
"database/sql"
"time"
"github.com/google/uuid"
"github.com/sqlc-dev/pqtype"
)
const createGrant = `-- 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 grant_id, product_id, granted_to_billing_account_id, granted_to_org_id, granted_to_person_id, granted_by_person_id, grant_reason, description, quantity, valid_from, valid_until, status, revoked_at, revoked_by_person_id, revocation_reason, metadata, created_at, updated_at, entitlement_set_id, extends_grant_id
`
type CreateGrantParams struct {
ProductID uuid.NullUUID `json:"product_id"`
EntitlementSetID uuid.NullUUID `json:"entitlement_set_id"`
GrantedToOrgID uuid.NullUUID `json:"granted_to_org_id"`
GrantedByPersonID uuid.NullUUID `json:"granted_by_person_id"`
GrantReason string `json:"grant_reason"`
Description sql.NullString `json:"description"`
Quantity int32 `json:"quantity"`
ValidFrom time.Time `json:"valid_from"`
ValidUntil sql.NullTime `json:"valid_until"`
ExtendsGrantID uuid.NullUUID `json:"extends_grant_id"`
}
func (q *Queries) CreateGrant(ctx context.Context, arg CreateGrantParams) (Grant, error) {
row := q.db.QueryRowContext(ctx, createGrant,
arg.ProductID,
arg.EntitlementSetID,
arg.GrantedToOrgID,
arg.GrantedByPersonID,
arg.GrantReason,
arg.Description,
arg.Quantity,
arg.ValidFrom,
arg.ValidUntil,
arg.ExtendsGrantID,
)
var i Grant
err := row.Scan(
&i.GrantID,
&i.ProductID,
&i.GrantedToBillingAccountID,
&i.GrantedToOrgID,
&i.GrantedToPersonID,
&i.GrantedByPersonID,
&i.GrantReason,
&i.Description,
&i.Quantity,
&i.ValidFrom,
&i.ValidUntil,
&i.Status,
&i.RevokedAt,
&i.RevokedByPersonID,
&i.RevocationReason,
&i.Metadata,
&i.CreatedAt,
&i.UpdatedAt,
&i.EntitlementSetID,
&i.ExtendsGrantID,
)
return i, err
}
const getGrantByID = `-- name: GetGrantByID :one
SELECT grant_id, product_id, granted_to_billing_account_id, granted_to_org_id, granted_to_person_id, granted_by_person_id, grant_reason, description, quantity, valid_from, valid_until, status, revoked_at, revoked_by_person_id, revocation_reason, metadata, created_at, updated_at, entitlement_set_id, extends_grant_id FROM entitlements.grants
WHERE grant_id = $1
`
func (q *Queries) GetGrantByID(ctx context.Context, grantID string) (Grant, error) {
row := q.db.QueryRowContext(ctx, getGrantByID, grantID)
var i Grant
err := row.Scan(
&i.GrantID,
&i.ProductID,
&i.GrantedToBillingAccountID,
&i.GrantedToOrgID,
&i.GrantedToPersonID,
&i.GrantedByPersonID,
&i.GrantReason,
&i.Description,
&i.Quantity,
&i.ValidFrom,
&i.ValidUntil,
&i.Status,
&i.RevokedAt,
&i.RevokedByPersonID,
&i.RevocationReason,
&i.Metadata,
&i.CreatedAt,
&i.UpdatedAt,
&i.EntitlementSetID,
&i.ExtendsGrantID,
)
return i, err
}
const getGrantLineage = `-- name: GetGrantLineage :many
WITH RECURSIVE lineage AS (
SELECT g.grant_id, g.product_id, g.granted_to_billing_account_id, g.granted_to_org_id, g.granted_to_person_id, g.granted_by_person_id, g.grant_reason, g.description, g.quantity, g.valid_from, g.valid_until, g.status, g.revoked_at, g.revoked_by_person_id, g.revocation_reason, g.metadata, g.created_at, g.updated_at, g.entitlement_set_id, g.extends_grant_id, 0 AS depth FROM entitlements.grants g
WHERE g.grant_id = $1
UNION ALL
SELECT g.grant_id, g.product_id, g.granted_to_billing_account_id, g.granted_to_org_id, g.granted_to_person_id, g.granted_by_person_id, g.grant_reason, g.description, g.quantity, g.valid_from, g.valid_until, g.status, g.revoked_at, g.revoked_by_person_id, g.revocation_reason, g.metadata, g.created_at, g.updated_at, g.entitlement_set_id, g.extends_grant_id, 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
`
type GetGrantLineageRow struct {
GrantID string `json:"grant_id"`
ProductID uuid.NullUUID `json:"product_id"`
EntitlementSetID uuid.NullUUID `json:"entitlement_set_id"`
GrantedToBillingAccountID uuid.NullUUID `json:"granted_to_billing_account_id"`
GrantedToOrgID uuid.NullUUID `json:"granted_to_org_id"`
GrantedToPersonID uuid.NullUUID `json:"granted_to_person_id"`
GrantedByPersonID uuid.NullUUID `json:"granted_by_person_id"`
GrantReason string `json:"grant_reason"`
Description sql.NullString `json:"description"`
Quantity int32 `json:"quantity"`
ValidFrom time.Time `json:"valid_from"`
ValidUntil sql.NullTime `json:"valid_until"`
Status string `json:"status"`
RevokedAt sql.NullTime `json:"revoked_at"`
RevokedByPersonID uuid.NullUUID `json:"revoked_by_person_id"`
RevocationReason sql.NullString `json:"revocation_reason"`
Metadata pqtype.NullRawMessage `json:"metadata"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ExtendsGrantID uuid.NullUUID `json:"extends_grant_id"`
}
// 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.
func (q *Queries) GetGrantLineage(ctx context.Context, grantID string) ([]GetGrantLineageRow, error) {
rows, err := q.db.QueryContext(ctx, getGrantLineage, grantID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetGrantLineageRow{}
for rows.Next() {
var i GetGrantLineageRow
if err := rows.Scan(
&i.GrantID,
&i.ProductID,
&i.EntitlementSetID,
&i.GrantedToBillingAccountID,
&i.GrantedToOrgID,
&i.GrantedToPersonID,
&i.GrantedByPersonID,
&i.GrantReason,
&i.Description,
&i.Quantity,
&i.ValidFrom,
&i.ValidUntil,
&i.Status,
&i.RevokedAt,
&i.RevokedByPersonID,
&i.RevocationReason,
&i.Metadata,
&i.CreatedAt,
&i.UpdatedAt,
&i.ExtendsGrantID,
); 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 listAllGrants = `-- name: ListAllGrants :many
SELECT grant_id, product_id, granted_to_billing_account_id, granted_to_org_id, granted_to_person_id, granted_by_person_id, grant_reason, description, quantity, valid_from, valid_until, status, revoked_at, revoked_by_person_id, revocation_reason, metadata, created_at, updated_at, entitlement_set_id, extends_grant_id FROM entitlements.grants
ORDER BY created_at DESC
`
func (q *Queries) ListAllGrants(ctx context.Context) ([]Grant, error) {
rows, err := q.db.QueryContext(ctx, listAllGrants)
if err != nil {
return nil, err
}
defer rows.Close()
items := []Grant{}
for rows.Next() {
var i Grant
if err := rows.Scan(
&i.GrantID,
&i.ProductID,
&i.GrantedToBillingAccountID,
&i.GrantedToOrgID,
&i.GrantedToPersonID,
&i.GrantedByPersonID,
&i.GrantReason,
&i.Description,
&i.Quantity,
&i.ValidFrom,
&i.ValidUntil,
&i.Status,
&i.RevokedAt,
&i.RevokedByPersonID,
&i.RevocationReason,
&i.Metadata,
&i.CreatedAt,
&i.UpdatedAt,
&i.EntitlementSetID,
&i.ExtendsGrantID,
); 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 listGrantsByOrgID = `-- name: ListGrantsByOrgID :many
SELECT grant_id, product_id, granted_to_billing_account_id, granted_to_org_id, granted_to_person_id, granted_by_person_id, grant_reason, description, quantity, valid_from, valid_until, status, revoked_at, revoked_by_person_id, revocation_reason, metadata, created_at, updated_at, entitlement_set_id, extends_grant_id FROM entitlements.grants
WHERE granted_to_org_id = $1
ORDER BY created_at DESC
`
func (q *Queries) ListGrantsByOrgID(ctx context.Context, grantedToOrgID uuid.NullUUID) ([]Grant, error) {
rows, err := q.db.QueryContext(ctx, listGrantsByOrgID, grantedToOrgID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []Grant{}
for rows.Next() {
var i Grant
if err := rows.Scan(
&i.GrantID,
&i.ProductID,
&i.GrantedToBillingAccountID,
&i.GrantedToOrgID,
&i.GrantedToPersonID,
&i.GrantedByPersonID,
&i.GrantReason,
&i.Description,
&i.Quantity,
&i.ValidFrom,
&i.ValidUntil,
&i.Status,
&i.RevokedAt,
&i.RevokedByPersonID,
&i.RevocationReason,
&i.Metadata,
&i.CreatedAt,
&i.UpdatedAt,
&i.EntitlementSetID,
&i.ExtendsGrantID,
); 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 revokeGrant = `-- 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 grant_id, product_id, granted_to_billing_account_id, granted_to_org_id, granted_to_person_id, granted_by_person_id, grant_reason, description, quantity, valid_from, valid_until, status, revoked_at, revoked_by_person_id, revocation_reason, metadata, created_at, updated_at, entitlement_set_id, extends_grant_id
`
type RevokeGrantParams struct {
GrantID string `json:"grant_id"`
RevokedByPersonID uuid.NullUUID `json:"revoked_by_person_id"`
RevocationReason sql.NullString `json:"revocation_reason"`
}
func (q *Queries) RevokeGrant(ctx context.Context, arg RevokeGrantParams) (Grant, error) {
row := q.db.QueryRowContext(ctx, revokeGrant, arg.GrantID, arg.RevokedByPersonID, arg.RevocationReason)
var i Grant
err := row.Scan(
&i.GrantID,
&i.ProductID,
&i.GrantedToBillingAccountID,
&i.GrantedToOrgID,
&i.GrantedToPersonID,
&i.GrantedByPersonID,
&i.GrantReason,
&i.Description,
&i.Quantity,
&i.ValidFrom,
&i.ValidUntil,
&i.Status,
&i.RevokedAt,
&i.RevokedByPersonID,
&i.RevocationReason,
&i.Metadata,
&i.CreatedAt,
&i.UpdatedAt,
&i.EntitlementSetID,
&i.ExtendsGrantID,
)
return i, err
}