author Martin Baláž <embeembe@gmail.com>
1706272912 +0100
committer Daniele Varrazzo <daniele.varrazzo@gmail.com>
1706783634 +0000
feat: add `scalar_row` factory
Close #723
.. autofunction:: tuple_row
.. autofunction:: dict_row
.. autofunction:: namedtuple_row
+.. autofunction:: scalar_row
+
+ .. versionadded:: 3.2
+
.. autofunction:: class_row
This is not a row factory, but rather a factory of row factories.
(:ticket:`340`).
- Add :ref:`raw-query-cursors` to execute queries using placeholders in
PostgreSQL format (`$1`, `$2`...) (:ticket:`#560`).
+- Add `~rows.scalar_row` to return scalar values from a query (:ticket:`#723`).
- Add `~Connection.set_autocommit()` on sync connections, and similar
transaction control methods available on the async connections.
- Add support for libpq functions to close prepared statements and portals
return kwargs_row_
+def scalar_row(cursor: "BaseCursor[Any, Any]") -> "RowMaker[Any]":
+ """
+ Generate a row factory returning the first column
+ as a scalar value.
+ """
+ res = cursor.pgresult
+ if not res:
+ return no_result
+
+ nfields = _get_nfields(res)
+ if nfields is None:
+ return no_result
+
+ if nfields < 1:
+ raise e.ProgrammingError("at least one column expected")
+
+ def scalar_row_(values: Sequence[Any]) -> Any:
+ return values[0]
+
+ return scalar_row_
+
+
def no_result(values: Sequence[Any]) -> NoReturn:
"""A `RowMaker` that always fail.
assert p.age == 42
+def test_scalar_row(conn):
+ cur = conn.cursor(row_factory=rows.scalar_row)
+ cur.execute("select 1")
+ assert cur.fetchone() == 1
+ cur.execute("select 1, 2")
+ assert cur.fetchone() == 1
+ with pytest.raises(psycopg.ProgrammingError):
+ cur.execute("select")
+
+
@pytest.mark.parametrize(
"factory",
"tuple_row dict_row namedtuple_row class_row args_row kwargs_row".split(),