feat(kol): marketplace and admin subscription repo queries

This commit is contained in:
2026-04-17 14:23:25 +08:00
parent 6eb663bd6e
commit df334c1e26
7 changed files with 96 additions and 32 deletions
@@ -15,7 +15,12 @@ const getPublishedKolPackage = `-- name: GetPublishedKolPackage :one
SELECT kp.id, kp.tenant_id, kp.kol_profile_id, kp.name, kp.description,
kp.cover_url, kp.industry, kp.tags, kp.price_note, kp.status,
kp.created_at, kp.updated_at,
pf.display_name AS kol_display_name, pf.avatar_url AS kol_avatar_url, pf.bio AS kol_bio
pf.display_name AS kol_display_name, pf.avatar_url AS kol_avatar_url, pf.bio AS kol_bio,
(SELECT COUNT(*) FROM kol_prompts p
WHERE p.package_id = kp.id AND p.status = 'active' AND p.deleted_at IS NULL) AS prompt_count,
(SELECT COUNT(*) FROM kol_subscriptions s
WHERE s.package_id = kp.id AND s.status = 'active'
AND (s.end_at IS NULL OR s.end_at > NOW())) AS subscriber_count
FROM kol_packages kp
JOIN kol_profiles pf ON pf.id = kp.kol_profile_id
AND pf.status = 'active'
@@ -27,21 +32,23 @@ WHERE kp.id = $1
`
type GetPublishedKolPackageRow struct {
ID int64 `json:"id"`
TenantID int64 `json:"tenant_id"`
KolProfileID int64 `json:"kol_profile_id"`
Name string `json:"name"`
Description pgtype.Text `json:"description"`
CoverUrl pgtype.Text `json:"cover_url"`
Industry pgtype.Text `json:"industry"`
Tags []byte `json:"tags"`
PriceNote pgtype.Text `json:"price_note"`
Status string `json:"status"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
KolDisplayName string `json:"kol_display_name"`
KolAvatarUrl pgtype.Text `json:"kol_avatar_url"`
KolBio pgtype.Text `json:"kol_bio"`
ID int64 `json:"id"`
TenantID int64 `json:"tenant_id"`
KolProfileID int64 `json:"kol_profile_id"`
Name string `json:"name"`
Description pgtype.Text `json:"description"`
CoverUrl pgtype.Text `json:"cover_url"`
Industry pgtype.Text `json:"industry"`
Tags []byte `json:"tags"`
PriceNote pgtype.Text `json:"price_note"`
Status string `json:"status"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
KolDisplayName string `json:"kol_display_name"`
KolAvatarUrl pgtype.Text `json:"kol_avatar_url"`
KolBio pgtype.Text `json:"kol_bio"`
PromptCount int64 `json:"prompt_count"`
SubscriberCount int64 `json:"subscriber_count"`
}
func (q *Queries) GetPublishedKolPackage(ctx context.Context, id int64) (GetPublishedKolPackageRow, error) {
@@ -63,6 +70,8 @@ func (q *Queries) GetPublishedKolPackage(ctx context.Context, id int64) (GetPubl
&i.KolDisplayName,
&i.KolAvatarUrl,
&i.KolBio,
&i.PromptCount,
&i.SubscriberCount,
)
return i, err
}
@@ -151,6 +151,31 @@ func (q *Queries) GetKolSubscriptionByID(ctx context.Context, arg GetKolSubscrip
return i, err
}
const getKolSubscriptionByIDAny = `-- name: GetKolSubscriptionByIDAny :one
SELECT id, tenant_id, package_id, status, approved_by, start_at, end_at, created_at, updated_at
FROM kol_subscriptions
WHERE id = $1
`
// Cross-tenant read: V1 tenant-admin endpoints temporarily manage subscriptions here
// until a dedicated platform-api exists.
func (q *Queries) GetKolSubscriptionByIDAny(ctx context.Context, id int64) (KolSubscription, error) {
row := q.db.QueryRow(ctx, getKolSubscriptionByIDAny, id)
var i KolSubscription
err := row.Scan(
&i.ID,
&i.TenantID,
&i.PackageID,
&i.Status,
&i.ApprovedBy,
&i.StartAt,
&i.EndAt,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const getSubscriptionPromptByID = `-- name: GetSubscriptionPromptByID :one
SELECT sp.id, sp.tenant_id, sp.subscription_id, sp.package_id, sp.prompt_id,
sp.status, sp.granted_at, sp.revoked_at,
@@ -62,6 +62,9 @@ type Querier interface {
GetKolPromptByID(ctx context.Context, arg GetKolPromptByIDParams) (GetKolPromptByIDRow, error)
GetKolPromptRevision(ctx context.Context, arg GetKolPromptRevisionParams) (GetKolPromptRevisionRow, error)
GetKolSubscriptionByID(ctx context.Context, arg GetKolSubscriptionByIDParams) (KolSubscription, error)
// Cross-tenant read: V1 tenant-admin endpoints temporarily manage subscriptions here
// until a dedicated platform-api exists.
GetKolSubscriptionByIDAny(ctx context.Context, id int64) (KolSubscription, error)
GetKolUsageByGenerationTask(ctx context.Context, arg GetKolUsageByGenerationTaskParams) (GetKolUsageByGenerationTaskRow, error)
GetPromptRuleByID(ctx context.Context, arg GetPromptRuleByIDParams) (GetPromptRuleByIDRow, error)
GetPublishedKolPackage(ctx context.Context, id int64) (GetPublishedKolPackageRow, error)
@@ -107,21 +107,23 @@ func (r *kolMarketplaceRepository) GetPublished(ctx context.Context, id int64) (
return nil, err
}
return &PublishedKolPackage{
ID: row.ID,
TenantID: row.TenantID,
KolProfileID: row.KolProfileID,
Name: row.Name,
Description: nullableText(row.Description),
CoverURL: nullableText(row.CoverUrl),
Industry: nullableText(row.Industry),
Tags: row.Tags,
PriceNote: nullableText(row.PriceNote),
Status: row.Status,
CreatedAt: timeFromTimestamp(row.CreatedAt),
UpdatedAt: timeFromTimestamp(row.UpdatedAt),
KolDisplayName: row.KolDisplayName,
KolAvatarURL: nullableText(row.KolAvatarUrl),
KolBio: nullableText(row.KolBio),
ID: row.ID,
TenantID: row.TenantID,
KolProfileID: row.KolProfileID,
Name: row.Name,
Description: nullableText(row.Description),
CoverURL: nullableText(row.CoverUrl),
Industry: nullableText(row.Industry),
Tags: row.Tags,
PriceNote: nullableText(row.PriceNote),
Status: row.Status,
CreatedAt: timeFromTimestamp(row.CreatedAt),
UpdatedAt: timeFromTimestamp(row.UpdatedAt),
KolDisplayName: row.KolDisplayName,
KolAvatarURL: nullableText(row.KolAvatarUrl),
KolBio: nullableText(row.KolBio),
PromptCount: row.PromptCount,
SubscriberCount: row.SubscriberCount,
}, nil
}
@@ -54,6 +54,7 @@ type CreateAccessRowInput struct {
type KolSubscriptionRepository interface {
Create(ctx context.Context, tenantID, packageID int64) (*KolSubscription, error)
GetByID(ctx context.Context, tenantID, id int64) (*KolSubscription, error)
GetByIDAny(ctx context.Context, id int64) (*KolSubscription, error)
GetActiveForTenant(ctx context.Context, tenantID, packageID int64) (*KolSubscription, error)
ListByTenant(ctx context.Context, tenantID int64) ([]KolSubscription, error)
ListActiveSubscribersForPackage(ctx context.Context, packageID int64) ([]KolSubscription, error)
@@ -117,6 +118,18 @@ func (r *kolSubscriptionRepository) GetByID(ctx context.Context, tenantID, id in
return &sub, nil
}
func (r *kolSubscriptionRepository) GetByIDAny(ctx context.Context, id int64) (*KolSubscription, error) {
row, err := r.q.GetKolSubscriptionByIDAny(ctx, id)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return nil, nil
}
return nil, err
}
sub := mapKolSubscription(row)
return &sub, nil
}
func (r *kolSubscriptionRepository) GetActiveForTenant(ctx context.Context, tenantID, packageID int64) (*KolSubscription, error) {
row, err := r.q.GetActiveKolSubscription(ctx, generated.GetActiveKolSubscriptionParams{
TenantID: tenantID,
@@ -26,7 +26,12 @@ LIMIT sqlc.arg('limit') OFFSET sqlc.arg('offset');
SELECT kp.id, kp.tenant_id, kp.kol_profile_id, kp.name, kp.description,
kp.cover_url, kp.industry, kp.tags, kp.price_note, kp.status,
kp.created_at, kp.updated_at,
pf.display_name AS kol_display_name, pf.avatar_url AS kol_avatar_url, pf.bio AS kol_bio
pf.display_name AS kol_display_name, pf.avatar_url AS kol_avatar_url, pf.bio AS kol_bio,
(SELECT COUNT(*) FROM kol_prompts p
WHERE p.package_id = kp.id AND p.status = 'active' AND p.deleted_at IS NULL) AS prompt_count,
(SELECT COUNT(*) FROM kol_subscriptions s
WHERE s.package_id = kp.id AND s.status = 'active'
AND (s.end_at IS NULL OR s.end_at > NOW())) AS subscriber_count
FROM kol_packages kp
JOIN kol_profiles pf ON pf.id = kp.kol_profile_id
AND pf.status = 'active'
@@ -9,6 +9,13 @@ FROM kol_subscriptions
WHERE id = sqlc.arg(id)
AND tenant_id = sqlc.arg(tenant_id)::bigint;
-- name: GetKolSubscriptionByIDAny :one
-- Cross-tenant read: V1 tenant-admin endpoints temporarily manage subscriptions here
-- until a dedicated platform-api exists.
SELECT id, tenant_id, package_id, status, approved_by, start_at, end_at, created_at, updated_at
FROM kol_subscriptions
WHERE id = sqlc.arg(id);
-- name: GetActiveKolSubscription :one
SELECT id, tenant_id, package_id, status, approved_by, start_at, end_at, created_at, updated_at
FROM kol_subscriptions