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.
338 lines
11 KiB
Go
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
|
|
}
|