func()

in src/psearch/serving/internal/services/spanner_service.go [85:141]


func (s *SpannerService) GetProductsBatch(ctx context.Context, productIDs []string) (map[string]map[string]interface{}, error) {
	if len(productIDs) == 0 {
		return make(map[string]map[string]interface{}), nil
	}

	startTime := time.Now()

	// Create a SQL statement with UNNEST to handle large number of product IDs
	stmt := spanner.Statement{
		SQL: `SELECT product_id, product_data 
              FROM products 
              WHERE product_id IN UNNEST(@product_ids)`,
		Params: map[string]interface{}{
			"product_ids": productIDs,
		},
	}

	resultMap := make(map[string]map[string]interface{})
	
	// Execute the query
	iter := s.client.Single().Query(ctx, stmt)
	defer iter.Stop()

	for {
		row, err := iter.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, fmt.Errorf("error iterating through query results: %v", err)
		}

		var productID string
		var productDataJSON spanner.NullJSON

		if err := row.Columns(&productID, &productDataJSON); err != nil {
			return nil, fmt.Errorf("failed to scan columns: %v", err)
		}

		if productDataJSON.Valid {
			// Type assert productDataJSON.Value directly to map[string]interface{}
			productData, ok := productDataJSON.Value.(map[string]interface{})
			if !ok {
				// Log the actual type if the assertion fails
				log.Printf("DEBUG: Unexpected type for productDataJSON.Value: %T", productDataJSON.Value)
				return nil, fmt.Errorf("failed to type assert product data from NullJSON.Value")
			}
			resultMap[productID] = productData
		}
	}

	elapsed := time.Since(startTime)
	log.Printf("Spanner batch fetch for %d products took %s, retrieved %d", 
		len(productIDs), elapsed, len(resultMap))

	return resultMap, nil
}