""" Execute defquery / defaction definitions. Unlike fragment handlers (which produce SX markup via ``async_eval_to_sx``), query/action defs produce **data** (dicts, lists, scalars) that get JSON-serialized by the calling blueprint. Uses ``async_eval()`` with the I/O primitive pipeline so ``(service ...)`` calls are awaited inline. """ from __future__ import annotations from typing import Any from .types import QueryDef, ActionDef, NIL async def execute_query(query_def: QueryDef, params: dict[str, str]) -> Any: """Execute a defquery and return a JSON-serializable result. Parameters are bound from request query string args. """ from .jinja_bridge import get_component_env, _get_request_context from .async_eval import async_eval env = dict(get_component_env()) env.update(query_def.closure) # Bind params from request args (try kebab-case and snake_case) for param in query_def.params: snake = param.replace("-", "_") val = params.get(param, params.get(snake, NIL)) # Coerce type=int for common patterns if isinstance(val, str) and val.lstrip("-").isdigit(): val = int(val) env[param] = val ctx = _get_request_context() result = await async_eval(query_def.body, env, ctx) return _normalize(result) async def execute_action(action_def: ActionDef, payload: dict[str, Any]) -> Any: """Execute a defaction and return a JSON-serializable result. Parameters are bound from the JSON request body. """ from .jinja_bridge import get_component_env, _get_request_context from .async_eval import async_eval env = dict(get_component_env()) env.update(action_def.closure) # Bind params from JSON payload (try kebab-case and snake_case) for param in action_def.params: snake = param.replace("-", "_") val = payload.get(param, payload.get(snake, NIL)) env[param] = val ctx = _get_request_context() result = await async_eval(action_def.body, env, ctx) return _normalize(result) def _normalize(value: Any) -> Any: """Ensure result is JSON-serializable (strip NIL, convert sets, etc).""" if value is NIL or value is None: return None if isinstance(value, set): return list(value) return value