fixes
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
package processing
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
// BackfillCompanyProcessedAttributes rewrites attributes and processed_attributes
|
||||
// for every processed row in a company using AttrsForPersist + category_attributes
|
||||
// allowlists (same rules as processOne / enhance). Returns rows updated.
|
||||
func BackfillCompanyProcessedAttributes(ctx context.Context, pool *pgxpool.Pool, companyID uuid.UUID) (int64, error) {
|
||||
if pool == nil {
|
||||
return 0, fmt.Errorf("backfill attributes: nil pool")
|
||||
}
|
||||
p := &Pipeline{Pool: pool}
|
||||
sets := p.loadCategoryAttributeKeySets(ctx, companyID, uuid.Nil)
|
||||
|
||||
rows, err := pool.Query(ctx, `
|
||||
SELECT id, COALESCE(category, ''), COALESCE(attributes, '{}'::jsonb), COALESCE(processed_attributes, '{}'::jsonb)
|
||||
FROM processed_products
|
||||
WHERE company_id = $1`, companyID)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("backfill attributes query: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var updated int64
|
||||
for rows.Next() {
|
||||
var (
|
||||
id uuid.UUID
|
||||
category string
|
||||
attrsJSON []byte
|
||||
procAttrsJSON []byte
|
||||
)
|
||||
if err := rows.Scan(&id, &category, &attrsJSON, &procAttrsJSON); err != nil {
|
||||
return updated, fmt.Errorf("backfill attributes scan: %w", err)
|
||||
}
|
||||
attrs := decodeAttrMap(attrsJSON)
|
||||
procAttrs := decodeAttrMap(procAttrsJSON)
|
||||
allowed := allowedAttrKeysFromSets(sets, category)
|
||||
cleanAttrs := AttrsForPersist(attrs, allowed)
|
||||
cleanProc := AttrsForPersist(procAttrs, allowed)
|
||||
if len(cleanProc) == 0 {
|
||||
cleanProc = cleanAttrs
|
||||
}
|
||||
newAttrsJSON, err := json.Marshal(cleanAttrs)
|
||||
if err != nil {
|
||||
return updated, fmt.Errorf("backfill attributes marshal attrs %s: %w", id, err)
|
||||
}
|
||||
newProcJSON, err := json.Marshal(cleanProc)
|
||||
if err != nil {
|
||||
return updated, fmt.Errorf("backfill attributes marshal processed %s: %w", id, err)
|
||||
}
|
||||
if bytes.Equal(compactJSON(attrsJSON), compactJSON(newAttrsJSON)) &&
|
||||
bytes.Equal(compactJSON(procAttrsJSON), compactJSON(newProcJSON)) {
|
||||
continue
|
||||
}
|
||||
ct, err := pool.Exec(ctx, `
|
||||
UPDATE processed_products
|
||||
SET attributes = $2::jsonb,
|
||||
processed_attributes = $3::jsonb,
|
||||
updated_at = now()
|
||||
WHERE id = $1 AND company_id = $4`, id, string(newAttrsJSON), string(newProcJSON), companyID)
|
||||
if err != nil {
|
||||
return updated, fmt.Errorf("backfill attributes update %s: %w", id, err)
|
||||
}
|
||||
updated += ct.RowsAffected()
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return updated, fmt.Errorf("backfill attributes rows: %w", err)
|
||||
}
|
||||
return updated, nil
|
||||
}
|
||||
|
||||
func decodeAttrMap(raw []byte) map[string]any {
|
||||
out := map[string]any{}
|
||||
if len(raw) == 0 {
|
||||
return out
|
||||
}
|
||||
var parsed any
|
||||
if err := json.Unmarshal(raw, &parsed); err != nil {
|
||||
return out
|
||||
}
|
||||
switch t := parsed.(type) {
|
||||
case map[string]any:
|
||||
return t
|
||||
case []any:
|
||||
for _, entry := range t {
|
||||
if m, ok := entry.(map[string]any); ok {
|
||||
if k, ok := m["key"].(string); ok && k != "" {
|
||||
out[k] = m
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func compactJSON(b []byte) []byte {
|
||||
var buf bytes.Buffer
|
||||
if err := json.Compact(&buf, b); err != nil {
|
||||
return b
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
Reference in New Issue
Block a user