Skip to content

Commit 5164519

Browse files
committed
refactor(builder): share SQL object extraction
1 parent 7a9d086 commit 5164519

2 files changed

Lines changed: 20 additions & 19 deletions

File tree

sqlspec/builder/_select.py

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
_coerce_column,
2222
extract_column_name,
2323
extract_expression,
24+
extract_sql_object_expression,
2425
parse_column_expression,
2526
parse_condition_expression,
2627
parse_order_expression,
@@ -648,16 +649,7 @@ def _normalize_subquery_expression(self, subquery: Any, builder: "SQLBuilderProt
648649
return subquery_expr
649650

650651
if has_expression_and_sql(subquery):
651-
self._merge_parameters(subquery)
652-
expression_attr = subquery.expression
653-
if isinstance(expression_attr, exp.Expr):
654-
return expression_attr
655-
sql_text = subquery.sql
656-
parsed_from_sql: exp.Expr | None = exp.maybe_parse(sql_text, dialect=builder.dialect)
657-
if parsed_from_sql is None:
658-
msg = f"Could not parse subquery SQL: {sql_text}"
659-
raise SQLBuilderError(msg)
660-
return parsed_from_sql
652+
return extract_sql_object_expression(subquery, builder=self)
661653

662654
if isinstance(subquery, exp.Expr):
663655
return subquery
@@ -779,15 +771,7 @@ def _normalize_condition_expression(expression: exp.Expr) -> exp.Expr:
779771
return builder._parameterize_expression(_normalize_condition_expression(raw_expr))
780772
return parse_condition_expression(str(condition))
781773
if has_expression_and_sql(condition):
782-
expression_attr = condition.expression
783-
if isinstance(expression_attr, exp.Expr):
784-
self._merge_parameters(condition)
785-
return _normalize_condition_expression(expression_attr)
786-
sql_text = getattr(condition, "raw_sql", None)
787-
if sql_text is None:
788-
sql_text = condition.sql
789-
self._merge_parameters(condition)
790-
return parse_condition_expression(sql_text)
774+
return _normalize_condition_expression(extract_sql_object_expression(condition, builder=self))
791775

792776
msg = f"Unsupported condition type: {type(condition).__name__}"
793777
raise SQLBuilderError(msg)

tests/unit/builder/test_sql_factory.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
StringExpression,
3333
)
3434
from sqlspec.builder._join import create_join_builder
35+
from sqlspec.builder import _select as select_module
36+
from sqlspec.builder._parsing_utils import extract_sql_object_expression
3537
from sqlspec.core import SQL
3638
from sqlspec.exceptions import SQLBuilderError
3739

@@ -982,6 +984,21 @@ def test_multiple_sql_raw_objects_parameter_merging() -> None:
982984
assert ":min_date" in stmt.sql
983985

984986

987+
def test_select_conditions_use_shared_expression_extraction(monkeypatch: pytest.MonkeyPatch) -> None:
988+
calls = 0
989+
990+
def extract(value: object, builder: object | None = None) -> exp.Expr:
991+
nonlocal calls
992+
calls += 1
993+
return extract_sql_object_expression(value, builder)
994+
995+
monkeypatch.setattr(select_module, "extract_sql_object_expression", extract)
996+
sql.select("*").from_("users").where_exists(
997+
sql.raw("SELECT 1 FROM posts WHERE posts.user_id = :user_id", user_id=1)
998+
).where(sql.raw("id = :id", id=1))
999+
assert calls == 2
1000+
1001+
9851002
def test_sql_raw_without_parameters_still_works() -> None:
9861003
"""Test that SQL objects without parameters still work correctly."""
9871004
raw_expr = sql.raw("NOW()")

0 commit comments

Comments
 (0)