From b076fb05594ddbd7e02688bc17698f597a2fc3a4 Mon Sep 17 00:00:00 2001 From: Lou Marvin Caraig Date: Tue, 22 Sep 2020 17:20:19 +0200 Subject: [PATCH 1/3] Make fetch_val call fetch_one for type conversion Signed-off-by: Lou Marvin Caraig --- databases/backends/postgres.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/databases/backends/postgres.py b/databases/backends/postgres.py index dcedcdf8..623da883 100644 --- a/databases/backends/postgres.py +++ b/databases/backends/postgres.py @@ -178,9 +178,10 @@ async def fetch_one(self, query: ClauseElement) -> typing.Optional[typing.Mappin async def fetch_val( self, query: ClauseElement, column: typing.Any = 0 ) -> typing.Any: - assert self._connection is not None, "Connection is not acquired" - query, args, _ = self._compile(query) - return await self._connection.fetchval(query, *args, column=column) + row = await self.fetch_one(query) + if row is None: + return None + return row[column] async def execute(self, query: ClauseElement) -> typing.Any: assert self._connection is not None, "Connection is not acquired" From a443b6fc09eb14c57c4afcb783c19fe743b28295 Mon Sep 17 00:00:00 2001 From: Vadim Markovtsev Date: Sat, 26 Sep 2020 07:54:35 +0200 Subject: [PATCH 2/3] Add fetch_val tests --- tests/test_databases.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_databases.py b/tests/test_databases.py index 99de7ae6..ccfc9fc6 100644 --- a/tests/test_databases.py +++ b/tests/test_databases.py @@ -155,6 +155,18 @@ async def test_queries(database_url): result = await database.fetch_val(query=query) assert result == "example1" + # fetch_val() with no rows + query = sqlalchemy.sql.select([notes.c.text]).where( + notes.c.text == "impossible" + ) + result = await database.fetch_val(query=query) + assert result is None + + # fetch_val() with a different column + query = sqlalchemy.sql.select([notes.c.id, notes.c.text]) + result = await database.fetch_val(query=query, column=1) + assert result == "example1" + # row access (needed to maintain test coverage for Record.__getitem__ in postgres backend) query = sqlalchemy.sql.select([notes.c.text]) result = await database.fetch_one(query=query) From bb5c2651193e368b70e7bb9463ddadeffe01c4ad Mon Sep 17 00:00:00 2001 From: Vadim Markovtsev Date: Sat, 26 Sep 2020 08:00:36 +0200 Subject: [PATCH 3/3] Add the comment to explain the replacement of fetchval --- databases/backends/postgres.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/databases/backends/postgres.py b/databases/backends/postgres.py index 623da883..f8601ec9 100644 --- a/databases/backends/postgres.py +++ b/databases/backends/postgres.py @@ -178,6 +178,13 @@ async def fetch_one(self, query: ClauseElement) -> typing.Optional[typing.Mappin async def fetch_val( self, query: ClauseElement, column: typing.Any = 0 ) -> typing.Any: + # we are not calling self._connection.fetchval here because + # it does not convert all the types, e.g. JSON stays string + # instead of an object + # see also: + # https://github.com/encode/databases/pull/131 + # https://github.com/encode/databases/pull/132 + # https://github.com/encode/databases/pull/246 row = await self.fetch_one(query) if row is None: return None