Skip to content

Commit b72f50d

Browse files
committed
Fix literal join operands and nested IF translation
- _quote_column_reference now passes numeric literals (e.g. 1, 3.14) through unquoted instead of wrapping them as identifiers ("1"). - IF/THEN/ELSE/END translation runs in a loop so nested IF blocks (IF x THEN IF y THEN ... END ELSE ... END) are fully converted to nested CASE WHEN expressions.
1 parent 0ee710e commit b72f50d

2 files changed

Lines changed: 31 additions & 5 deletions

File tree

sidemantic/adapters/tableau.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,11 @@ def _translate_formula(formula: str | None) -> tuple[str | None, bool]:
459459
result = _translate_iif(result)
460460

461461
# IF c THEN t ELSE e END -> CASE WHEN c THEN t ELSE e END
462-
result = _IF_THEN_RE.sub(_if_to_case, result)
462+
# Apply repeatedly for nested IF blocks
463+
prev = None
464+
while prev != result:
465+
prev = result
466+
result = _IF_THEN_RE.sub(_if_to_case, result)
463467

464468
# CONTAINS(s, sub) -> s LIKE '%' || sub || '%' (balanced-paren aware)
465469
result = _translate_contains(result)
@@ -736,10 +740,18 @@ def _quote_sql_identifier(identifier: str) -> str:
736740
return '"' + identifier.replace('"', '""') + '"'
737741

738742

743+
_NUMERIC_LITERAL_RE = re.compile(r"^-?\d+(\.\d+)?$")
744+
745+
739746
def _quote_identifier_if_needed(identifier: str) -> str:
740-
"""Quote a raw Tableau field name when it is not a simple SQL identifier."""
747+
"""Quote a raw Tableau field name when it is not a simple SQL identifier.
748+
749+
Passes through numeric literals and already-quoted identifiers unchanged.
750+
"""
741751
if identifier.startswith('"') and identifier.endswith('"'):
742752
return identifier
753+
if _NUMERIC_LITERAL_RE.match(identifier):
754+
return identifier
743755
if _SIMPLE_SQL_IDENTIFIER_RE.match(identifier):
744756
return identifier
745757
if "." in identifier:
@@ -748,9 +760,15 @@ def _quote_identifier_if_needed(identifier: str) -> str:
748760

749761

750762
def _quote_column_reference(column_name: str) -> str:
751-
"""Quote a possibly-qualified column reference."""
752-
parts = _strip_brackets(column_name).split(".")
753-
return ".".join(_quote_sql_identifier(part) for part in parts if part)
763+
"""Quote a possibly-qualified column reference.
764+
765+
Passes through numeric literals unchanged.
766+
"""
767+
stripped = _strip_brackets(column_name)
768+
if _NUMERIC_LITERAL_RE.match(stripped):
769+
return stripped
770+
parts = stripped.split(".")
771+
return ".".join(_quote_identifier_if_needed(part) for part in parts if part)
754772

755773

756774
def _quote_table_reference(table_name: str) -> str:

tests/adapters/tableau/test_formula.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,3 +388,11 @@ def test_contains_nested_args():
388388
assert "LIKE" in sql
389389
assert "COALESCE" in sql
390390
assert "'x'" in sql
391+
392+
393+
def test_nested_if_blocks():
394+
"""Nested IF/THEN/ELSE/END blocks are fully translated."""
395+
sql, ok = _translate_formula("IF [x]=1 THEN IF [y]=2 THEN 'a' ELSE 'b' END ELSE 'c' END")
396+
assert ok
397+
assert "IF" not in sql.upper().replace("CASE WHEN", "")
398+
assert sql.upper().count("CASE WHEN") == 2

0 commit comments

Comments
 (0)