This commit is contained in:
2026-08-16 18:18:39 +02:00
parent b19373e2a4
commit d981147ff2
18 changed files with 20707 additions and 20497 deletions
@@ -92,6 +92,67 @@ func BackfillProcessedCategoriesFromMapped(ctx context.Context, pool *pgxpool.Po
return out, nil
}
// BackfillMappedCategoriesFromProcessed copies processed_products.category into
// raw_products.mapped_data.category when mapped category is empty. Legacy A1 dumps
// often store category only on processed rows; feed mappings do not map category,
// so Fix Catalog / re-seed must push processed → mapped for Products UI coverage.
// Does not invent categories.
func BackfillMappedCategoriesFromProcessed(ctx context.Context, pool *pgxpool.Pool, companyID uuid.UUID) (int64, error) {
if pool == nil {
return 0, fmt.Errorf("mapped category backfill: nil pool")
}
if companyID == uuid.Nil {
return 0, fmt.Errorf("mapped category backfill: empty company id")
}
ct, err := pool.Exec(ctx, `
UPDATE raw_products r
SET mapped_data = jsonb_set(
COALESCE(r.mapped_data, '{}'::jsonb),
'{category}',
to_jsonb(p.category),
true
),
updated_at = now()
FROM processed_products p
WHERE p.raw_product_id = r.id
AND p.company_id = $1
AND r.company_id = $1
AND COALESCE(NULLIF(trim(p.category), ''), '') <> ''
AND lower(trim(p.category)) <> 'none'
AND COALESCE(NULLIF(trim(r.mapped_data->>'category'), ''), '') = ''`, companyID)
if err != nil {
return 0, fmt.Errorf("mapped category backfill: %w", err)
}
return ct.RowsAffected(), nil
}
// CountMappedCategoryCoverage returns how many raw_products rows have a non-empty
// mapped_data.category vs empty, plus taxonomy row count for the company.
func CountMappedCategoryCoverage(ctx context.Context, pool *pgxpool.Pool, companyID uuid.UUID) (withCat, withoutCat, taxonomy int64, err error) {
if pool == nil {
return 0, 0, 0, fmt.Errorf("mapped category coverage: nil pool")
}
err = pool.QueryRow(ctx, `
SELECT
COUNT(*) FILTER (
WHERE COALESCE(NULLIF(trim(mapped_data->>'category'), ''), '') <> ''
),
COUNT(*) FILTER (
WHERE COALESCE(NULLIF(trim(mapped_data->>'category'), ''), '') = ''
)
FROM raw_products
WHERE company_id = $1`, companyID).Scan(&withCat, &withoutCat)
if err != nil {
return 0, 0, 0, fmt.Errorf("mapped category coverage: %w", err)
}
err = pool.QueryRow(ctx, `
SELECT COUNT(*) FROM categories WHERE company_id = $1`, companyID).Scan(&taxonomy)
if err != nil {
return withCat, withoutCat, 0, fmt.Errorf("taxonomy count: %w", err)
}
return withCat, withoutCat, taxonomy, nil
}
// CountProcessedCategoryCoverage returns how many processed rows for companyID have
// a non-empty category vs empty/"none".
func CountProcessedCategoryCoverage(ctx context.Context, pool *pgxpool.Pool, companyID uuid.UUID) (withCat, withoutCat int64, err error) {