Skip to content
This repository was archived by the owner on Aug 19, 2025. It is now read-only.

Commit 3f26f76

Browse files
author
ansipunk
committed
S01E08
1 parent 1c58a73 commit 3f26f76

File tree

4 files changed

+58
-58
lines changed

4 files changed

+58
-58
lines changed

databases/backends/asyncpg.py

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
import asyncpg
55
from sqlalchemy.engine.interfaces import Dialect
66
from sqlalchemy.sql import ClauseElement
7+
from sqlalchemy.sql.ddl import DDLElement
78

89
from databases.backends.common.records import Record, create_column_maps
9-
from databases.backends.dialects.psycopg import compile_query, get_dialect
10-
from databases.core import DatabaseURL
10+
from databases.backends.dialects.psycopg import dialect as psycopg_dialect
11+
from databases.core import LOG_EXTRA, DatabaseURL
1112
from databases.interfaces import (
1213
ConnectionBackend,
1314
DatabaseBackend,
@@ -24,9 +25,20 @@ def __init__(
2425
) -> None:
2526
self._database_url = DatabaseURL(database_url)
2627
self._options = options
27-
self._dialect = get_dialect()
28+
self._dialect = self._get_dialect()
2829
self._pool = None
2930

31+
def _get_dialect(self) -> Dialect:
32+
dialect = psycopg_dialect(paramstyle="pyformat")
33+
dialect.implicit_returning = True
34+
dialect.supports_native_enum = True
35+
dialect.supports_smallserial = True # 9.2+
36+
dialect._backslash_escapes = False
37+
dialect.supports_sane_multi_rowcount = True # psycopg 2.0.9+
38+
dialect._has_native_hstore = True
39+
dialect.supports_native_decimal = True
40+
return dialect
41+
3042
def _get_connection_kwargs(self) -> dict:
3143
url_options = self._database_url.options
3244

@@ -87,15 +99,15 @@ async def release(self) -> None:
8799

88100
async def fetch_all(self, query: ClauseElement) -> typing.List[RecordInterface]:
89101
assert self._connection is not None, "Connection is not acquired"
90-
query_str, args, result_columns = compile_query(query, self._dialect)
102+
query_str, args, result_columns = self._compile(query)
91103
rows = await self._connection.fetch(query_str, *args)
92104
dialect = self._dialect
93105
column_maps = create_column_maps(result_columns)
94106
return [Record(row, result_columns, dialect, column_maps) for row in rows]
95107

96108
async def fetch_one(self, query: ClauseElement) -> typing.Optional[RecordInterface]:
97109
assert self._connection is not None, "Connection is not acquired"
98-
query_str, args, result_columns = compile_query(query, self._dialect)
110+
query_str, args, result_columns = self._compile(query)
99111
row = await self._connection.fetchrow(query_str, *args)
100112
if row is None:
101113
return None
@@ -123,7 +135,7 @@ async def fetch_val(
123135

124136
async def execute(self, query: ClauseElement) -> typing.Any:
125137
assert self._connection is not None, "Connection is not acquired"
126-
query_str, args, _ = compile_query(query, self._dialect)
138+
query_str, args, _ = self._compile(query)
127139
return await self._connection.fetchval(query_str, *args)
128140

129141
async def execute_many(self, queries: typing.List[ClauseElement]) -> None:
@@ -132,25 +144,55 @@ async def execute_many(self, queries: typing.List[ClauseElement]) -> None:
132144
# loop through multiple executes here, which should all end up
133145
# using the same prepared statement.
134146
for single_query in queries:
135-
single_query, args, _ = compile_query(single_query, self._dialect)
147+
single_query, args, _ = self._compile(single_query)
136148
await self._connection.execute(single_query, *args)
137149

138150
async def iterate(
139151
self, query: ClauseElement
140152
) -> typing.AsyncGenerator[typing.Any, None]:
141153
assert self._connection is not None, "Connection is not acquired"
142-
query_str, args, result_columns = compile_query(query, self._dialect)
154+
query_str, args, result_columns = self._compile(query)
143155
column_maps = create_column_maps(result_columns)
144156
async for row in self._connection.cursor(query_str, *args):
145157
yield Record(row, result_columns, self._dialect, column_maps)
146158

147159
def transaction(self) -> TransactionBackend:
148160
return AsyncpgTransaction(connection=self)
149161

150-
@property
151-
def raw_connection(self) -> asyncpg.connection.Connection:
152-
assert self._connection is not None, "Connection is not acquired"
153-
return self._connection
162+
def _compile(self, query: ClauseElement) -> typing.Tuple[str, list, tuple]:
163+
compiled = query.compile(
164+
dialect=self._dialect, compile_kwargs={"render_postcompile": True}
165+
)
166+
167+
if not isinstance(query, DDLElement):
168+
compiled_params = sorted(compiled.params.items())
169+
170+
mapping = {
171+
key: "$" + str(i) for i, (key, _) in enumerate(compiled_params, start=1)
172+
}
173+
compiled_query = compiled.string % mapping
174+
175+
processors = compiled._bind_processors
176+
args = [
177+
processors[key](val) if key in processors else val
178+
for key, val in compiled_params
179+
]
180+
result_map = compiled._result_columns
181+
else:
182+
compiled_query = compiled.string
183+
args = []
184+
result_map = None
185+
186+
query_message = compiled_query.replace(" \n", " ").replace("\n", " ")
187+
logger.debug(
188+
"Query: %s Args: %s", query_message, repr(tuple(args)), extra=LOG_EXTRA
189+
)
190+
return compiled_query, args, result_map
191+
192+
@property
193+
def raw_connection(self) -> asyncpg.connection.Connection:
194+
assert self._connection is not None, "Connection is not acquired"
195+
return self._connection
154196

155197

156198
class AsyncpgTransaction(TransactionBackend):

databases/backends/dialects/psycopg.py

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010
from sqlalchemy import types, util
1111
from sqlalchemy.dialects.postgresql.base import PGDialect, PGExecutionContext
1212
from sqlalchemy.engine import processors
13-
from sqlalchemy.engine.interfaces import Dialect
14-
from sqlalchemy.sql import ClauseElement
15-
from sqlalchemy.sql.ddl import DDLElement
1613
from sqlalchemy.types import Float, Numeric
1714

1815

@@ -46,42 +43,4 @@ class PGDialect_psycopg(PGDialect):
4643
execution_ctx_cls = PGExecutionContext_psycopg
4744

4845

49-
def get_dialect() -> Dialect:
50-
dialect = PGDialect_psycopg(paramstyle="pyformat")
51-
dialect.implicit_returning = True
52-
dialect.supports_native_enum = True
53-
dialect.supports_smallserial = True # 9.2+
54-
dialect._backslash_escapes = False
55-
dialect.supports_sane_multi_rowcount = True # psycopg 2.0.9+
56-
dialect._has_native_hstore = True
57-
dialect.supports_native_decimal = True
58-
return dialect
59-
60-
61-
def compile_query(
62-
query: ClauseElement, dialect: Dialect
63-
) -> typing.Tuple[str, list, tuple]:
64-
compiled = query.compile(
65-
dialect=dialect, compile_kwargs={"render_postcompile": True}
66-
)
67-
68-
if not isinstance(query, DDLElement):
69-
compiled_params = sorted(compiled.params.items())
70-
71-
mapping = {
72-
key: "$" + str(i) for i, (key, _) in enumerate(compiled_params, start=1)
73-
}
74-
compiled_query = compiled.string % mapping
75-
76-
processors = compiled._bind_processors
77-
args = [
78-
processors[key](val) if key in processors else val
79-
for key, val in compiled_params
80-
]
81-
result_map = compiled._result_columns
82-
else:
83-
compiled_query = compiled.string
84-
args = []
85-
result_map = None
86-
87-
return compiled_query, args, result_map
46+
dialect = PGDialect_psycopg

databases/backends/psycopg.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,8 @@ async def connect(self) -> None:
3939
if self._pool is not None:
4040
return
4141

42-
self._pool = psycopg_pool.AsyncConnectionPool(
43-
self._database_url._url, open=False, **self._options
44-
)
42+
url = self._database_url._url.replace("postgresql+psycopg", "postgresql")
43+
self._pool = psycopg_pool.AsyncConnectionPool(url, open=False, **self._options)
4544

4645
# TODO: Add configurable timeouts
4746
await self._pool.open()

databases/core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@
4444
class Database:
4545
SUPPORTED_BACKENDS = {
4646
"postgres": "databases.backends.asyncpg:AsyncpgBackend",
47+
"postgresql": "databases.backends.asyncpg:AsyncpgBackend",
4748
"postgresql+aiopg": "databases.backends.aiopg:AiopgBackend",
4849
"postgresql+asyncpg": "databases.backends.asyncpg:AsyncpgBackend",
4950
"postgresql+psycopg": "databases.backends.psycopg:PsycopgBackend",
50-
"postgresql": "databases.backends.psycopg:PsycopgBackend",
5151
"mysql": "databases.backends.mysql:MySQLBackend",
5252
"mysql+aiomysql": "databases.backends.asyncmy:MySQLBackend",
5353
"mysql+asyncmy": "databases.backends.asyncmy:AsyncMyBackend",

0 commit comments

Comments
 (0)