commit 7eb2000f9451e89e3df9d65e5cb996ea29598fe6
parent e57e0c9c5e586e4863cadf39c508c5c999b3950a
Author: triesap <tyson@radroots.org>
Date: Mon, 21 Sep 2026 12:59:29 +0000
core: add product references and taxonomy views
Diffstat:
2 files changed, 58 insertions(+), 0 deletions(-)
diff --git a/src/hyf_core/domain/product.mojo b/src/hyf_core/domain/product.mojo
@@ -0,0 +1,38 @@
+from std.collections import Optional
+
+
+@fieldwise_init
+struct ProductRef(Copyable, Movable):
+ var phrase: String
+ var catalogue_id: Optional[String]
+ var resolution: String
+
+
+def resolved_product(phrase: String, catalogue_id: String) raises -> ProductRef:
+ if phrase.strip() == "":
+ raise Error("product phrase must not be empty")
+ if catalogue_id.strip() == "":
+ raise Error("resolved product requires a catalogue id")
+ return ProductRef(
+ phrase=String(phrase),
+ catalogue_id=Optional[String](String(catalogue_id)),
+ resolution="resolved",
+ )
+
+
+def unresolved_product(phrase: String) raises -> ProductRef:
+ if phrase.strip() == "":
+ raise Error("product phrase must not be empty")
+ return ProductRef(
+ phrase=String(phrase), catalogue_id=None, resolution="unresolved"
+ )
+
+
+def product_is_resolved(product: ProductRef) -> Bool:
+ return product.resolution == "resolved" and product.catalogue_id is not None
+
+
+def product_matches(left: ProductRef, right: ProductRef) -> Bool:
+ if not product_is_resolved(left) or not product_is_resolved(right):
+ return False
+ return left.catalogue_id.value() == right.catalogue_id.value()
diff --git a/tests/test_domain.mojo b/tests/test_domain.mojo
@@ -323,3 +323,23 @@ def test_freshness_separates_record_harvest_and_verification() raises:
assert_true(not record_recency_implies_harvest_age())
with assert_raises():
_ = freshness(-1, 0, 0)
+
+
+from hyf_core.domain.product import (
+ product_is_resolved,
+ product_matches,
+ resolved_product,
+ unresolved_product,
+)
+
+
+def test_product_reference_resolution_and_unknown() raises:
+ var tomato = resolved_product("Roma tomatoes", "tomato.roma")
+ var other = resolved_product("Roma tomato", "tomato.roma")
+ assert_true(product_is_resolved(tomato))
+ assert_true(product_matches(tomato, other))
+ var unknown = unresolved_product("mystery greens")
+ assert_true(not product_is_resolved(unknown))
+ assert_true(not product_matches(tomato, unknown))
+ with assert_raises():
+ _ = resolved_product("x", "")