MagicStack / asyncpg

A fast PostgreSQL Database Client Library for Python/asyncio.
Apache License 2.0
7.01k stars 402 forks source link

Add equivalent to psycopg2 `register_adapter` #1186

Open dgilman-hrp opened 1 month ago

dgilman-hrp commented 1 month ago

In psycopg2, register_adapter along with utility functions provides a useful way to map custom Python classes into valid representations, often by relatively simple behaviors such as casting to str. There is no equivalent in asyncpg meaning moving from psycopg2 to asyncpg requires adding lots of str() casts to add and select queries.

The closest equivalent is set_type_codec but this only works for types that are registered with Postgres, not custom Python classes.

elprans commented 1 month ago

asyncpg normally relies on duck typing when accepting inputs, e.g if an argument is an integer, asyncpg will happily accept an object that implements __int__(), which is in line with Python's implicit casting tradition. Are you looking for a way to stringify objects specifically?

dgilman-hrp commented 1 month ago

What I have is a class which inherits from Pydantic ConstrainedStr. When I use it in a query, I get an error Expected unicode, unless I explicitly cast it to str before passing it to the query.

Adding __str__ to the custom class does not solve the problem.

asyncpg/protocol/prepared_stmt.pyx:168: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
asyncpg/protocol/codecs/base.pyx:206: in asyncpg.protocol.protocol.Codec.encode
    ???
asyncpg/protocol/codecs/base.pyx:111: in asyncpg.protocol.protocol.Codec.encode_scalar
    ???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
>   ???
E   TypeError: Expected unicode, got ApiKeyId
asyncpg/pgproto/./codecs/uuid.pyx:16: TypeError

It looks like the difference is that PyUnicode_AsUTF8AndSize expects an actual str whereas the equivalent file in psycopg2 works with custom types. https://github.com/psycopg/psycopg2/blob/a805acf59f402f554e95624b5e27518169ca7715/psycopg/adapter_qstring.c

Fixing this to work more like psycopg2 would fix my issue, as would a feature like register_adapter