health score
This commit is contained in:
@@ -37,12 +37,7 @@ var ErrCatalogueDBUnavailable = errors.New("catalogue database is not configured
|
||||
// catalogueProductColumns casts the text[] columns to text: GORM's raw
|
||||
// scan-into-struct silently drops slice-kind destination fields, so they
|
||||
// are read as text here and parsed into []string in scanProductRow.
|
||||
//
|
||||
// DELIBERATELY WITHOUT `nutrition`. This list is the fallback for when column
|
||||
// discovery has not run, and it asserts that every column it names exists — so
|
||||
// naming one that no brand table has yet would fail every read on this path
|
||||
// rather than cost one field. `nutrition` lives in catalogueOptionalColumns
|
||||
// below, which is what lets it ship before the agent team creates it.
|
||||
|
||||
const catalogueProductColumns = `id, product_name, title, description, category, image_id, size,
|
||||
variant_key, product_sku, sku_source, price_range, providers::text AS providers, fssai_license,
|
||||
highlights::text AS highlights, nutrients::text AS nutrients, search_query, created_at, updated_at`
|
||||
@@ -73,12 +68,6 @@ var catalogueOptionalColumns = []struct{ Name, Present, Absent string }{
|
||||
{"fssai_license", "fssai_license", "NULL::text AS fssai_license"},
|
||||
{"highlights", "highlights::text AS highlights", "NULL::text AS highlights"},
|
||||
{"nutrients", "nutrients::text AS nutrients", "NULL::text AS nutrients"},
|
||||
|
||||
// The structured panel the agent team fills: per, serving size and typed
|
||||
// rows. Optional like everything else here, and that is what makes it
|
||||
// shippable before the column exists — a brand table without it reads NULL
|
||||
// and falls back to parsing `nutrients` above, rather than going dark.
|
||||
{"nutrition", "nutrition::text AS nutrition", "NULL::text AS nutrition"},
|
||||
{"search_query", "search_query", "NULL::text AS search_query"},
|
||||
{"created_at", "created_at", "NULL::timestamptz AS created_at"},
|
||||
{"updated_at", "updated_at", "NULL::timestamptz AS updated_at"},
|
||||
@@ -146,7 +135,6 @@ type catalogueProductRow struct {
|
||||
FSSAILicense string
|
||||
Highlights string
|
||||
Nutrients string
|
||||
Nutrition string
|
||||
SearchQuery string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
@@ -230,7 +218,6 @@ func (row catalogueProductRow) toModel(brand string) models.CatalogueProduct {
|
||||
FSSAILicense: row.FSSAILicense,
|
||||
Highlights: models.ParsePGArray(row.Highlights),
|
||||
Nutrients: models.ParsePGArray(row.Nutrients),
|
||||
Nutrition: nutritionOf(row),
|
||||
SearchQuery: row.SearchQuery,
|
||||
CreatedAt: row.CreatedAt,
|
||||
UpdatedAt: row.UpdatedAt,
|
||||
@@ -741,29 +728,3 @@ func (r *catalogueRepository) GetProductByID(brand string, id int64) (*models.Ca
|
||||
product := row.toModel(strings.ToLower(brand))
|
||||
return &product, nil
|
||||
}
|
||||
|
||||
// nutritionOf decides which nutrition a catalogue row actually has.
|
||||
//
|
||||
// Two sources, and the structured one wins wherever it exists. The agent team
|
||||
// fills `nutrition` — a JSON panel with the basis, the serving size and typed
|
||||
// rows — and that is the one the app wants. Everything already in the catalogue
|
||||
// has only `nutrients`, a text[] of display lines, so those are parsed into the
|
||||
// same shape rather than left unusable.
|
||||
//
|
||||
// The derived panel is strictly worse: the strings never carried a basis, so it
|
||||
// has no "per 100g" on it. It is still the difference between a product page
|
||||
// with figures and an empty one, for every row on the platform today.
|
||||
//
|
||||
// A malformed `nutrition` value falls back rather than failing the read. One
|
||||
// bad JSON blob in one row should cost that row its panel, not take out the
|
||||
// brand listing it appears in.
|
||||
func nutritionOf(row catalogueProductRow) *models.NutritionPanel {
|
||||
if raw := strings.TrimSpace(row.Nutrition); raw != "" && raw != "null" {
|
||||
var panel models.NutritionPanel
|
||||
if err := json.Unmarshal([]byte(raw), &panel); err == nil && panel.HasValues() {
|
||||
return &panel
|
||||
}
|
||||
log.Printf("catalogue: product %d has nutrition that could not be read; falling back to its nutrient lines", row.ID)
|
||||
}
|
||||
return models.NutritionFromLines(models.ParsePGArray(row.Nutrients))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user