support datafields in projection

This commit is contained in:
mats committed 2026-06-30 10:31:31 +02:00
1 parent b128608316
commit d04679daf5
4 files changed
+64 -7

No files matched your search

+18
View File
@@ -115,6 +115,23 @@ func Apply(s Schema, source map[string]any) (Projection, error) {
truthy = DefaultTrueValues()
}
var attrs json.RawMessage
if len(s.AttributesFields) > 0 {
m := make(map[string]any)
for _, key := range s.AttributesFields {
if val, ok := source[key]; ok && val != nil {
m[key] = val
}
}
if len(m) > 0 {
b, err := json.Marshal(m)
if err != nil {
return Projection{}, fmt.Errorf("%w: marshal attributes: %w", ErrProjectionBuild, err)
}
attrs = b
}
}
p := Projection{
ItemID: uint32Of(source, s.ItemIdField),
ID: id,
@@ -122,6 +139,7 @@ func Apply(s Schema, source map[string]any) (Projection, error) {
Title: stringOf(source, s.TitleField),
PriceIncVat: price,
Currency: cur,
Attributes: attrs,
TaxClass: tax,
InventoryTracked: boolOf(source, s.InventoryTrackedF, truthy),
DropShip: boolOf(source, s.DropShipF, truthy),
+33
View File
@@ -37,6 +37,39 @@ func TestBuilderJSONNumber(t *testing.T) {
}
}
func TestBuilderAttributes(t *testing.T) {
s := DefaultSchema()
s.AttributesFields = []string{"cart", "color"}
src := map[string]any{
"sku": "X-1",
"price_inc_vat": int64(100),
"updated_at": int64(1700000000000),
"cart": map[string]any{"data": "some-cart-data"},
"color": "red",
"ignored": "should-not-be-in-attrs",
}
p, err := Apply(s, src)
if err != nil {
t.Fatalf("Apply: %v", err)
}
var m map[string]any
if err := json.Unmarshal(p.Attributes, &m); err != nil {
t.Fatalf("unmarshal Attributes: %v", err)
}
if len(m) != 2 {
t.Errorf("expected 2 attributes, got %d", len(m))
}
if cartVal, ok := m["cart"].(map[string]any); !ok || cartVal["data"] != "some-cart-data" {
t.Errorf("cart attribute: got %v", m["cart"])
}
if m["color"] != "red" {
t.Errorf("color attribute: got %v", m["color"])
}
if _, ok := m["ignored"]; ok {
t.Errorf("ignored attribute was extracted: %v", m)
}
}
// Updated=UseSourceField: missing source updated_at MUST be a loud error,
// not a stamp-now fallback. (Foot-gun 3 resolution: silence here invalidates
// every consumer's cache on rebuild.)
+8 -7
View File
@@ -92,13 +92,14 @@ type Projection struct {
// TaxClass uses a string identifier (see platform/tax class constants).
// Empty string means "unclassified"; the consumer's tax.Provider is what
// resolves the identifier to a numeric rate.
TaxClass string `json:"tax_class"`
InventoryTracked bool `json:"inventory_tracked"`
DropShip bool `json:"drop_ship"`
Category string `json:"category,omitempty"`
Brand string `json:"brand,omitempty"`
Image string `json:"image,omitempty"`
UpdatedAt int64 `json:"updated_at"`
Attributes json.RawMessage `json:"attributes,omitempty"`
TaxClass string `json:"tax_class"`
InventoryTracked bool `json:"inventory_tracked"`
DropShip bool `json:"drop_ship"`
Category string `json:"category,omitempty"`
Brand string `json:"brand,omitempty"`
Image string `json:"image,omitempty"`
UpdatedAt int64 `json:"updated_at"`
}
// PayloadKey is the envelope key producers use when publishing a slice of
+5
View File
@@ -61,6 +61,9 @@ type Schema struct {
CategoryField string `json:"category_field,omitempty"`
BrandField string `json:"brand_field,omitempty"`
ImageField string `json:"image_field,omitempty"`
// AttributesFields names the keys in the source map[string]any that
// should be extracted and built into the Projection's json.RawMessage Attributes field.
AttributesFields []string `json:"attributes_fields,omitempty"`
// ItemIdField is the source-side key carrying the producer's catalog
// item id (uint32-equivalent). DefaultSchema points at "id" (matching
// the product service's /api/get/{sku} shape). Producers that omit
@@ -127,6 +130,7 @@ func DefaultSchema() Schema {
// Standard product service carries the integer catalog id under "id".
ItemIdField: "id",
UpdatedAtField: "updated_at",
AttributesFields: []string{"data"},
FixedCurrency: "", // read from source if present
DefaultTaxClass: "standard",
@@ -165,6 +169,7 @@ func BygglagretSchema() Schema {
ImageField: "PrimaryImage",
ItemIdField: "item_id",
UpdatedAtField: "LastModifiedMs",
AttributesFields: []string{"data"},
FixedCurrency: "SEK",
DefaultTaxClass: "standard",