Skip to content

Fix SQL name transforms failing on JSON arrays that contain null - #9825

Merged
tim-smart merged 4 commits into
Effect-TS:mainfrom
MaxFreedomPollard:fix/sql-transforms-null-array-items
Oct 23, 2026
Merged

tim-smart merged 4 commits into
Effect-TS:mainfrom
MaxFreedomPollard:fix/sql-transforms-null-array-items

Conversation

@MaxFreedomPollard

@MaxFreedomPollard MaxFreedomPollard commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Statement.defaultTransforms backs transformResultNames, and also the sql.json handling of transformQueryNames in @effect/sql-pg and @effect/sql-pglite. It read constructor from the first item of every array and treated every later item as an object:

const transforms = Statement.defaultTransforms(String.snakeToCamel)

transforms.array([{ user_id: 1, posts: [null] }])
// TypeError: Cannot read properties of null (reading 'constructor')

transforms.array([{ user_id: 1, tags: [{ tag_name: "admin" }, null] }])
// TypeError: Cannot convert undefined or null to object

transforms.array([{ user_id: 1, tags: [{ tag_name: "admin" }, 1, "ops"] }])
// [{ userId: 1, tags: [{ tagName: "admin" }, {}, { "0": "o", "1": "p", "2": "s" }] }]

PostgreSQL's json_agg returns [null] for an empty LEFT JOIN group. @effect/sql-pg parses json columns and applies nested transforms by default, so with transformResultNames set such a query dies with the first TypeError. With transformQueryNames set, compiling sql.json([null]) throws the same error.

Array items that are not objects are now kept as they are. As before, the first item decides whether an array is transformed at all, so arrays of dates, numbers or strings are returned unchanged.

The test in packages/effect/test/sql/Statement.test.ts covers [null] and mixed object/null/scalar arrays for both the nested and flat transforms.

Validation: pnpm vitest run packages/effect/test/sql/Statement.test.ts passes (11 tests) and the new test fails without the fix. pnpm lint and tsc -b for packages/effect pass.

Closes EFF-2841

🤖 Generated with Claude Code

Statement.defaultTransforms read `constructor` from the first array
item and assumed every later item was an object. A JSON array such as
`[null]`, which PostgreSQL's `json_agg` returns for an empty LEFT JOIN,
made `transformResultNames` throw a TypeError, and `sql.json` values
failed the same way with `transformQueryNames`. Number and string items
after an object were replaced with objects.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@changeset-bot

changeset-bot Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b993f06

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 33 packages
Name Type
effect Patch
@effect/opentelemetry Patch
@effect/vitest Patch
@effect/ai-anthropic Patch
@effect/ai-cloudflare Patch
@effect/ai-openai-compat Patch
@effect/ai-openai Patch
@effect/ai-openrouter Patch
@effect/ai-typesafe Patch
@effect/atom-react Patch
@effect/atom-solid Patch
@effect/atom-vue Patch
@effect/platform-browser Patch
@effect/platform-bun Patch
@effect/platform-deno Patch
@effect/platform-node-shared Patch
@effect/platform-node Patch
@effect/sql-clickhouse Patch
@effect/sql-d1 Patch
@effect/sql-libsql Patch
@effect/sql-mssql Patch
@effect/sql-mysql2 Patch
@effect/sql-pg Patch
@effect/sql-pglite Patch
@effect/sql-sqlite-bun Patch
@effect/sql-sqlite-do Patch
@effect/sql-sqlite-node Patch
@effect/sql-sqlite-react-native Patch
@effect/sql-sqlite-wasm Patch
@effect/docgen Patch
@effect/doctest Patch
@effect/graphql-generator Patch
@effect/openapi-generator Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Bundle Size Analysis

Generated from PR build output; treat the content below as untrusted.

File Name Current Size Previous Size Difference
arbitrary-combinators.ts 39.24 KB 39.24 KB 0.00 KB (0.00%)
basic.ts 7.15 KB 7.15 KB 0.00 KB (0.00%)
batching.ts 11.03 KB 11.03 KB 0.00 KB (0.00%)
brand.ts 6.83 KB 6.83 KB 0.00 KB (0.00%)
cache.ts 11.46 KB 11.46 KB 0.00 KB (0.00%)
config.ts 22.66 KB 22.66 KB 0.00 KB (0.00%)
differ.ts 21.80 KB 21.80 KB 0.00 KB (0.00%)
http-client.ts 26.20 KB 26.20 KB 0.00 KB (0.00%)
http-router.ts 36.24 KB 36.24 KB 0.00 KB (0.00%)
logger.ts 11.84 KB 11.84 KB 0.00 KB (0.00%)
metric.ts 9.38 KB 9.38 KB 0.00 KB (0.00%)
optic.ts 7.04 KB 7.04 KB 0.00 KB (0.00%)
pubsub.ts 15.91 KB 15.91 KB 0.00 KB (0.00%)
queue.ts 12.70 KB 12.70 KB 0.00 KB (0.00%)
schedule.ts 11.71 KB 11.71 KB 0.00 KB (0.00%)
schema-bigdecimal.ts 13.95 KB 13.95 KB 0.00 KB (0.00%)
schema-binary.ts 40.85 KB 40.85 KB 0.00 KB (0.00%)
schema-class.ts 21.45 KB 21.45 KB 0.00 KB (0.00%)
schema-fromJsonSchemaDocument.ts 32.51 KB 32.51 KB 0.00 KB (0.00%)
schema-representation-roundtrip.ts 27.69 KB 27.69 KB 0.00 KB (0.00%)
schema-string-transformation.ts 15.20 KB 15.20 KB 0.00 KB (0.00%)
schema-string.ts 12.20 KB 12.20 KB 0.00 KB (0.00%)
schema-template-literal.ts 16.14 KB 16.14 KB 0.00 KB (0.00%)
schema-toArbitrary.ts 38.76 KB 38.76 KB 0.00 KB (0.00%)
schema-toCodeDocument.ts 25.85 KB 25.85 KB 0.00 KB (0.00%)
schema-toCodecJson.ts 20.73 KB 20.73 KB 0.00 KB (0.00%)
schema-toEquivalence.ts 20.88 KB 20.88 KB 0.00 KB (0.00%)
schema-toFormatter.ts 20.98 KB 20.98 KB 0.00 KB (0.00%)
schema-toJsonSchemaDocument.ts 25.61 KB 25.61 KB 0.00 KB (0.00%)
schema-toRepresentation.ts 20.97 KB 20.97 KB 0.00 KB (0.00%)
schema.ts 20.65 KB 20.65 KB 0.00 KB (0.00%)
stm.ts 14.04 KB 14.04 KB 0.00 KB (0.00%)
stream.ts 10.26 KB 10.26 KB 0.00 KB (0.00%)

@tim-smart
tim-smart merged commit 39da87a into Effect-TS:main Oct 23, 2026
10 of 11 checks passed

This branch is waiting to be deployed

1 waiting deployment
fork — b993f06e Waiting Oct 23, 2026 by effect-bot via approval-gate #22844
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.

3 participants