You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ossie.apache.org by kb...@apache.org on 2026/09/15 15:52:32 UTC
(ossie) branch main updated: fix(validation): enforce equal arity for relationship column arrays (#375)
This is an automated email from the ASF dual-hosted git repository.
khush-bhatia pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ossie.git
The following commit(s) were added to refs/heads/main by this push:
new 8170f667 fix(validation): enforce equal arity for relationship column arrays (#375)
8170f667 is described below
commit 8170f66716a175b9fd40ade92da5b06e498d40c1
Author: Chris Eubank <10...@users.noreply.github.com>
AuthorDate: Tue Sep 15 08:52:25 2026 -0700
fix(validation): enforce equal arity for relationship column arrays (#375)
The spec (core-spec/spec.md, "Relationships") requires from_columns and
to_columns to correspond positionally and to have the same number of
columns, but nothing enforced it. JSON Schema cannot express a
cross-array equality constraint, so a document with mismatched arities
(for example from_columns: [a, b] with to_columns: [c]) validated
successfully despite describing an incomplete tuple join.
Add validate_relationship_column_arity to validation/validate.py as a
new endpoint-validation rule, alongside validate_references. It emits an
[Arity] error per mismatched relationship and skips documents that
already fail schema validation. Covered by tests in
validation/tests/test_validate.py.
Addresses Problem 6 (Relationship Column Array Arity) from
https://github.com/apache/ossie/discussions/374
Signed-off-by: Chris Eubank <10...@users.noreply.github.com>
---
validation/tests/test_validate.py | 55 +++++++++++++++++++++++++++++++++++++++
validation/validate.py | 34 +++++++++++++++++++++++-
2 files changed, 88 insertions(+), 1 deletion(-)
diff --git a/validation/tests/test_validate.py b/validation/tests/test_validate.py
index 30806f18..bc41135b 100644
--- a/validation/tests/test_validate.py
+++ b/validation/tests/test_validate.py
@@ -32,6 +32,7 @@ _VALIDATE = module_from_spec(_SPEC)
_SPEC.loader.exec_module(_VALIDATE)
validate_references = _VALIDATE.validate_references
+validate_relationship_column_arity = _VALIDATE.validate_relationship_column_arity
def _document(datasets: list[dict], relationships: list[dict]) -> dict:
@@ -161,3 +162,57 @@ def test_skips_malformed_flat_unique_keys() -> None:
)
assert errors == []
+
+
+def _arity_relationship(from_columns: list[str], to_columns: list[str]) -> dict:
+ return {
+ "name": "orders_to_customers",
+ "from": "orders",
+ "to": "customers",
+ "from_columns": from_columns,
+ "to_columns": to_columns,
+ }
+
+
+@pytest.mark.parametrize(
+ ("from_columns", "to_columns"),
+ [
+ (["customer_id"], ["id"]),
+ (["product_id", "variant_id"], ["id", "variant_id"]),
+ ],
+)
+def test_arity_accepts_equal_length_columns(
+ from_columns: list[str], to_columns: list[str]
+) -> None:
+ rel = _arity_relationship(from_columns, to_columns)
+
+ assert validate_relationship_column_arity(_document([_ORDERS, _CUSTOMERS], [rel])) == []
+
+
+@pytest.mark.parametrize(
+ ("from_columns", "to_columns"),
+ [
+ (["product_id", "variant_id"], ["id"]),
+ (["customer_id"], ["id", "variant_id"]),
+ ],
+)
+def test_arity_rejects_mismatched_length_columns(
+ from_columns: list[str], to_columns: list[str]
+) -> None:
+ rel = _arity_relationship(from_columns, to_columns)
+
+ errors = validate_relationship_column_arity(_document([_ORDERS, _CUSTOMERS], [rel]))
+
+ assert errors == [
+ f"[Arity] Relationship 'orders_to_customers' in model 'm': "
+ f"from_columns ({len(from_columns)}) and to_columns ({len(to_columns)}) "
+ f"must have the same number of columns"
+ ]
+
+
+def test_arity_skips_non_list_columns() -> None:
+ # Schema validation reports the shape error; the arity check must not crash.
+ rel = _arity_relationship(["customer_id"], ["id"])
+ rel["to_columns"] = "id"
+
+ assert validate_relationship_column_arity(_document([_ORDERS, _CUSTOMERS], [rel])) == []
diff --git a/validation/validate.py b/validation/validate.py
index e11d49f4..04932138 100644
--- a/validation/validate.py
+++ b/validation/validate.py
@@ -33,7 +33,8 @@ Validates Ossie YAML files against:
1. JSON Schema (structure, types, enums)
2. Unique names (datasets, fields, metrics, relationships)
3. Valid relationship references
-4. SQL syntax (using sqlglot)
+4. Relationship column arity (from_columns and to_columns lengths match)
+5. SQL syntax (using sqlglot)
Usage:
python validation/validate.py <yaml_file>
@@ -231,6 +232,36 @@ def validate_references(data: dict) -> list[str]:
return errors
+def validate_relationship_column_arity(data: dict) -> list[str]:
+ """Validate that from_columns and to_columns have the same length.
+
+ The spec requires the two arrays to correspond positionally, so their
+ lengths must match. JSON Schema cannot express this, so it is checked here.
+ """
+ errors = []
+
+ for model in data.get("semantic_model", []):
+ model_name = model.get("name", "<unnamed>")
+
+ for rel in model.get("relationships", []):
+ rel_name = rel.get("name", "<unnamed>")
+ from_columns = rel.get("from_columns")
+ to_columns = rel.get("to_columns")
+
+ # Skip anything that already failed schema validation.
+ if not isinstance(from_columns, list) or not isinstance(to_columns, list):
+ continue
+
+ if len(from_columns) != len(to_columns):
+ errors.append(
+ f"[Arity] Relationship '{rel_name}' in model '{model_name}': "
+ f"from_columns ({len(from_columns)}) and "
+ f"to_columns ({len(to_columns)}) must have the same number of columns"
+ )
+
+ return errors
+
+
def validate_sql_expression(expr: str, dialect: str, context: str) -> str | None:
"""Validate a single SQL expression. Returns error message or None if valid."""
if not SQLGLOT_AVAILABLE:
@@ -344,6 +375,7 @@ def main():
if data.get("semantic_model"):
errors.extend(validate_unique_names(data))
errors.extend(validate_references(data))
+ errors.extend(validate_relationship_column_arity(data))
errors.extend(validate_sql(data))
# Report results