Skip to content

Commit 00dd77d

Browse files
committed
Clean up rows_as_map transaction fix per PR lpil#74 review
Address the inline review feedback on the cherry-picked fix: - Replace `element(11, Conn)` with `Conn#conn.decode_opts` by including pgo_internal.hrl. The header is private (it lives in pgo/src/, not pgo/include/), so the include is annotated to flag the dependency on internal PGO shape. - Split the in-transaction assertion out of expected_maps_test into a dedicated transaction_respects_rows_as_map_test, with a comment explaining the regression it covers. - Add an Unreleased CHANGELOG entry for the bug fix. Verified the new test fails (UnexpectedResultType, Dict vs Array) when pog_ffi:query/4 reverts to the pre-fix call, and all 32 tests pass with the fix.
1 parent 44e71aa commit 00dd77d

3 files changed

Lines changed: 47 additions & 15 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
- Fixed a bug where queries inside `pog.transaction` did not respect the pool's
6+
`rows_as_map` configuration. Rows are now returned as maps when the pool is
7+
configured with `rows_as_map: True`, both inside and outside transactions.
8+
39
## v4.1.0 - 2025-07-14
410

511
- Added a `numeric_decoder` to decode numeric types coming from postgres.

src/pog_ffi.erl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
-include_lib("pog/include/pog_Config.hrl").
66
-include_lib("pg_types/include/pg_types.hrl").
7+
%% pgo_internal.hrl is a private header (it lives in pgo/src/, not pgo/include/).
8+
%% We rely on it to read decode_opts off the #conn{} record because
9+
%% pgo_handler:extended_query/4 ignores Conn#conn.decode_opts and hardcodes [].
10+
-include_lib("pgo/src/pgo_internal.hrl").
711

812
null() ->
913
null.
@@ -85,8 +89,7 @@ start(Config) ->
8589
query(Pool, Sql, Arguments, Timeout) ->
8690
Res = case Pool of
8791
{single_connection, Conn} ->
88-
DecodeOpts = element(11, Conn),
89-
pgo_handler:extended_query(Conn, Sql, Arguments, DecodeOpts, #{});
92+
pgo_handler:extended_query(Conn, Sql, Arguments, Conn#conn.decode_opts, #{});
9093
{pool, Name} ->
9194
Options = #{
9295
pool => Name,

test/pog_test.gleam

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -515,25 +515,13 @@ pub fn expected_maps_test() {
515515
VALUES
516516
(DEFAULT, 'neo', true, ARRAY ['black'], '2022-10-10 11:30:30', '2020-03-04')
517517
RETURNING
518-
id, name"
518+
id"
519519

520520
let assert Ok(pog.Returned(rows: [id], ..)) =
521521
pog.query(sql)
522522
|> pog.returning(decode.at(["id"], decode.int))
523523
|> pog.execute(db.data)
524524

525-
let assert Ok(pog.Returned(1, ["neo"])) =
526-
pog.transaction(db.data, fn(conn) {
527-
let assert Ok(returned) =
528-
pog.query(sql)
529-
|> pog.returning(decode.at(["name"], decode.string))
530-
|> pog.execute(conn)
531-
532-
assert returned.rows == ["neo"]
533-
534-
Ok(returned)
535-
})
536-
537525
let assert Ok(returned) =
538526
pog.query("SELECT * FROM cats WHERE id = $1")
539527
|> pog.parameter(pog.int(id))
@@ -571,6 +559,41 @@ pub fn expected_maps_test() {
571559
disconnect(db)
572560
}
573561

562+
// Regression test: queries run inside `pog.transaction` against the checked-out
563+
// single connection must honour the pool's `rows_as_map` setting. Prior to the
564+
// fix in pog_ffi:query/4, decode_opts were not threaded through and rows came
565+
// back as positional tuples even when the pool was configured with
566+
// `rows_as_map: True`.
567+
pub fn transaction_respects_rows_as_map_test() {
568+
let name = process.new_name("pog_test")
569+
let assert Ok(db) =
570+
pog.Config(..default_config(name), rows_as_map: True)
571+
|> pog.start
572+
573+
let sql =
574+
"
575+
INSERT INTO
576+
cats
577+
VALUES
578+
(DEFAULT, 'neo', true, ARRAY ['black'], '2022-10-10 11:30:30', '2020-03-04')
579+
RETURNING
580+
id, name"
581+
582+
let assert Ok(pog.Returned(1, ["neo"])) =
583+
pog.transaction(db.data, fn(conn) {
584+
let assert Ok(returned) =
585+
pog.query(sql)
586+
|> pog.returning(decode.at(["name"], decode.string))
587+
|> pog.execute(conn)
588+
589+
assert returned.rows == ["neo"]
590+
591+
Ok(returned)
592+
})
593+
594+
disconnect(db)
595+
}
596+
574597
pub fn transaction_commit_test() {
575598
let db = start_default()
576599
let id_decoder = decode.at([0], decode.int)

0 commit comments

Comments
 (0)