in src/psearch/serving/internal/services/spanner_service.go [261:443]
func (s *SpannerService) transformToSearchResult(productID string, productData map[string]interface{}, score float64) (models.SearchResult, error) {
// Create score map
scoreMap := map[string]float64{
"hybrid": score,
}
// Extract name
name, _ := productData["name"].(string)
// Extract title
title, _ := productData["title"].(string)
// Extract brands
var brands []string
if brandsData, ok := productData["brands"].([]interface{}); ok {
for _, b := range brandsData {
if brand, ok := b.(string); ok {
brands = append(brands, brand)
}
}
}
// Extract categories
var categories []string
if categoriesData, ok := productData["categories"].([]interface{}); ok {
for _, c := range categoriesData {
if category, ok := c.(string); ok {
categories = append(categories, category)
}
}
}
// Handle price info
priceInfo := models.PriceInfo{
CurrencyCode: "USD", // Default
}
if priceInfoData, ok := productData["priceInfo"].(map[string]interface{}); ok {
if cost, ok := priceInfoData["cost"].(string); ok {
priceInfo.Cost = cost
}
if currencyCode, ok := priceInfoData["currencyCode"].(string); ok {
priceInfo.CurrencyCode = currencyCode
}
if originalPrice, ok := priceInfoData["originalPrice"].(string); ok {
priceInfo.OriginalPrice = originalPrice
}
if price, ok := priceInfoData["price"].(string); ok {
priceInfo.Price = price
}
if effectiveTime, ok := priceInfoData["priceEffectiveTime"].(string); ok {
priceInfo.PriceEffectiveTime = effectiveTime
}
if expireTime, ok := priceInfoData["priceExpireTime"].(string); ok {
priceInfo.PriceExpireTime = expireTime
}
}
// Handle images
var images []models.Image
if imagesData, ok := productData["images"].([]interface{}); ok {
for _, img := range imagesData {
if imgMap, ok := img.(map[string]interface{}); ok {
height := "0"
width := "0"
uri := ""
if h, ok := imgMap["height"].(string); ok {
height = h
}
if w, ok := imgMap["width"].(string); ok {
width = w
}
if u, ok := imgMap["uri"].(string); ok {
uri = u
}
// Convert gs:// URLs to https://storage.googleapis.com/
if len(uri) > 5 && uri[:5] == "gs://" {
uri = "https://storage.googleapis.com/" + uri[5:]
}
images = append(images, models.Image{
Height: height,
Width: width,
URI: uri,
})
}
}
}
// Extract sizes
var sizes []string
if sizesData, ok := productData["sizes"].([]interface{}); ok {
for _, s := range sizesData {
if size, ok := s.(string); ok {
sizes = append(sizes, size)
} else if sizeNum, ok := s.(float64); ok {
sizes = append(sizes, fmt.Sprintf("%v", sizeNum))
}
}
}
// Extract URI
uri, _ := productData["uri"].(string)
// Process attributes
var attributes []models.Attribute
if attrsData, ok := productData["attributes"].([]interface{}); ok {
for _, attr := range attrsData {
if attrMap, ok := attr.(map[string]interface{}); ok {
key, keyOk := attrMap["key"].(string)
valueData, valueOk := attrMap["value"].(map[string]interface{})
if keyOk && valueOk {
// Handle attribute value
attrValue := models.AttributeValue{}
if textData, ok := valueData["text"].([]interface{}); ok {
for _, t := range textData {
if textStr, ok := t.(string); ok {
attrValue.Text = append(attrValue.Text, textStr)
}
}
}
if numbersData, ok := valueData["numbers"].([]interface{}); ok {
for _, n := range numbersData {
if num, ok := n.(float64); ok {
attrValue.Numbers = append(attrValue.Numbers, num)
}
}
}
if indexable, ok := valueData["indexable"].(string); ok {
attrValue.Indexable = &indexable
}
if searchable, ok := valueData["searchable"].(string); ok {
attrValue.Searchable = &searchable
}
attributes = append(attributes, models.Attribute{
Key: key,
Value: attrValue,
})
}
}
}
}
// Handle tags as attributes
if tagsData, ok := productData["tags"].([]interface{}); ok {
for _, t := range tagsData {
if tag, ok := t.(string); ok {
attributes = append(attributes, models.Attribute{
Key: "tag",
Value: models.AttributeValue{
Text: []string{tag},
},
})
}
}
}
// Create search result
result := models.SearchResult{
ID: productID,
Name: name,
Title: title,
Brands: brands,
Categories: categories,
PriceInfo: priceInfo,
Availability: "IN_STOCK", // Default
Images: images,
Sizes: sizes,
RetrievableFields: "*",
Attributes: attributes,
URI: uri,
Score: scoreMap,
}
return result, nil
}