fix(typegen): only collapse ROWS 1 return types when SetofOptions is emitted - #1096
Conversation
E2E verification against postgrest-jsI ran the cross-repo check locally: built two pg-meta images — one from this PR's merge-base (e7d86a3) and one from this branch — pinned each into the postgrest-js test stack, regenerated types for the postgrest-js test database with both, and compared against PostgREST's actual runtime responses. 1. No change to postgrest-js's existing type surface
This is expected: all three 2. For the broken shapes, the new types match runtime; the old ones don'tAdded the affected shapes to the live test DB and called them through PostgREST:
Neither shape emits 3. postgrest-js type suite (tstyche)
That failure is pre-existing drift, not this PR: it reproduces identically with the unmodified merge-base image. The committed Reproduction steps# 1. Build both images so the Supabase CLI resolves them locally (checked before pulling)
git -C postgres-meta worktree add /tmp/pgmeta-base $(git -C postgres-meta merge-base HEAD master)
docker build postgres-meta -t public.ecr.aws/supabase/postgres-meta:rows1-pr
docker build /tmp/pgmeta-base -t public.ecr.aws/supabase/postgres-meta:rows1-base
# 2. In supabase-js/packages/core/postgrest-js: pin the image tag and start the stack
printf 'rows1-base' > test/supabase/.temp/pgmeta-version
pnpm exec supabase --workdir test start
# 3. Generate with each image (the pin is re-read per invocation)
pnpm exec supabase --workdir test gen types typescript --local --schema public,personal > /tmp/types-base.ts
printf 'rows1-pr' > test/supabase/.temp/pgmeta-version
pnpm exec supabase --workdir test gen types typescript --local --schema public,personal > /tmp/types-pr.ts
diff /tmp/types-base.ts /tmp/types-pr.ts # → identical
# 4. Runtime source of truth for the affected shapes
docker exec supabase_db_test psql -U postgres -c "
CREATE FUNCTION public.e2e_rows1_ad_hoc_table(prefix text)
RETURNS TABLE(id int, name text) LANGUAGE SQL STABLE ROWS 1
AS \$\$ SELECT 1, prefix || '_one' \$\$;
CREATE FUNCTION public.e2e_rows1_scalar_setof(prefix text)
RETURNS SETOF text LANGUAGE SQL STABLE ROWS 1
AS \$\$ SELECT prefix || '_scalar' \$\$;
NOTIFY pgrst, 'reload schema';"
curl -s http://127.0.0.1:54321/rest/v1/rpc/e2e_rows1_ad_hoc_table \
-X POST -H "apikey: $ANON" -H "Content-Type: application/json" -d '{"prefix":"hello"}'
# → [{"id":1,"name":"hello_one"}]
# 5. Type suite: swap regenerated types in, post-process, run tstyche
cp /tmp/types-pr.ts test/types.generated.ts
node scripts/update-json-type.js && pnpm exec prettier --write test/types.generated.ts
pnpm exec tstycheFollow-up regression tests for the ROWS 1 array contract on the SDK side are tracked in SDK-1383. |
avallete
left a comment
There was a problem hiding this comment.
Nice. I think we'll want the new tests to be added to postgrest-js against actual e2e postgrest runtime when this is merged and released. That way we don't get a regression on the behavior in the future 👍
Fixes supabase/supabase#46525.
The TypeScript typegen drops the
[]from the return type of every set-returning function declared withROWS 1, but the compensatingSetofOptionsmetadata is only emitted when the function returns a named table, view, or composite type. For ad-hocRETURNS TABLE (...)and scalarSETOFfunctions this produced a single-object type while PostgREST still returns an array at runtime, and there is no metadata for postgrest-js to correct it. The collapse is now gated on the same condition as theSetofOptionsemission, so those functions keep the array type, while named-relation functions (where postgrest-js restores the array for direct RPC calls viaisOneToOne) are unchanged.Note for consumers: regenerating types flips
Returnsfrom object to array for affected functions. The resulting type errors point at real runtime mismatches, since PostgREST has always returned an array for these calls.