-
Notifications
You must be signed in to change notification settings - Fork 261
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for connection.raw_connection
#58
Conversation
I followed 2 different approaches:
If anything of these looks good I can get rid of redundant bits in the code and finish the rest of unittests. I'm also quite bad at naming. |
Yeah, p. 2 ( |
databases/backends/postgres.py
Outdated
def __getitem__(self, key: str) -> typing.Any: | ||
idx, datatype = self._column_map[key] | ||
raw = self._row[idx] | ||
def __getitem__(self, key: typing.Any) -> typing.Any: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not happy with this implementation in general and especially passing typing.Any
. I think it might be limited to str
and int
as a raw record's fields can be accessed by an int index or by the str key.
connection.raw_connection
to access the underlying driver's connection interface
connection.raw_connection
to access the underlying driver's connection interfaceconnection.raw_connection
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Crackin' stuff. A few comments here - most importantly, tweaking things so that .raw_connection
is a property.
databases/backends/postgres.py
Outdated
@@ -150,6 +150,10 @@ def __init__(self, database: PostgresBackend, dialect: Dialect): | |||
async for row in self._connection.cursor(query, *args): | |||
yield Record(row, result_columns, self._dialect) | |||
|
|||
async def raw_connection(self) -> asyncpg.connection.Connection: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need to (shouldn't) be an async method. (It's not performing any I/O itself, just returning the handle)
I guess we should probably use a property too, rather than a method.
@property
def raw_connection(self):
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's possible that the implementations ought to use a def get_raw_connection()
method, and the developer facing interface should be a def raw_connection
property, that calls get_raw_connection()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, was thinking about the property as well, and naming would be more natural as well.
databases/core.py
Outdated
@@ -111,6 +111,10 @@ def __init__( | |||
async for record in connection.iterate(query): | |||
yield record | |||
|
|||
async def raw_connection(self) -> typing.Any: | |||
async with self.connection() as connection: | |||
return await connection.raw_connection() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't be exposed at the top-level. Ie. You have to acquire the connection first, in order to access .raw_connection
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense and sets explicit flow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That also gives clarity. As connection already acquired (and it seems reasonable to avoid spawning the raw_connection from the database level acquiring a new one) we can expose already allocated connection object, that makes it a perfect case for the property.
databases/core.py
Outdated
@@ -168,6 +172,9 @@ def __init__(self, backend: DatabaseBackend) -> None: | |||
async def execute_many(self, query: ClauseElement, values: list) -> None: | |||
await self._connection.execute_many(query, values) | |||
|
|||
async def raw_connection(self) -> typing.Any: | |||
return await self._connection.raw_connection() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's go with...
@property
def raw_connection(self) -> typing.Any:
return self._connection.get_raw_connection()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also let's move the implementation to the very end of the class. That layout feels more natural to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Happy with layout, but considering the given context I think I'm looking forward to:
@property
def raw_connection(self) -> typing.Any:
return self._connection.raw_connection
if there're no objections
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fine with me, yup. 👍
tests/test_databases.py
Outdated
raw_connection_2 = await connection_2.raw_connection() | ||
|
||
assert raw_connection_0 is raw_connection_1 is raw_connection_2 | ||
assert raw_connection_0 is connection_1._connection._connection |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using properties I think we'd really want to change this to something like this...
async with Database(database_url) as database:
async with database.connection() as connection_1:
async with database.connection() as connection_2:
assert connection_1 is connection_2
assert connection_1.raw_connection is connection_2.raw_connection
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, that would be neat
tests/test_databases.py
Outdated
async with Database(database_url) as database: | ||
async with database.transaction(force_rollback=True): | ||
# Get the raw connection | ||
con = await database.raw_connection() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use something like connection
, raw_connection
, or driver
rather than the shorthand variable name.
Looks great! I don't think there's anything else to do on this part right? You happy for it to go in now? |
Yeah, I'm quite happy now, can't think of anything else as well. Thanks for the feedback! |
I'll prepare the documentation examples tomorrow, but within the |
@gvbgduh Makes sense - thanks. |
Adds ability to access the underlying driver's connection interface.