Skip to content

Use built-in array types when fetch_types is false - fixes #1164 - #1247

Open
WolfieLeader wants to merge 1 commit into
porsager:masterfrom
WolfieLeader:fix/builtin-arrays-without-fetch-types
Open

WolfieLeader wants to merge 1 commit into
porsager:masterfrom
WolfieLeader:fix/builtin-arrays-without-fetch-types

Conversation

@WolfieLeader

@WolfieLeader WolfieLeader commented Oct 6, 2026 •

Copy link
Copy Markdown

Fixes #1164.

With fetch_types: false, built-in arrays are neither parsed nor serialized:

const sql = postgres({ fetch_types: false })
await sql`select array['x','y']::text[] as t, array[1,2]::int4[] as i`
// [{ t: '{x,y}', i: '{1,2}' }]  (strings)
await sql`select ${ sql.array(['a', 'b']) }::text[]`
// PostgresError 22P02: malformed array literal: "a,b"

Only fetchArrayTypes() registers array parsers and serializers, and it runs only when fetch_types is true. Cloudflare's Hyperdrive guide for Postgres.js turns fetch_types off to save a round trip.

This change registers 22 built-in element/array pairs when fetch_types is false. Built-in types can be hard-coded because PostgreSQL fixes their OIDs in its catalog (pg_type.dat), so they are the same in every install. Custom types still need fetch_types. fetch_types: true is unchanged.

Changes

  • addArrayType() moves from connection.js to types.js and takes options first.
  • parseOptions() registers the pairs. addArrayType() keeps a parser or serializer that is already set (feat: don't override array type if already exists #578), so user types still win.
  • It runs in parseOptions(), not per connection. Per connection, the eager subscribe client filled the parent's serializers first and broke Insert array with undefined transform.
  • With fetch_types: false, built-in array columns now come back as JS arrays instead of '{x,y}' strings. Code that parsed those strings itself will see a change.

Test

New Built-in array types without fetch_types in tests/index.js. Before: 22P02 malformed array literal: "c,d". After: passes.

node tests/index.js and npm run test:cjs pass in full on Node 24.21.0 and PostgreSQL 15, set up like CI. Deno not run. eslint is clean. The 22 pairs match pg_type on PostgreSQL 12, 15 and 18.

Questions



Array parsers and serializers were only registered by fetchArrayTypes(), so with fetch_types: false a text[] column came back as the string '{x,y}' and sql.array(['a', 'b']) was sent as 'a,b'. Built-in array OIDs are fixed in the PostgreSQL catalog, so parseOptions now registers them when fetch_types is false. It runs in parseOptions rather than per connection because the listen and subscribe clients reuse the parent's options object and would otherwise register serializers bound to their own transform.
@WolfieLeader
WolfieLeader marked this pull request as ready for review October 6, 2026 14:52
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.

Feature request: Static array types with fetch_types false

1 participant