rows_as_map context lost in transaction connection
Hello!
Since upgrading pog to version 4, I am seeing some unexpected behavior with the feature to parse rows as a map when inside a transaction. My application, which was working with pog version 3, has started to fail because my decoders that are in transactions no longer have access to map data.
I have included a minimal reproduction. Note that the connection is instantiated with rows_as_map(True) which behaves as expected in a normal query on the connection itself, but that it reverts to tuple access when inside a transaction.
Maybe I'm holding it wrong? But since this seems to have been working before, maybe it's worth creating an issue.
import gleam/dynamic/decode
import gleam/erlang/process
import gleam/io
import gleam/result
import gleam/string
import pog
pub fn main() -> Nil {
let db = init()
let assert Ok(rows) =
"
SELECT * FROM test
"
|> pog.query()
|> pog.returning({
use id <- decode.field("id", decode.int)
use name <- decode.field("name", decode.string)
decode.success(#(id, name))
})
|> pog.execute(db)
io.println("Rows: " <> rows |> string.inspect())
let _ =
pog.transaction(db, fn(tx) {
let assert Ok(rows) =
"
SELECT * FROM test
"
|> pog.query()
|> pog.returning({
// this works, but it should not because i set rows_as_map on the connection
let id = decode.at([0], decode.int)
let name = decode.at([1], decode.string)
decode.success(#(id, name))
})
|> pog.execute(tx)
io.println(
"THIS WILL PRINT but it shouldn't rows: " <> rows |> string.inspect(),
)
Ok(rows)
})
let _ =
pog.transaction(db, fn(tx) {
let assert Ok(rows) =
"
SELECT * FROM test
"
|> pog.query()
|> pog.returning({
// this fails, because the rows_as_map is not being applied in the transaction
use id <- decode.field("id", decode.int)
use name <- decode.field("name", decode.string)
decode.success(#(id, name))
})
|> pog.execute(tx)
io.println("THIS WILL NOT PRINT TX rows: " <> rows |> string.inspect())
Ok(rows)
})
Nil
}
fn init() {
let name = process.new_name("db_pog_test")
let assert Ok(started) =
name
|> pog.url_config("postgresql://pog_test:pog_test@localhost:5434/pog_test")
|> result.unwrap(pog.default_config(name))
|> pog.rows_as_map(True)
|> pog.start()
let db = started.data
let assert Ok(_) =
"
CREATE TABLE IF NOT EXISTS test (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
"
|> pog.query()
|> pog.execute(db)
let assert Ok(_) =
"
INSERT INTO test(name) VALUES ('pog_test');
"
|> pog.query()
|> pog.execute(db)
db
}
Oh dear! That's unfortunate. Thank you for the report
I don't have enough time to make a real PR for this (because it would need more than 20 minutes reading the code), but I investigated a bit the issue. The root cause seems to come from pgo_handler:extended_query, used in pog_ffi:105. I'm sharing what I found, in hope it could help.
Actually, as we can see in pgo, extended_query/6 requires the default formatting options provided as argument. We can provide default formatting options through extended_query/5. It works with regular pgo:query/*, because we can see at pgo:14, that pgo injects the formatting options in extended_query.
I suspect pog_ffi:88 to fail too, but probably that everyone is actually using the pooled version of pog.
This bit me last night too, though I was crazy for a second. Will spends some time trying to fix it.