Files
member-console/internal/billing/products.sql.go
T
cgalo5758 dd3962990b Adopt entity keys and add invoice numbers
Replace the entity slugs on organizations, workspaces, resource pools,
and
plan ladders with nullable `key` columns and add keys to products,
prices,
and entitlement sets. Rename `providers.slug` to `provider` and add
partial
unique indexes for system and org role names.

Assign invoice numbers per billing account from a gapless transactional
counter; Stripe's number moves to the invoice mapping as an external
reference.

Seeds, fixtures, and the operator lookup address rows by key, and the
returning-login resync no longer blanks a display name when the IdP
sends
no `name` claim.
2026-08-29 20:12:04 -05:00

482 lines
14 KiB
Go

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.29.0
// source: products.sql
package billing
import (
"context"
"database/sql"
"github.com/google/uuid"
"github.com/sqlc-dev/pqtype"
)
const anyProduct = `-- name: AnyProduct :one
SELECT EXISTS(SELECT 1 FROM core.products)
`
// Setup-checklist existence probe.
func (q *Queries) AnyProduct(ctx context.Context) (bool, error) {
row := q.db.QueryRowContext(ctx, anyProduct)
var exists bool
err := row.Scan(&exists)
return exists, err
}
const anyPublishedProduct = `-- name: AnyPublishedProduct :one
SELECT EXISTS(SELECT 1 FROM core.products WHERE lifecycle_status = 'published')
`
// Setup-checklist existence probe.
func (q *Queries) AnyPublishedProduct(ctx context.Context) (bool, error) {
row := q.db.QueryRowContext(ctx, anyPublishedProduct)
var exists bool
err := row.Scan(&exists)
return exists, err
}
const countPublishedProducts = `-- name: CountPublishedProducts :one
SELECT COUNT(*) FROM core.products
WHERE lifecycle_status = 'published'
`
// Operator overview tile: the size of the live catalog. Counts only
// lifecycle_status='published' — drafts are work in progress and retired
// products are history, so neither belongs in a "what we sell today" number.
func (q *Queries) CountPublishedProducts(ctx context.Context) (int64, error) {
row := q.db.QueryRowContext(ctx, countPublishedProducts)
var count int64
err := row.Scan(&count)
return count, err
}
const countPublishedTierProducts = `-- name: CountPublishedTierProducts :one
SELECT COUNT(DISTINCT t.product_id) FROM core.plan_ladder_tiers t
JOIN core.products p ON p.product_id = t.product_id
WHERE p.lifecycle_status = 'published'
`
// Operator catalog overview (ux-ia-naming 2.1): how many published products
// are a tier on some plan ladder, vs. off-ladder. A product counts once even
// when it is shared across more than one ladder (DISTINCT).
func (q *Queries) CountPublishedTierProducts(ctx context.Context) (int64, error) {
row := q.db.QueryRowContext(ctx, countPublishedTierProducts)
var count int64
err := row.Scan(&count)
return count, err
}
const createProduct = `-- name: CreateProduct :one
INSERT INTO core.products (name, description, display_category, is_active, is_public, entitlement_set_id, lifecycle_status, key)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING product_id, name, description, display_category, metadata, is_active, is_public, created_at, updated_at, entitlement_set_id, lifecycle_status, key
`
type CreateProductParams struct {
Name string `json:"name"`
Description sql.NullString `json:"description"`
DisplayCategory sql.NullString `json:"display_category"`
IsActive bool `json:"is_active"`
IsPublic bool `json:"is_public"`
EntitlementSetID uuid.NullUUID `json:"entitlement_set_id"`
LifecycleStatus string `json:"lifecycle_status"`
Key sql.NullString `json:"key"`
}
// `key` is the optional declarative address (entity-keys §3), root-scoped.
// Product names deliberately carry no uniqueness constraint (two ladders may
// each have a "Pro"), which is exactly why a caller outside the database
// needs a key to name one row. The operator create form does not collect
// one, so a UI-created product leaves it NULL.
func (q *Queries) CreateProduct(ctx context.Context, arg CreateProductParams) (Product, error) {
row := q.db.QueryRowContext(ctx, createProduct,
arg.Name,
arg.Description,
arg.DisplayCategory,
arg.IsActive,
arg.IsPublic,
arg.EntitlementSetID,
arg.LifecycleStatus,
arg.Key,
)
var i Product
err := row.Scan(
&i.ProductID,
&i.Name,
&i.Description,
&i.DisplayCategory,
&i.Metadata,
&i.IsActive,
&i.IsPublic,
&i.CreatedAt,
&i.UpdatedAt,
&i.EntitlementSetID,
&i.LifecycleStatus,
&i.Key,
)
return i, err
}
const getProductByID = `-- name: GetProductByID :one
SELECT product_id, name, description, display_category, metadata, is_active, is_public, created_at, updated_at, entitlement_set_id, lifecycle_status, key FROM core.products
WHERE product_id = $1
`
func (q *Queries) GetProductByID(ctx context.Context, productID string) (Product, error) {
row := q.db.QueryRowContext(ctx, getProductByID, productID)
var i Product
err := row.Scan(
&i.ProductID,
&i.Name,
&i.Description,
&i.DisplayCategory,
&i.Metadata,
&i.IsActive,
&i.IsPublic,
&i.CreatedAt,
&i.UpdatedAt,
&i.EntitlementSetID,
&i.LifecycleStatus,
&i.Key,
)
return i, err
}
const getProductByKey = `-- name: GetProductByKey :one
SELECT product_id, name, description, display_category, metadata, is_active, is_public, created_at, updated_at, entitlement_set_id, lifecycle_status, key FROM core.products
WHERE key = $1
`
// Root key resolver (entity-keys §5). uq_products_key guarantees at most one
// row matches -- unlike GetProductByName, whose column has no unique
// constraint at all.
func (q *Queries) GetProductByKey(ctx context.Context, key sql.NullString) (Product, error) {
row := q.db.QueryRowContext(ctx, getProductByKey, key)
var i Product
err := row.Scan(
&i.ProductID,
&i.Name,
&i.Description,
&i.DisplayCategory,
&i.Metadata,
&i.IsActive,
&i.IsPublic,
&i.CreatedAt,
&i.UpdatedAt,
&i.EntitlementSetID,
&i.LifecycleStatus,
&i.Key,
)
return i, err
}
const getProductShape = `-- name: GetProductShape :one
SELECT product_id, lifecycle_status, is_public, set_present, ladder_count, billing_shape, consumption_shape FROM core.product_shape
WHERE product_id = $1
`
// Diagnostics view (migration 00006): independent structural dimensions per
// product. Readiness reads set_present and billing_shape.
func (q *Queries) GetProductShape(ctx context.Context, productID string) (CoreProductShape, error) {
row := q.db.QueryRowContext(ctx, getProductShape, productID)
var i CoreProductShape
err := row.Scan(
&i.ProductID,
&i.LifecycleStatus,
&i.IsPublic,
&i.SetPresent,
&i.LadderCount,
&i.BillingShape,
&i.ConsumptionShape,
)
return i, err
}
const listActiveProducts = `-- name: ListActiveProducts :many
SELECT product_id, name, description, display_category, metadata, is_active, is_public, created_at, updated_at, entitlement_set_id, lifecycle_status, key FROM core.products
WHERE is_active = TRUE
ORDER BY name ASC
`
func (q *Queries) ListActiveProducts(ctx context.Context) ([]Product, error) {
rows, err := q.db.QueryContext(ctx, listActiveProducts)
if err != nil {
return nil, err
}
defer rows.Close()
items := []Product{}
for rows.Next() {
var i Product
if err := rows.Scan(
&i.ProductID,
&i.Name,
&i.Description,
&i.DisplayCategory,
&i.Metadata,
&i.IsActive,
&i.IsPublic,
&i.CreatedAt,
&i.UpdatedAt,
&i.EntitlementSetID,
&i.LifecycleStatus,
&i.Key,
); 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 listAllProducts = `-- name: ListAllProducts :many
SELECT product_id, name, description, display_category, metadata, is_active, is_public, created_at, updated_at, entitlement_set_id, lifecycle_status, key FROM core.products
ORDER BY name ASC
`
func (q *Queries) ListAllProducts(ctx context.Context) ([]Product, error) {
rows, err := q.db.QueryContext(ctx, listAllProducts)
if err != nil {
return nil, err
}
defer rows.Close()
items := []Product{}
for rows.Next() {
var i Product
if err := rows.Scan(
&i.ProductID,
&i.Name,
&i.Description,
&i.DisplayCategory,
&i.Metadata,
&i.IsActive,
&i.IsPublic,
&i.CreatedAt,
&i.UpdatedAt,
&i.EntitlementSetID,
&i.LifecycleStatus,
&i.Key,
); 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 listProductsByNameCI = `-- name: ListProductsByNameCI :many
SELECT
p.product_id,
p.name,
p.is_active,
l.plan_ladder_id AS ladder_id,
l.name AS ladder_name
FROM core.products p
LEFT JOIN core.plan_ladder_tiers t ON t.product_id = p.product_id
LEFT JOIN core.plan_ladders l ON l.plan_ladder_id = t.plan_ladder_id
WHERE lower(p.name) = lower($1::text)
AND ($2::uuid IS NULL OR p.product_id <> $2::uuid)
ORDER BY p.name ASC, l.name ASC
`
type ListProductsByNameCIParams struct {
Name string `json:"name"`
ExcludeProductID uuid.NullUUID `json:"exclude_product_id"`
}
type ListProductsByNameCIRow struct {
ProductID string `json:"product_id"`
Name string `json:"name"`
IsActive bool `json:"is_active"`
LadderID uuid.NullUUID `json:"ladder_id"`
LadderName sql.NullString `json:"ladder_name"`
}
// Product duplicate-name warning (entity-keys): products may
// legitimately share a name (a "Pro" tier on two ladders), so
// core.products.name carries no uniqueness constraint -- this powers a live,
// non-blocking warning on the create/edit forms instead of a 422. Matches
// case-insensitively; when exclude_product_id is set (the edit form's own
// product), that product is excluded from its own duplicate check. LEFT
// JOINs the ladder tables so a matching product that is on no ladder still
// returns one row (ladder columns NULL); the caller groups rows by
// product_id in Go and collects each product's ladder names.
func (q *Queries) ListProductsByNameCI(ctx context.Context, arg ListProductsByNameCIParams) ([]ListProductsByNameCIRow, error) {
rows, err := q.db.QueryContext(ctx, listProductsByNameCI, arg.Name, arg.ExcludeProductID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListProductsByNameCIRow{}
for rows.Next() {
var i ListProductsByNameCIRow
if err := rows.Scan(
&i.ProductID,
&i.Name,
&i.IsActive,
&i.LadderID,
&i.LadderName,
); 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 listPublicPlanProducts = `-- name: ListPublicPlanProducts :many
SELECT p.product_id, p.name, p.description, p.display_category, p.metadata, p.is_active, p.is_public, p.created_at, p.updated_at, p.entitlement_set_id, p.lifecycle_status, p.key FROM core.products p
WHERE p.is_active = TRUE AND p.is_public = TRUE AND p.lifecycle_status = 'published'
AND EXISTS (
SELECT 1 FROM core.plan_ladder_tiers t WHERE t.product_id = p.product_id
)
ORDER BY p.name ASC
`
// Plan products are those attached to a ladder via plan_ladder_tiers
// (Doc 31 Amendment #3); membership is the structural signal —
// display_category is presentation-only and never branched on.
func (q *Queries) ListPublicPlanProducts(ctx context.Context) ([]Product, error) {
rows, err := q.db.QueryContext(ctx, listPublicPlanProducts)
if err != nil {
return nil, err
}
defer rows.Close()
items := []Product{}
for rows.Next() {
var i Product
if err := rows.Scan(
&i.ProductID,
&i.Name,
&i.Description,
&i.DisplayCategory,
&i.Metadata,
&i.IsActive,
&i.IsPublic,
&i.CreatedAt,
&i.UpdatedAt,
&i.EntitlementSetID,
&i.LifecycleStatus,
&i.Key,
); 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 listPublicProducts = `-- name: ListPublicProducts :many
SELECT product_id, name, description, display_category, metadata, is_active, is_public, created_at, updated_at, entitlement_set_id, lifecycle_status, key FROM core.products
WHERE is_active = TRUE AND is_public = TRUE AND lifecycle_status = 'published'
ORDER BY name ASC
`
func (q *Queries) ListPublicProducts(ctx context.Context) ([]Product, error) {
rows, err := q.db.QueryContext(ctx, listPublicProducts)
if err != nil {
return nil, err
}
defer rows.Close()
items := []Product{}
for rows.Next() {
var i Product
if err := rows.Scan(
&i.ProductID,
&i.Name,
&i.Description,
&i.DisplayCategory,
&i.Metadata,
&i.IsActive,
&i.IsPublic,
&i.CreatedAt,
&i.UpdatedAt,
&i.EntitlementSetID,
&i.LifecycleStatus,
&i.Key,
); 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 updateProduct = `-- name: UpdateProduct :one
UPDATE core.products
SET name = $2, description = $3, display_category = $4, is_active = $5, is_public = $6, entitlement_set_id = $7, metadata = $8
WHERE product_id = $1
RETURNING product_id, name, description, display_category, metadata, is_active, is_public, created_at, updated_at, entitlement_set_id, lifecycle_status, key
`
type UpdateProductParams struct {
ProductID string `json:"product_id"`
Name string `json:"name"`
Description sql.NullString `json:"description"`
DisplayCategory sql.NullString `json:"display_category"`
IsActive bool `json:"is_active"`
IsPublic bool `json:"is_public"`
EntitlementSetID uuid.NullUUID `json:"entitlement_set_id"`
Metadata pqtype.NullRawMessage `json:"metadata"`
}
func (q *Queries) UpdateProduct(ctx context.Context, arg UpdateProductParams) (Product, error) {
row := q.db.QueryRowContext(ctx, updateProduct,
arg.ProductID,
arg.Name,
arg.Description,
arg.DisplayCategory,
arg.IsActive,
arg.IsPublic,
arg.EntitlementSetID,
arg.Metadata,
)
var i Product
err := row.Scan(
&i.ProductID,
&i.Name,
&i.Description,
&i.DisplayCategory,
&i.Metadata,
&i.IsActive,
&i.IsPublic,
&i.CreatedAt,
&i.UpdatedAt,
&i.EntitlementSetID,
&i.LifecycleStatus,
&i.Key,
)
return i, err
}