OSIToMSIConverter._find_dataset_for_col picks the wrong semantic_model for a SUM_BOOLEAN metric whose condition references a qualified column, because it re-parses the whole aggregation expression instead of just the column reference.
Root cause
converters/dbt/src/ossie_dbt/osi_to_msi.py:361-387, _find_dataset_for_col:
raw_inner = _get_raw_inner_col(raw_expr_str)
if raw_inner and "." in raw_inner:
ds_name, _ = raw_inner.rsplit(".", 1)
return ds_name
raw_expr_str is the entire metric expression, not the bare column. For a simple SUM(orders.amount), _get_raw_inner_col (expression_utils.py:136) returns orders.amount and the rsplit correctly yields orders. But for the SUM(CASE WHEN <qualified column> THEN 1 ELSE 0 END) shape that _extract_agg_info (expression_utils.py:63-73) recognizes as AggregationType.SUM_BOOLEAN, _get_raw_inner_col returns the entire rendered CASE WHEN expression (since tree.this of a Sum node is the Case node itself), and rsplit(".", 1) then slices through the CASE WHEN keywords instead of the dataset qualifier.
Repro (current HEAD 8c410f904c9bb20f683ef31292442e7bc432a8f6), driven through the real OSIToMSIConverter.convert() entry point, not the helper directly:
import sys
sys.path.insert(0, "converters/dbt/src")
sys.path.insert(0, "converters/dbt")
sys.path.insert(0, "python/src")
from ossie_dbt.osi_to_msi import OSIToMSIConverter
from tests.helpers import _osi_dataset, _osi_doc, _osi_field, _osi_metric
doc = _osi_doc(
datasets=[_osi_dataset("orders", fields=[_osi_field("order_id")])],
metrics=[_osi_metric("has_order", "SUM(CASE WHEN orders.order_id IS NOT NULL THEN 1 ELSE 0 END)")],
)
result = OSIToMSIConverter().convert(doc).output
print(result.metrics[0].type_params.metric_aggregation_params.semantic_model)
Run from converters/dbt/ with metricflow>=0.209.0, sqlglot>=20.0, jinja2>=3.0, PyYAML>=6.0, pydantic>=2.0 installed.
Observed: semantic_model is 'CASE WHEN NOT orders'.
Expected: 'orders'.
The resulting PydanticMetric points at a semantic model name that doesn't exist in the manifest, which the MetricFlow validator downstream would reject (or silently fail to resolve if a coincidentally-named model exists).
tests/test_osi_to_msi.py has no case exercising SUM_BOOLEAN over a qualified column, so this shape isn't covered.
Happy to send a PR (the fix is a small, scoped change to _find_dataset_for_col) if that's useful.
OSIToMSIConverter._find_dataset_for_colpicks the wrongsemantic_modelfor aSUM_BOOLEANmetric whose condition references a qualified column, because it re-parses the whole aggregation expression instead of just the column reference.Root cause
converters/dbt/src/ossie_dbt/osi_to_msi.py:361-387,_find_dataset_for_col:raw_expr_stris the entire metric expression, not the bare column. For a simpleSUM(orders.amount),_get_raw_inner_col(expression_utils.py:136) returnsorders.amountand thersplitcorrectly yieldsorders. But for theSUM(CASE WHEN <qualified column> THEN 1 ELSE 0 END)shape that_extract_agg_info(expression_utils.py:63-73) recognizes asAggregationType.SUM_BOOLEAN,_get_raw_inner_colreturns the entire rendered CASE WHEN expression (sincetree.thisof aSumnode is theCasenode itself), andrsplit(".", 1)then slices through theCASE WHENkeywords instead of the dataset qualifier.Repro (current HEAD
8c410f904c9bb20f683ef31292442e7bc432a8f6), driven through the realOSIToMSIConverter.convert()entry point, not the helper directly:Run from
converters/dbt/withmetricflow>=0.209.0,sqlglot>=20.0,jinja2>=3.0,PyYAML>=6.0,pydantic>=2.0installed.Observed:
semantic_modelis'CASE WHEN NOT orders'.Expected:
'orders'.The resulting
PydanticMetricpoints at a semantic model name that doesn't exist in the manifest, which the MetricFlow validator downstream would reject (or silently fail to resolve if a coincidentally-named model exists).tests/test_osi_to_msi.pyhas no case exercisingSUM_BOOLEANover a qualified column, so this shape isn't covered.Happy to send a PR (the fix is a small, scoped change to
_find_dataset_for_col) if that's useful.