11from typing import TYPE_CHECKING , Any , final , override
22
3- from pydantic import BaseModel
3+ from pydantic import TypeAdapter
44from sqlalchemy import JSON , Dialect , TypeDecorator
55from sqlalchemy .dialects .postgresql import JSONB
66
1010
1111# Taken from https://gist.github.com/pdmtt/a6dc62f051c5597a8cdeeb8271c1e079?permalink_comment_id=5761533#gistcomment-5761533
1212@final
13- class PydanticType (TypeDecorator [BaseModel ]):
13+ class PydanticType (TypeDecorator [Any ]):
1414 """Pydantic type.
1515
1616 SAVING:
@@ -38,9 +38,10 @@ class PydanticType(TypeDecorator[BaseModel]):
3838 impl = JSONB
3939 cache_ok = True
4040
41- def __init__ (self , pydantic_type : type [ BaseModel ] ) -> None :
41+ def __init__ (self , pydantic_type : Any ) -> None :
4242 super ().__init__ ()
4343 self .pydantic_type = pydantic_type
44+ self ._adapter : TypeAdapter [Any ] = TypeAdapter (pydantic_type )
4445
4546 @override
4647 def load_dialect_impl (self , dialect : Dialect ) -> TypeEngine [JSONB | JSON ]:
@@ -55,31 +56,20 @@ def load_dialect_impl(self, dialect: Dialect) -> TypeEngine[JSONB | JSON]:
5556 @override
5657 def process_bind_param (
5758 self ,
58- value : BaseModel | None ,
59+ value : Any | None ,
5960 dialect : Dialect ,
6061 ) -> dict [str , Any ] | None :
6162 if value is None :
6263 return None
63-
64- if not isinstance (value , BaseModel ): # dynamic typing.
65- msg = f'The value "{ value !r} " is not a pydantic model'
66- raise TypeError (msg )
67-
68- # Setting mode to "json" entails that you won't need to define a custom json
69- # serializer ahead.
70- return value .model_dump (mode = "json" )
64+ return self ._adapter .dump_python (value , mode = "json" )
7165
7266 @override
7367 def process_result_value (
7468 self ,
7569 value : dict [str , Any ] | None ,
7670 dialect : Dialect ,
77- ) -> BaseModel | None :
78- # We're assuming that the value will be a dictionary here.
79- validate_on_load = True
80- if validate_on_load :
81- return self .pydantic_type .model_validate (value ) if value else None
82- return self .pydantic_type .model_construct (** value ) if value else None
71+ ) -> Any | None :
72+ return self ._adapter .validate_python (value ) if value else None
8373
8474 def __repr__ (self ) -> str :
8575 # Used by alembic
0 commit comments