psqlpy-python / psqlpy

Asynchronous Python PostgreSQL driver written in Rust
https://psqlpy-python.github.io/
MIT License
211 stars 3 forks source link

tx.execute_many return type is None? #67

Closed brizzbuzz closed 2 months ago

brizzbuzz commented 2 months ago

hey... very happy to see a project like this taking shape :) was tinkering around with it and I'm either confused (very possible) or there is a bug in the declaration of transaction.execute_many.

When I inspect the python type definition, I see

 async def execute_many(
        self: Self,
        querystring: str,
        parameters: Sequence[Sequence[Any]] | None = None,
        prepared: bool = True,
    ) -> None:

this itself is inside of a .pyi file, which was new to me, but seems to be a way to define interfaces in Python? kinda neat. Anyway, I tried running a quick snippet of code and it does seem to be the case that execute_many returns None. If this is intended, how are users supposed to retrieve the result of the query? if not I guess it's a bug :)

brizzbuzz commented 2 months ago

fwiw here's the end snippet of the stack trace of a simple execute many request

    result = results.result()
             ^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'result'
    conn: Final[Connection] = await db_pool.connection()
    async with conn.transaction() as tx:
        results: Final[QueryResult] = await tx.execute_many(
            "can't show u this :)",
            [
                [
                    "or", "this"
                ]
                for thing in things
            ],
        )
        result = results.result()
        return result
chandr-andr commented 2 months ago

Hello, @brizzbuzz ! Thank you very much for you interest in the project.

There is no bug here. Originally, this method exists for queries which don't return anything. And we are trying to copy some methods from asyncpg and psycopg to make migration from one driver to another less painful. For example:

await transaction.execute_many("INSERT INTO table VALUES ($1, $2, $3)", params=[(1, 2, 3), (4, 5, 6)])

If you want to execute independent queries (and have some performance boost), I suggest you pipeline method for transaction. I think it has enough explanation in docs but if you have additional questions, you can ask here or in the project tg chat

If you want to make a lot of queries like in execute_many and retrieve results, it's better to use iterator:

for thing in things:
    res = await tx.execute("SQL", params=[thing])

About pyi files - they are necessary cuz the main code is written in Rust and there is no auto conversion from rust to python types.

brizzbuzz commented 2 months ago

ah there is totally enough info in the doc, I just never scrolled past execute_many 🤦

Gonna close this, but maybe a good NIT would be to add a call to action pointing people down the page :)

thanks for the speedy response

chandr-andr commented 2 months ago

Good idea, thanks!