|
34 | 34 | StatementTypeT, |
35 | 35 | ) |
36 | 36 | from advanced_alchemy.service import ModelDictListT, ModelDictT, ModelDTOT, ModelOrRowMappingT, ModelT, OffsetPagination |
| 37 | +from advanced_alchemy.utils.serialization import DEFAULT_TYPE_ENCODERS |
37 | 38 |
|
38 | 39 | if TYPE_CHECKING: |
| 40 | + from collections.abc import Callable |
| 41 | + |
39 | 42 | from click import Group |
40 | 43 | from litestar.config.app import AppConfig |
41 | 44 | from litestar.types import BeforeMessageSendHookHandler |
|
44 | 47 |
|
45 | 48 | __all__ = ("SQLAlchemyInitPlugin",) |
46 | 49 |
|
| 50 | + |
| 51 | +def _get_aa_type_encoders() -> dict[type, "Callable[[Any], Any]"]: |
| 52 | + """Get Advanced Alchemy's built-in type encoders. |
| 53 | +
|
| 54 | + These encoders handle database-specific types that need special |
| 55 | + serialization. They are added to Litestar's type_encoders with |
| 56 | + lower precedence than user-defined encoders. |
| 57 | +
|
| 58 | + Returns: |
| 59 | + Dictionary of type to encoder function mappings. |
| 60 | + """ |
| 61 | + encoders: dict[type, Callable[[Any], Any]] = {**DEFAULT_TYPE_ENCODERS} |
| 62 | + |
| 63 | + # asyncpg UUID type (PostgreSQL asyncpg driver) |
| 64 | + with contextlib.suppress(ImportError): |
| 65 | + from asyncpg.pgproto import pgproto # pyright: ignore[reportMissingImports] |
| 66 | + |
| 67 | + encoders[pgproto.UUID] = str |
| 68 | + |
| 69 | + # uuid_utils UUID type (fast UUID implementation) |
| 70 | + with contextlib.suppress(ImportError): |
| 71 | + import uuid_utils # pyright: ignore[reportMissingImports] |
| 72 | + |
| 73 | + encoders[uuid_utils.UUID] = str # pyright: ignore[reportUnknownMemberType] |
| 74 | + |
| 75 | + return encoders |
| 76 | + |
| 77 | + |
| 78 | +def _get_aa_type_decoders() -> list[tuple["Callable[[Any], bool]", "Callable[[type, Any], Any]"]]: |
| 79 | + """Get Advanced Alchemy's built-in type decoders. |
| 80 | +
|
| 81 | + These decoders handle database-specific types that need special |
| 82 | + deserialization during request parsing. |
| 83 | +
|
| 84 | + Returns: |
| 85 | + List of (predicate, decoder) tuples for Litestar's type_decoders. |
| 86 | + """ |
| 87 | + decoders: list[tuple[Callable[[Any], bool], Callable[[type, Any], Any]]] = [] |
| 88 | + |
| 89 | + # uuid_utils UUID type decoder |
| 90 | + with contextlib.suppress(ImportError): |
| 91 | + import uuid_utils # pyright: ignore[reportMissingImports] |
| 92 | + |
| 93 | + decoders.append( |
| 94 | + (lambda x: x is uuid_utils.UUID, lambda t, v: t(str(v))) # pyright: ignore[reportUnknownMemberType] |
| 95 | + ) |
| 96 | + |
| 97 | + return decoders |
| 98 | + |
| 99 | + |
47 | 100 | signature_namespace_values: dict[str, Any] = { |
48 | 101 | "BeforeAfter": BeforeAfter, |
49 | 102 | "OnBeforeAfter": OnBeforeAfter, |
@@ -125,20 +178,24 @@ def on_app_init(self, app_config: "AppConfig") -> "AppConfig": |
125 | 178 | app_config: The :class:`AppConfig <.config.app.AppConfig>` instance. |
126 | 179 | """ |
127 | 180 | self._validate_config() |
| 181 | + |
| 182 | + # Add AA built-in type encoders/decoders |
| 183 | + # These are added BEFORE user encoders so user config takes precedence |
| 184 | + aa_encoders = _get_aa_type_encoders() |
| 185 | + aa_decoders = _get_aa_type_decoders() |
| 186 | + |
| 187 | + # Merge: AA built-ins first, then user encoders override |
| 188 | + app_config.type_encoders = {**aa_encoders, **(app_config.type_encoders or {})} |
| 189 | + app_config.type_decoders = [*aa_decoders, *(app_config.type_decoders or [])] |
| 190 | + |
128 | 191 | with contextlib.suppress(ImportError): |
129 | 192 | from asyncpg.pgproto import pgproto # pyright: ignore[reportMissingImports] |
130 | 193 |
|
131 | 194 | signature_namespace_values.update({"pgproto.UUID": pgproto.UUID}) |
132 | | - app_config.type_encoders = {pgproto.UUID: str, **(app_config.type_encoders or {})} |
133 | 195 | with contextlib.suppress(ImportError): |
134 | 196 | import uuid_utils # pyright: ignore[reportMissingImports] |
135 | 197 |
|
136 | 198 | signature_namespace_values.update({"uuid_utils.UUID": uuid_utils.UUID}) # pyright: ignore[reportUnknownMemberType] |
137 | | - app_config.type_encoders = {uuid_utils.UUID: str, **(app_config.type_encoders or {})} # pyright: ignore[reportUnknownMemberType] |
138 | | - app_config.type_decoders = [ |
139 | | - (lambda x: x is uuid_utils.UUID, lambda t, v: t(str(v))), # pyright: ignore[reportUnknownMemberType] |
140 | | - *(app_config.type_decoders or []), |
141 | | - ] |
142 | 199 | configure_exception_handler = False |
143 | 200 | for config in self.config: |
144 | 201 | if config.set_default_exception_handler: |
|
0 commit comments