Source code for neosqlite.collection.expr_evaluator.sql_converters.conditional

"""SQL converters for conditional operators."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
    pass


from .base import BaseSqlMixin


[docs] class ConditionalMixin(BaseSqlMixin): """$cond / $ifNull → SQL CASE / COALESCE."""
[docs] def _convert_cond_operator( self, operands: dict[str, Any] ) -> tuple[str, list[Any]]: """Convert $cond operator to SQL CASE statement.""" if not isinstance(operands, dict): raise ValueError("$cond requires a dictionary") if "if" not in operands or "then" not in operands: raise ValueError("$cond requires 'if' and 'then' fields") condition_sql, condition_params = self._convert_expr_to_sql( operands["if"] ) then_sql, then_params = self._convert_operand_to_sql(operands["then"]) if "else" in operands: else_sql, else_params = self._convert_operand_to_sql( operands["else"] ) else: else_sql, else_params = "NULL", [] sql = f"CASE WHEN {condition_sql} THEN {then_sql} ELSE {else_sql} END" return sql, condition_params + then_params + else_params
[docs] def _convert_ifNull_operator( self, operands: list[Any] ) -> tuple[str, list[Any]]: """Convert $ifNull operator to SQL COALESCE.""" if not isinstance(operands, list) or len(operands) != 2: raise ValueError("$ifNull requires exactly 2 operands") expr_sql, expr_params = self._convert_operand_to_sql(operands[0]) replacement_sql, replacement_params = self._convert_operand_to_sql( operands[1] ) sql = f"COALESCE({expr_sql}, {replacement_sql})" return sql, expr_params + replacement_params
[docs] def _convert_switch_operator( self, operands: dict[str, Any] ) -> tuple[str, list[Any]]: """Convert $switch operator to SQL CASE statement. MongoDB syntax: { $switch: { branches: [ { case: <expr>, then: <expr> }, ... ], default: <expr> // optional } } SQL equivalent: CASE WHEN <case1> THEN <then1> WHEN <case2> THEN <then2> ... ELSE <default> // NULL if omitted END """ if not isinstance(operands, dict): raise ValueError("$switch requires a dictionary") branches = operands.get("branches") if not branches or not isinstance(branches, list) or len(branches) == 0: raise ValueError("$switch requires a non-empty 'branches' array") default_val = operands.get("default") all_params: list[Any] = [] when_clauses: list[str] = [] for branch in branches: if not isinstance(branch, dict): raise ValueError("Each $switch branch must be a dictionary") case_expr = branch.get("case") then_expr = branch.get("then") if case_expr is None: raise ValueError( "Each $switch branch requires a 'case' expression" ) if then_expr is None: raise ValueError( "Each $switch branch requires a 'then' expression" ) # The 'case' is a boolean expression — use _convert_expr_to_sql case_sql, case_params = self._convert_expr_to_sql(case_expr) # The 'then' can be any value — use _convert_operand_to_sql then_sql, then_params = self._convert_operand_to_sql(then_expr) when_clauses.append(f"WHEN {case_sql} THEN {then_sql}") all_params.extend(case_params) all_params.extend(then_params) if default_val is not None: default_sql, default_params = self._convert_operand_to_sql( default_val ) else_clause = f"ELSE {default_sql}" all_params.extend(default_params) else: else_clause = "ELSE NULL" sql = f"CASE {' '.join(when_clauses)} {else_clause} END" return sql, all_params