package models import ( "strings" "time" ) // CatalogueProduct maps to the per-brand tables (brand_dabur, brand_nestle, ...) // in the separate pgvector catalogue database. The `embedding` vector column // is intentionally not mapped here — it is never needed in an API response. type CatalogueProduct struct { ID int64 `json:"id"` Brand string `json:"brand"` ProductName string `json:"product_name"` Title string `json:"title,omitempty"` Description string `json:"description,omitempty"` Category string `json:"category,omitempty"` ImageID string `json:"image_id,omitempty"` Images []string `json:"images,omitempty"` Size string `json:"size,omitempty"` VariantKey string `json:"variant_key,omitempty"` ProductSKU string `json:"product_sku,omitempty"` SKUSource string `json:"sku_source,omitempty"` PriceRange string `json:"price_range,omitempty"` Providers PGStringArray `json:"providers,omitempty"` FSSAILicense string `json:"fssai_license,omitempty"` Highlights PGStringArray `json:"highlights,omitempty"` Nutrients PGStringArray `json:"nutrients,omitempty"` SearchQuery string `json:"search_query,omitempty"` CreatedAt time.Time `json:"created_at,omitempty"` UpdatedAt time.Time `json:"updated_at,omitempty"` } // CatalogueBrand describes a brand available in the catalogue DB. type CatalogueBrand struct { Brand string `json:"brand"` ProductCount int64 `json:"product_count"` } // PGStringArray is a plain []string used for catalogue array fields // (providers, highlights, nutrients) in JSON responses. type PGStringArray []string // ParsePGArray parses a Postgres text[] literal (e.g. "{Amazon,Flipkart}") // into a Go []string. GORM's raw-scan-into-struct silently drops slice-kind // destination fields, so array columns are queried as `col::text` and // converted with this function after scanning, rather than scanned directly. func ParsePGArray(s string) PGStringArray { s = strings.TrimSpace(s) if s == "" || s == "{}" { return PGStringArray{} } if strings.HasPrefix(s, "{") && strings.HasSuffix(s, "}") { s = s[1 : len(s)-1] } var result PGStringArray var buf strings.Builder inQuotes := false escaped := false for _, r := range s { switch { case escaped: buf.WriteRune(r) escaped = false case r == '\\': escaped = true case r == '"': inQuotes = !inQuotes case r == ',' && !inQuotes: result = append(result, buf.String()) buf.Reset() default: buf.WriteRune(r) } } result = append(result, buf.String()) for i, v := range result { if v == "NULL" { result[i] = "" } } return result }