From 0685446e164c0ea700701e136f4f0738d5459e74 Mon Sep 17 00:00:00 2001 From: aaronfriedman Date: Mon, 24 Mar 2025 14:04:54 -0400 Subject: [PATCH] Add ability to return Postgres cursor description --- .python-version | 2 +- CHANGELOG.md | 3 +++ pyproject.toml | 2 +- src/nypl_py_utils/classes/postgresql_client.py | 9 +++++++-- tests/test_postgresql_client.py | 16 ++++++++++++++++ 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/.python-version b/.python-version index 9f3d4c1..c10780c 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.9.16 +3.13.1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 06478d6..07db7b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ # Changelog +## v1.6.5 3/24/25 +- Add capability to return PostgreSQL cursor description + ## v1.6.4 1/30/25 - Update pyproject.toml to reflect CL changes (since omitted in last release) diff --git a/pyproject.toml b/pyproject.toml index 7444b81..9fc68e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "nypl_py_utils" -version = "1.6.4" +version = "1.6.5" authors = [ { name="Aaron Friedman", email="aaronfriedman@nypl.org" }, ] diff --git a/src/nypl_py_utils/classes/postgresql_client.py b/src/nypl_py_utils/classes/postgresql_client.py index f174d34..3b1a836 100644 --- a/src/nypl_py_utils/classes/postgresql_client.py +++ b/src/nypl_py_utils/classes/postgresql_client.py @@ -55,7 +55,8 @@ def connect(self, retry_count=0, backoff_factor=5, **kwargs): 'Error connecting to {name} database: {error}'.format( name=self.database, error=e)) from None - def execute_query(self, query, query_params=None, **kwargs): + def execute_query( + self, query, return_desc=False, query_params=None, **kwargs): """ Executes an arbitrary query against the given database connection. @@ -63,6 +64,9 @@ def execute_query(self, query, query_params=None, **kwargs): ---------- query: str The query to execute + return_desc: bool, optional + Whether or not to return the cursor description in addition to the + results query_params: sequence, optional The values to be used in a parameterized query. The values can be for a single insert query -- e.g. execute_query( @@ -92,7 +96,8 @@ def execute_query(self, query, query_params=None, **kwargs): else: cursor.execute(query, query_params, **kwargs) self.conn.commit() - return None if cursor.description is None else cursor.fetchall() + results = None if cursor.description is None else cursor.fetchall() + return (results, cursor.description) if return_desc else results except Exception as e: self.conn.rollback() cursor.close() diff --git a/tests/test_postgresql_client.py b/tests/test_postgresql_client.py index af93625..f26feda 100644 --- a/tests/test_postgresql_client.py +++ b/tests/test_postgresql_client.py @@ -50,6 +50,22 @@ def test_execute_read_query(self, mock_pg_conn, test_instance, mocker): test_instance.conn.commit.assert_called_once() mock_cursor.close.assert_called_once() + def test_execute_read_query_with_desc(self, mock_pg_conn, test_instance, + mocker): + test_instance.connect() + + mock_cursor = mocker.MagicMock() + mock_cursor.description = [('description', None, None)] + mock_cursor.execute.return_value = mock_cursor + mock_cursor.fetchall.return_value = [(1, 2, 3), ('a', 'b', 'c')] + test_instance.conn.cursor.return_value = mock_cursor + + assert test_instance.execute_query('test query', return_desc=True) == ( + [(1, 2, 3), ('a', 'b', 'c')], [('description', None, None)]) + mock_cursor.execute.assert_called_once_with('test query', None) + test_instance.conn.commit.assert_called_once() + mock_cursor.close.assert_called_once() + def test_execute_write_query(self, mock_pg_conn, test_instance, mocker): test_instance.connect()