test(integration): add PostgreSQL real-database case#377
Conversation
Add a `case_postgresql_real` integration scenario that exercises the
generated pog adapter against a live PostgreSQL server.
- `test/fixtures/postgresql_schema.sql` / `postgresql_crud_query.sql`:
a small `authors` schema plus CRUD / count queries covering `:one`,
`:many`, `:exec`, `:execlastid`, and an aggregate `:one`.
- `integration_test/fixtures/postgresql_real_test.gleam`: gleeunit
tests that drive the generated `pog_adapter` functions end-to-end
(create + get, ordered list_authors, null bio round-trip,
non-existent get returns None, delete round-trip, count row). The
test module checks `DATABASE_URL` at startup and prints a skip
message if it is not set so local `run.sh case_postgresql_real`
invocations without Postgres still exit cleanly.
- `integration_test/cases.sh`: register the case. It is intentionally
excluded from `ALL_INTEGRATION_CASES` because most local checkouts
do not have a Postgres running; callers pass
`sh integration_test/run.sh case_postgresql_real` with a
`DATABASE_URL` exported.
- `integration_test/lib.sh`: extend `_integration_dev_deps_block`
with a `gleeunit+envoy` alias so the new case can depend on
`envoy` for `DATABASE_URL` lookup without passing a multi-line
dev-deps TOML through the existing key=value runner interface.
- `.github/workflows/ci.yml`: provision a `postgres:16` service
container and run the new case with the container URL after the
existing gleam / ShellSpec steps.
Fix a pre-existing pog-adapter codegen bug that the new end-to-end
coverage surfaced:
- `render_pog_exec_last_id` emitted `|> pog.returning(decode.int)`,
which tries to decode an entire row as an integer. pog 4 rows are
positional arrays, so the decode failed with
`UnexpectedResultType([DecodeError("Int", "Array", [])])`. Changed
the returning decoder to read the first column instead, matching
how `:one` results already decode. Verified against a local
postgres:16 container (all six tests pass).
`just all` (format-check + check + build + `gleam test` +
ShellSpec) continues to pass end-to-end.
Closes #151
ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Free Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThis pull request introduces PostgreSQL integration testing infrastructure by adding a PostgreSQL 16 service container to CI, implementing integration test cases with database fixtures, and updating code generation to properly decode pog adapter results. Changes
Sequence DiagramsequenceDiagram
participant CI as CI Runner
participant PG as PostgreSQL Service
participant Test as Test Executor (gleeunit)
participant Adapter as pog_adapter
CI->>PG: Start service on port 5432
activate PG
CI->>Test: Run case_postgresql_real
activate Test
Test->>Test: Read DATABASE_URL from env
Test->>Adapter: connect_or_fail (create pool)
Adapter->>PG: Establish connection
PG-->>Adapter: Connection ready
Adapter-->>Test: pog.Connection
Test->>Test: reset_authors (drop/recreate table)
Test->>PG: Execute schema reset
PG-->>Test: Schema ready
Test->>Test: Execute test functions
loop Test Cases
Test->>Adapter: Execute SQL query (create, read, list, delete, count)
Adapter->>PG: Query execution
PG-->>Adapter: Row results
Adapter-->>Test: Decoded result
end
Test-->>CI: Test results
deactivate Test
deactivate PG
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
Note 🎁 Summarized by CodeRabbit FreeYour organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login. Comment |
Summary
Add an end-to-end integration test that drives the generated pog adapter against a real PostgreSQL server, closing the gap between "the generated code compiles" (existing ShellSpec build test) and "the generated code actually works" for PostgreSQL. CI provisions a
postgres:16service container and runs the new case after the existing gleam / ShellSpec steps. Closes #151.Changes
test/fixtures/postgresql_schema.sql/postgresql_crud_query.sql: smallauthorsschema plus CRUD + count queries covering:one,:many,:exec,:execlastid, and an aggregate:one.integration_test/fixtures/postgresql_real_test.gleam: gleeunit test module that drives the generatedpog_adapterfunctions end-to-end (create + get, orderedlist_authors, null-bio round-trip, non-existentgetreturnsNone, delete round-trip, count row). The module checksDATABASE_URLat startup and prints a skip message if it is not set so localrun.sh case_postgresql_realwithout Postgres still exits cleanly.integration_test/cases.sh: registercase_postgresql_real. Intentionally not added toALL_INTEGRATION_CASESbecause most local checkouts do not have Postgres running; invoke it explicitly withDATABASE_URL=... sh integration_test/run.sh case_postgresql_real.integration_test/lib.sh: add agleeunit+envoydev-deps alias so the new case can depend onenvoyforDATABASE_URLlookup without passing a multi-line TOML through the existing key=value runner interface..github/workflows/ci.yml: add apostgres:16service container with a health-check and a new CI step that setsDATABASE_URLand runssh integration_test/run.sh case_postgresql_real.Out-of-scope bug fix caught by the new coverage
render_pog_exec_last_idemitted|> pog.returning(decode.int), which tries to decode an entire row as an integer. pog 4 returns rows as positional arrays, so the decode failed withUnexpectedResultType([DecodeError("Int", "Array", [])]). Changed the returning decoder to read the first column instead, matching how:oneresults already decode. Verified against a localpostgres:16container (all six new tests pass after the fix).Design Decisions
main()whenDATABASE_URLis missing. The alternative — moving the check into every test function — would repeat eight lines of boilerplate per test without preventing anyone from forgetting it on a future test. Short-circuiting frommainkeeps every test in the file free to assume the connection works.run.sh. An explicitcase_postgresql_realargument keepsrun.sha one-shot happy path locally while still letting CI provision the service and run it.envoyfor env-var access instead of a custom FFI shim. The Gleamenvoypackage is the community default foros.getenv, and adding it as an integration-only dev dependency via the newgleeunit+envoyalias keeps the coresqlodepackage dependency surface unchanged. A custom Erlanggetenvshim would have lived insrc/and forced a separate module to handle a one-line capability.Limitations
:one,:many,:exec,:execlastid, and aggregate:onecover. RETURNING clauses, PostgreSQL-specific types (ENUMs, UUIDs, arrays), and slice parameters are not yet covered; those can be added as follow-up cases by registering more functions incases.sh.gleeunitmain exits 0 without reporting that zero tests ran, which is indistinguishable from "successfully ran nothing". CI always exportsDATABASE_URL, so the skip path exists primarily for local convenience.sqlode_pg_integration_poolatom. Running two instances of this test in parallel on the same node would conflict; the case keeps things serial inside one process, and CI runs it inside a fresh Erlang VM per job.Summary by CodeRabbit
Tests
Bug Fixes