Files

101 lines
3.8 KiB
Go
Raw Permalink Normal View History

2026-08-16 16:57:36 +02:00
package catalog
import (
"context"
"fmt"
"github.com/descrybe/descrybe-v2/apps/api/internal/billing"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgxpool"
)
// EnsureCategoryAttributeLinks removes orphan category_attributes rows (missing
// category or attribute) without wiping taxonomy or valid links. Returns orphans
// removed and remaining link count.
func EnsureCategoryAttributeLinks(ctx context.Context, pool *pgxpool.Pool, companyID uuid.UUID) (orphansRemoved int, links int, err error) {
if pool == nil {
return 0, 0, fmt.Errorf("nil pool")
}
ct, err := pool.Exec(ctx, `
DELETE FROM category_attributes ca
WHERE ca.company_id = $1
AND (
NOT EXISTS (
SELECT 1 FROM categories c
WHERE c.company_id = ca.company_id AND c.unique_id = ca.category_unique_id
)
OR NOT EXISTS (
SELECT 1 FROM attributes a
WHERE a.id = ca.attribute_id AND a.company_id = ca.company_id
)
)`, companyID)
if err != nil {
return 0, 0, fmt.Errorf("purge orphan category_attributes: %w", err)
}
orphansRemoved = int(ct.RowsAffected())
if err := pool.QueryRow(ctx, `
SELECT count(*)::int FROM category_attributes WHERE company_id = $1`, companyID).Scan(&links); err != nil {
return orphansRemoved, 0, err
}
return orphansRemoved, links, nil
}
// RepairCompanyCategoryEnhancePrompts is the company-scoped variant of
2026-08-17 00:39:25 +02:00
// RepairA1DemoCategoryEnhancePrompts: loads wp_product_categories.sql when
// available (upload bytes, SEED_A1_WP_CATEGORIES / Downloads), else
// a1-category-prompts.json, splits legacy combined overlays into role sections,
// and force-applies WP dump matches. Falls back to CategoryEnhanceUserTemplate.
// Idempotent when unchanged.
2026-08-16 16:57:36 +02:00
func RepairCompanyCategoryEnhancePrompts(ctx context.Context, pool *pgxpool.Pool, companyID uuid.UUID) (updated, alreadyOK, emptySkipped int, err error) {
2026-08-17 00:39:25 +02:00
res, err := RepairCompanyCategoryEnhancePromptsWithOptions(ctx, pool, companyID, RepairA1DemoOptions{})
2026-08-16 16:57:36 +02:00
if err != nil {
return 0, 0, 0, err
}
2026-08-17 00:39:25 +02:00
return res.Updated, res.AlreadyOK, res.EmptySkipped, nil
}
// RepairCompanyCategoryEnhancePromptsWithOptions applies category enhance prompt
// repair for one company. Pass WPCategoriesSQL to force-apply an uploaded dump
// (Admin Sync A1); empty opts keep auto-detect fallback.
func RepairCompanyCategoryEnhancePromptsWithOptions(ctx context.Context, pool *pgxpool.Pool, companyID uuid.UUID, opts RepairA1DemoOptions) (RepairCategoryEnhancePromptsResult, error) {
out := RepairCategoryEnhancePromptsResult{
ByCompany: map[string]int{},
}
if pool == nil {
return out, fmt.Errorf("nil pool")
}
if len(opts.WPCategoriesSQL) > 0 {
if _, _, err := LoadWPCategoryPromptOverlaysFromBytes(opts.WPCategoriesSQL); err != nil {
return out, fmt.Errorf("wp_product_categories upload: %w", err)
}
}
seedByNorm, seedByUID, seedMeta := resolveCategoryPromptOverlays(opts)
out.SeedPath = seedMeta.Path
out.WPCategoriesPath = seedMeta.WPPath
out.SeedEntries = seedMeta.Entries
forceFromSeed := seedMeta.ForceFromSeed
if opts.ForceFromSeed != nil {
forceFromSeed = *opts.ForceFromSeed
}
if _, err := repairCompanyCategoryEnhancePrompts(ctx, pool, companyID, companyID.String(), seedByNorm, seedByUID, false, forceFromSeed, &out); err != nil {
return out, err
2026-08-16 16:57:36 +02:00
}
2026-08-17 00:39:25 +02:00
return out, nil
2026-08-16 16:57:36 +02:00
}
// ResolvePlatformDemoCompanyID finds the Platform Demo sandbox (never A1 cohort).
func ResolvePlatformDemoCompanyID(ctx context.Context, pool *pgxpool.Pool) (uuid.UUID, error) {
var id uuid.UUID
err := pool.QueryRow(ctx, `
SELECT c.id
FROM companies c
WHERE c.name = $1
AND COALESCE(c.legacy_company_id, '') <> $2
ORDER BY c.created_at ASC
LIMIT 1`, platformDemoCompanyName, billing.A1LegacyCompanyID).Scan(&id)
if err != nil {
return uuid.Nil, fmt.Errorf("platform demo company not found: %w", err)
}
return id, nil
}