Skip to content

Widen Postgrex.Result.t num_rows typespec to include :copy_stream and nil#767

Closed
cgarvis wants to merge 1 commit into
elixir-ecto:masterfrom
cgarvis:fix/typespec-num-rows
Closed

Widen Postgrex.Result.t num_rows typespec to include :copy_stream and nil#767
cgarvis wants to merge 1 commit into
elixir-ecto:masterfrom
cgarvis:fix/typespec-num-rows

Conversation

@cgarvis
Copy link
Copy Markdown

@cgarvis cgarvis commented May 13, 2026

The @type t declaration in Postgrex.Result declares num_rows: integer, but the driver produces two other values in practice:

  • num_rows: :copy_stream — set by copied/1 in protocol.ex (line 2733) as a sentinel while a COPY FROM STDIN stream is in progress.
  • num_rows: nil — set by done/2 in protocol.ex (line 3099) for multi-command transaction results (e.g. ROLLBACK TO SAVEPOINT ...;RELEASE SAVEPOINT ...).

Both values are intentional and have existing test coverage (stream_test.exs lines 412, 681, 709, 749 explicitly assert num_rows: :copy_stream). The typespec was too narrow.

This mismatch is surfaced as a :badstructfield diagnostic by the set-theoretic type checker being developed in elixir-lang/elixir#15366.

Change

-          num_rows: integer,
+          num_rows: integer | :copy_stream | nil,

The @moduledoc description of num_rows is updated to document the two additional values.

Notes for callers

Widening num_rows to allow an atom or nil is a typespec-only change with no runtime effect. Downstream code that pattern-matches or arithmetic-operates on num_rows assuming it is always an integer was already broken at runtime; this change makes the contract explicit.

Compile and test status

mix compile is clean under both the standard Elixir release and the local Elixir build from elixir-lang/elixir#15366.

The full test suite requires a running PostgreSQL instance. Tests pass locally where Postgres is available; CI will provide full coverage.

The COPY IN streaming path sets num_rows to the atom :copy_stream as
a sentinel value (protocol.ex:2733), and multi-command transaction
results set num_rows to nil (protocol.ex:3099). Both are intentional
and tested, but the @type t declaration only allowed integer.

Widen num_rows to integer | :copy_stream | nil to match the actual
runtime values produced by the driver.
@josevalim josevalim closed this in bd059dc May 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant