From ef434b4c47f50dea328d8a1da895aed7e0870865 Mon Sep 17 00:00:00 2001 From: Chris Eubank <108756251+christianeu-db@users.noreply.github.com> Date: Wed, 23 Sep 2026 15:35:56 +0000 Subject: [PATCH] fix(wisdom): read OSSIE_SQL_2026 metric expressions OSSIE_SQL_2026 (core-spec #439, Python enum #440) is an ANSI-SQL-compatible portable dialect, but the wisdom converter's _pick_expression() fell back only through the dataset dialect and then ANSI_SQL. A field or metric expressed only in OSSIE_SQL_2026 raised a spurious MISSING_DIALECT_EXPRESSION issue, even though the converter still used the first listed expression as a fallback. Add OSSIE_SQL_2026 to the fallback chain, treating it as an ANSI_SQL-equivalent, so an OSSIE_SQL_2026-only field or metric is exported without the spurious issue. Add regression tests covering a field-only and a metric-only OSSIE_SQL_2026 expression, the ANSI_SQL and native-dialect precedence over it, and a genuinely unusable dialect that still reports MISSING_DIALECT_EXPRESSION. Partial fix for #442 (wisdom converter only). Co-authored-by: Isaac --- .../src/ossie_wisdom/ossie_to_wisdom.py | 3 + .../wisdom/tests/test_ossie_to_wisdom.py | 121 ++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/converters/wisdom/src/ossie_wisdom/ossie_to_wisdom.py b/converters/wisdom/src/ossie_wisdom/ossie_to_wisdom.py index b7be440e..75e10137 100644 --- a/converters/wisdom/src/ossie_wisdom/ossie_to_wisdom.py +++ b/converters/wisdom/src/ossie_wisdom/ossie_to_wisdom.py @@ -284,6 +284,9 @@ def _pick_expression( return by_dialect[dialect] if OssieDialect.ANSI_SQL in by_dialect: return by_dialect[OssieDialect.ANSI_SQL] + # OSSIE_SQL_2026 is ANSI-SQL-compatible; treat it as an ANSI_SQL-equivalent fallback. + if OssieDialect.OSSIE_SQL_2026 in by_dialect: + return by_dialect[OssieDialect.OSSIE_SQL_2026] issues.append( ConverterIssue(issue_type=ConverterIssueType.MISSING_DIALECT_EXPRESSION, element_name=element_name) ) diff --git a/converters/wisdom/tests/test_ossie_to_wisdom.py b/converters/wisdom/tests/test_ossie_to_wisdom.py index f89f5413..3048d263 100644 --- a/converters/wisdom/tests/test_ossie_to_wisdom.py +++ b/converters/wisdom/tests/test_ossie_to_wisdom.py @@ -38,6 +38,15 @@ def _snowflake(expression): return OssieExpression(dialects=[OssieDialectExpression(dialect=OssieDialect.SNOWFLAKE, expression=expression)]) +def _expr(*dialect_expressions): + return OssieExpression( + dialects=[ + OssieDialectExpression(dialect=dialect, expression=expression) + for dialect, expression in dialect_expressions + ] + ) + + @pytest.fixture(scope="module") def ossie_document(): export = json.loads(FIXTURE.read_text()) @@ -211,3 +220,115 @@ def test_unresolved_metric_attaches_to_first_dataset(): assert [issue.element_name for issue in _issues_of(result, ConverterIssueType.METRIC_TABLE_UNRESOLVED)] == [ "row_count" ] + + +def test_field_only_ossie_sql_2026_is_exported_without_missing_issue(): + """A field expressed only in OSSIE_SQL_2026 is exported, with no spurious + MISSING_DIALECT_EXPRESSION issue (#442).""" + document = OssieDocument( + name="m", + datasets=[ + OssieDataset( + name="orders", + source="analytics.sales.orders", + fields=[OssieField(name="region", expression=_expr((OssieDialect.OSSIE_SQL_2026, "o_region")))], + ) + ], + ) + result = OssieToWisdomConverter().convert(document, exported_at="2026-07-10T00:00:00+00:00") + formulas = {formula["name"]: formula["expression"] for formula in _table(result.output, "orders").get("formulas", [])} + assert formulas == {"region": "o_region"} + assert _issues_of(result, ConverterIssueType.MISSING_DIALECT_EXPRESSION) == [] + + +def test_metric_only_ossie_sql_2026_is_exported_without_missing_issue(): + """A metric expressed only in OSSIE_SQL_2026 is exported as a measure, with no + spurious MISSING_DIALECT_EXPRESSION issue (#442).""" + from ossie import OssieMetric + + document = OssieDocument( + name="m", + datasets=[OssieDataset(name="orders", source="analytics.sales.orders")], + metrics=[ + OssieMetric(name="total_amount", expression=_expr((OssieDialect.OSSIE_SQL_2026, "SUM(orders.amount)"))) + ], + ) + result = OssieToWisdomConverter().convert(document, exported_at="2026-07-10T00:00:00+00:00") + measures = {measure["name"]: measure["expression"] for measure in _table(result.output, "orders").get("measures", [])} + assert measures == {"total_amount": "SUM(orders.amount)"} + assert _issues_of(result, ConverterIssueType.MISSING_DIALECT_EXPRESSION) == [] + + +def test_ansi_sql_preferred_over_ossie_sql_2026(): + """ANSI_SQL wins over OSSIE_SQL_2026 when both are present.""" + document = OssieDocument( + name="m", + datasets=[ + OssieDataset( + name="orders", + source="analytics.sales.orders", + fields=[ + OssieField( + name="region", + expression=_expr( + (OssieDialect.OSSIE_SQL_2026, "portable_region"), + (OssieDialect.ANSI_SQL, "ansi_region"), + ), + ) + ], + ) + ], + ) + result = OssieToWisdomConverter().convert(document, exported_at="2026-07-10T00:00:00+00:00") + formulas = {formula["name"]: formula["expression"] for formula in _table(result.output, "orders").get("formulas", [])} + assert formulas == {"region": "ansi_region"} + + +def test_native_dialect_preferred_over_ossie_sql_2026(): + """A native dialect (SNOWFLAKE) wins over OSSIE_SQL_2026 when both are present.""" + document = OssieDocument( + name="m", + datasets=[ + OssieDataset( + name="orders", + source="analytics.sales.orders", + fields=[ + OssieField( + name="region", + expression=_expr( + (OssieDialect.OSSIE_SQL_2026, "portable_region"), + (OssieDialect.SNOWFLAKE, "snow_region"), + ), + ) + ], + ) + ], + ) + result = OssieToWisdomConverter().convert(document, exported_at="2026-07-10T00:00:00+00:00") + formulas = {formula["name"]: formula["expression"] for formula in _table(result.output, "orders").get("formulas", [])} + assert formulas == {"region": "snow_region"} + + +def test_unusable_dialect_still_reports_missing_expression(): + """A metric whose only dialect matches neither the dataset dialect, ANSI_SQL, nor + OSSIE_SQL_2026 still reports MISSING_DIALECT_EXPRESSION and falls back to the first + listed expression. Guards the fallback chain against silently accepting any dialect (#442).""" + from ossie import OssieMetric + + document = OssieDocument( + name="m", + datasets=[ + OssieDataset( + name="orders", + source="analytics.sales.orders", + fields=[OssieField(name="id", expression=_snowflake("id"))], + ) + ], + metrics=[OssieMetric(name="row_count", expression=_expr((OssieDialect.BIGQUERY, "COUNT(orders.id)")))], + ) + result = OssieToWisdomConverter().convert(document, exported_at="2026-07-10T00:00:00+00:00") + measures = {measure["name"]: measure["expression"] for measure in _table(result.output, "orders").get("measures", [])} + assert measures == {"row_count": "COUNT(orders.id)"} + assert [issue.element_name for issue in _issues_of(result, ConverterIssueType.MISSING_DIALECT_EXPRESSION)] == [ + "row_count" + ]