"""Declared parameter metadata for SQL-file ``-- param:`` annotations.
Carries the name, declared type string, and description parsed from
``-- param: <name> <type> [description]`` directives, plus an extensible registry
that resolves declared type strings to Python types for validation. Resolution is a
pure lookup; declared type strings are never evaluated.
"""
from collections.abc import Callable
from datetime import date, datetime, time
from decimal import Decimal
from typing import Final, TypeAlias
from uuid import UUID
from sqlspec.utils.serializers import to_json
__all__ = (
"ParamTypeMatcher",
"ParameterDeclaration",
"matches_param_type",
"register_param_type",
"resolve_param_type",
)
ParamTypeMatcher: TypeAlias = type | tuple[type, ...] | Callable[[object], bool]
_JSON_VALUE_TYPES: Final[tuple[type, ...]] = (dict, list, str, int, float, bool)
def _is_json_value(value: object) -> bool:
"""Return whether a value can be encoded by SQLSpec's JSON serializer."""
if not isinstance(value, _JSON_VALUE_TYPES):
return False
try:
to_json(value)
except (TypeError, ValueError):
return False
return True
_TYPE_REGISTRY: Final[dict[str, ParamTypeMatcher]] = {
"str": str,
"int": int,
"float": float,
"bool": bool,
"bytes": bytes,
"date": date,
"datetime": datetime,
"time": time,
"decimal": Decimal,
"uuid": UUID,
"uuid.uuid": UUID,
"dict": dict,
"dict[str,any]": dict,
"dict[str,object]": dict,
"json": _is_json_value,
"jsonb": _is_json_value,
"list[int]": list,
"list[str]": list,
"list[float]": list,
"list[bool]": list,
"list": list,
"tuple": tuple,
}
class ParameterDeclaration:
"""A single parameter declared in a SQL file header."""
__slots__ = ("description", "name", "required", "type_str")
def __init__(self, name: str, type_str: str, description: "str | None" = None, *, required: bool = True) -> None:
self.name = name
self.type_str = type_str
self.description = description
self.required = required