gino icon indicating copy to clipboard operation
gino copied to clipboard

Use asyncpg dsn

Open mociepka opened this issue 4 years ago • 1 comments

Currently, Gino is overriding an asyncpg connection host, port, user, password, database settings before passing them to the connection pool. In addition url params are not passed to the connection pool.

Because of this behavior developers are not able to pass host, port arguments in the query string. The asyncpg documentation explains that in more details.

In other words url like:

postgresql://postgres@postgres/mydb?host=/cloudsql/project:us-central1:bd/.s.PGSQL.5432

will use the localhost value instead of the socket path. This is how a DSN looks like when you work with the Google Cloud SQL server. Unfortunately, Google examples doesn't work with Gino.

mociepka avatar Jun 20 '20 18:06 mociepka

Cool, thanks for the PR and sorry for the late reply! I'm also suggesting the following changes on your branch:

diff --git a/src/gino/dialects/asyncpg.py b/src/gino/dialects/asyncpg.py
index 795f8d9..f329e69 100644
--- a/src/gino/dialects/asyncpg.py
+++ b/src/gino/dialects/asyncpg.py
@@ -2,6 +2,7 @@ import inspect
 import itertools
 import time
 import warnings
+from copy import copy

 import asyncpg
 from sqlalchemy import util, exc, sql
@@ -244,8 +245,10 @@ class Pool(base.Pool):
                 super().__init__(*pargs, **kwargs)
                 self.baked_queries = {}

+        url = copy(self._url)
+        url.drivername = "postgresql"
         args.update(
-            connection_class=Connection, dsn=str(self._url), loop=self._loop,
+            connection_class=Connection, dsn=str(url), loop=self._loop,
         )

         if self._prebake and self._bakery:
diff --git a/src/gino/strategies.py b/src/gino/strategies.py
index 63bee32..21be879 100644
--- a/src/gino/strategies.py
+++ b/src/gino/strategies.py
@@ -6,7 +6,6 @@ from sqlalchemy.engine.url import make_url
 from sqlalchemy.engine.strategies import EngineStrategy

 from .engine import GinoEngine
-from .dialects.asyncpg import AsyncpgDialect


 class GinoStrategy(EngineStrategy):
@@ -15,7 +14,8 @@ class GinoStrategy(EngineStrategy):
     This strategy is initialized automatically as :mod:`gino` is imported.

     If :func:`sqlalchemy.create_engine` uses ``strategy="gino"``, it will return a
-    :class:`~collections.abc.Coroutine`.
+    :class:`~collections.abc.Coroutine`, and treat URL prefix ``postgresql://`` or
+    ``postgres://`` as ``postgresql+asyncpg://``.
     """

     name = "gino"
@@ -26,13 +26,11 @@ class GinoStrategy(EngineStrategy):
         url = make_url(name_or_url)
         if loop is None:
             loop = asyncio.get_event_loop()
+        if url.drivername in {"postgresql", "postgres"}:
+            url = copy(url)
+            url.drivername = "postgresql+asyncpg"

-        # The postgresql dialect is already taken by the PGDialect_psycopg2
-        # we need to force ourone.
-        if url.drivername in ("postgresql", "postgres"):
-            dialect_cls = AsyncpgDialect
-        else:
-            dialect_cls = url.get_dialect()
+        dialect_cls = url.get_dialect()

         pop_kwarg = kwargs.pop

diff --git a/tests/test_bind.py b/tests/test_bind.py
index 7685fad..2a1d9bf 100644
--- a/tests/test_bind.py
+++ b/tests/test_bind.py
@@ -79,4 +79,10 @@ async def test_bind_url(dsn, driver_name):
     assert url.drivername == driver_name
     await db.set_bind(dsn)
     assert url.drivername == driver_name
+    assert (
+        await db.scalar(
+            "SELECT client_addr FROM pg_stat_activity where pid = pg_backend_pid()"
+        )
+        is not None
+    )
     await db.pop_bind().close()

fantix avatar Sep 07 '20 00:09 fantix