Validates and normalizes product metadata for options and pricing.
This module handles:
- Format normalization (object -> string for price modifiers)
- Consistency validation between _option_values and _price_modifiers
- Cleanup of orphaned modifiers for removed values
Price Modifier Formats
The canonical format is a simple string representing the price delta:
%{"_price_modifiers" => %{
"size" => %{"M" => "5.00", "L" => "10.00"},
"color" => %{"Gold" => "8.00"}
}}Legacy object format is also supported for backward compatibility:
%{"_price_modifiers" => %{
"size" => %{"M" => %{"type" => "fixed", "value" => "5.00"}}
}}Both formats are normalized to string format when saving.
Summary
Functions
Removes orphaned modifiers for values not in _option_values.
Normalizes all price modifiers to string format.
Normalizes a complete set of product attributes before saving.
Validates metadata structure against option schema.
Validates consistency between _option_values and _price_modifiers.
Functions
Removes orphaned modifiers for values not in _option_values.
This cleans up price modifiers when option values are removed.
Examples
metadata = %{
"_option_values" => %{"size" => ["M", "L"]},
"_price_modifiers" => %{"size" => %{"S" => "0", "M" => "5.00", "L" => "10.00"}}
}
MetadataValidator.clean_orphaned_modifiers(metadata)
# => %{
# "_option_values" => %{"size" => ["M", "L"]},
# "_price_modifiers" => %{"size" => %{"M" => "5.00", "L" => "10.00"}}
# }
Normalizes all price modifiers to string format.
Converts object format to string format:
%{"type" => "fixed", "value" => "10.00"}->"10.00"%{"value" => "10.00"}->"10.00"%{"final_price" => "30.00"}with base_price 20 ->"10.00"
Already-string values are passed through unchanged.
Examples
metadata = %{
"_price_modifiers" => %{
"size" => %{
"M" => %{"type" => "fixed", "value" => "5.00"},
"L" => "10.00"
}
}
}
MetadataValidator.normalize_price_modifiers(metadata)
# => %{
# "_price_modifiers" => %{
# "size" => %{"M" => "5.00", "L" => "10.00"}
# }
# }
Normalizes a complete set of product attributes before saving.
This function:
- Normalizes price modifiers to string format
- Cleans orphaned modifiers
- Removes empty _option_values and _price_modifiers maps
Examples
attrs = %{
"title" => "My Product",
"metadata" => %{
"_option_values" => %{"size" => ["M", "L"]},
"_price_modifiers" => %{
"size" => %{
"M" => %{"type" => "fixed", "value" => "5.00"},
"S" => "orphaned"
}
}
}
}
MetadataValidator.normalize_product_attrs(attrs)
# Normalizes modifiers and removes orphaned "S" entry
Validates metadata structure against option schema.
Returns :ok or {:error, errors} where errors is a list of error tuples.
Examples
schema = [%{"key" => "size", "type" => "select", "options" => ["S", "M", "L"]}]
MetadataValidator.validate(%{"size" => "M"}, schema)
# => :ok
MetadataValidator.validate(%{"size" => "XL"}, schema)
# => {:error, [{"size", "must be one of: S, M, L"}]}
Validates consistency between _option_values and _price_modifiers.
Ensures that:
- All keys in _price_modifiers have corresponding entries in _option_values (or are schema options)
- All values in _price_modifiers exist in their respective option values
Returns a list of error tuples (empty if valid).