Repository navigation
feat(typegen): generate typed RPC methods from rpcFunctions - #1959
Merged
Merged
Conversation
`PostgrestClient.rpc`, `SupabaseClient.rpc` and `SupabaseQuerySchema.rpc` are getters returning a `PostgrestRpc`. Calling it makes the same untyped call as before; its `rows` and `value` methods are the typed entry points the extension methods `supabase_typegen` generates are built on. Both go through the typed request and executor, so a function returning rows keeps `where`, `order`, `limit`, `selectOnly`, `single()` and `count()`. SDK-1836
Contributor
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configuration
📒 Files selected for processing: 28
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…meters `head()` on a typed function call switched the POST to a HEAD, which carries no body, so the arguments were dropped and PostgREST resolved another overload or none. They are now sent as query parameters, the way an untyped `get` call sends them. The executor renders a function call as one more case of `_operation`, and selects the columns of its rows through the shared mutation rule instead of a special case of its own. SDK-1836
Reads the `rpcFunctions` collection postgrest-typegen 0.5.0 attaches to GeneratorMetadata and generates an extension method on `PostgrestRpc` for every function PostgREST exposes, `client.rpc.searchBooks(query: 'dart')`. The introspection port moves to postgrest-typegen/v0.5.0 and gains a Dart port of `resolveRpcFunctions`, so the direct connection modes emit the collection too and documents predating it still generate. The fixture is regenerated with RPC functions covering every result shape. SDK-2232
A database function named like a lowercase core type (`int`) or a codec (`postgrest_bytea`) generated a method that shadowed it inside the extension, and a RETURNS TABLE column named like a codec a getter that shadowed it in the row type; both no longer compile, so those names are reserved. An overload taking the unnamed json body is named `…WithBody` instead of `…With$`. A function returning a single row resolves to a nullable row: PostgREST answers one that finds no row with an object whose every column is null, which now reads as `null` instead of a row whose getters throw. SDK-2232
spydon
force-pushed
the
lukasklingsbo/sdk-2232-typed-rpc-generation
branch
from
October 14, 2026 15:24
1f51636 to
378fc6e
Compare
spydon
added a commit
that referenced
this pull request
Oct 15, 2026
…nts (#1958) Linear: SDK-1836 ## Why The typed surface covers tables (`client.table(Books.table)`) but not Postgres functions: `rpc<T>()` leaves `T` free and decodes with an unchecked cast. `supabase_typegen` can now resolve every callable function from postgrest-typegen 0.5.0's `rpcFunctions`, so it needs a runtime to generate against. The call site we settled on is `client.rpc.searchBooks(query: 'dart')`, generated extension methods on whatever `rpc` returns. ## What - **`rpc` is a getter** on `PostgrestClient`, `SupabaseClient` and `SupabaseQuerySchema`, returning a `PostgrestRpc`. `PostgrestRpc.call` makes the same untyped call as before, so `client.rpc('fn', params: {...})` and `client.rpc<int>('fn')` compile unchanged. - **Typed entry points** the generated code builds on: - `rows(function, arguments:, rowFromJson:, schema:)` returns a `PostgrestTypedFilterBuilder<Row, List<Row>>`, so `where`, `order`, `limit`, `range`, `selectOnly`, `single()` and `count()` work on the returned rows with the column tokens of the row type. - `value(function, arguments:, fromJson:, schema:)` returns a `PostgrestTypedBuilder<T>` for scalars, single rows, sets of scalars and `void`. - **`head()`** on a typed call sends the arguments as query parameters, since a HEAD request carries no body. - **Schema:** a typed call addresses the schema it is given, like a `PostgrestTable` does; a client scoped with `.schema()` wins. - **Executor:** both go through the typed request and executor as a new internal `PostgrestTableOperation.rpc` (plus a `PostgrestResultShape.value`), one more case of the executor's `_operation`, rendered through the untyped rpc builder so the wire request matches an untyped call. Both types stay hidden from the public API. `isMutation` is `true` for a function call, since nothing on the client says whether it writes, so a trailing `select`/`selectOnly` goes through the same rule as after a mutation. - `MIGRATION.md` covers the one break: passing `rpc` itself around as a function. `sdk-compliance.yaml` registers `PostgrestRpc` and its members under `database.query.rpc`. ## Tests - `typed_rpc_test.dart`: the untyped call through the getter (params, type argument, GET, scoped schema), and `rows`/`value` with filters, ordering, limits, `selectOnly`, `single()`, `count()`, schema precedence and request options. - `typed_rpc_integration_test.dart` against the local stack: `RETURNS TABLE` rows filtered and ordered, `selectOnly` plus `single()`, `count()`, scalars, a `NULL` result, `void`, array arguments and a function in another schema. - `postgrest` (613) and `supabase` (242) suites pass locally; DCM reports no warnings; the compliance symbol, drift and schema checks pass against the pinned capability matrix. Follow-up: #1959, which generates the extension methods. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Database function calls now support typed row and value results, including filtering, ordering, column selection, and schema-specific calls. * Function results can be decoded into application-defined types, including scalar and nullable values. * RPC access is available through an object that supports both regular and typed calls. * **Documentation** * Added migration guidance: calling RPC access remains supported, but passing it directly as a function no longer compiles. Wrap it in a closure instead. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Base automatically changed from
lukasklingsbo/sdk-1836-typed-rpc-entry-point
to
main
October 15, 2026 13:05
spydon
added a commit
that referenced
this pull request
Oct 16, 2026
…ity matrix to v1.16.0 (#1964) Linear: SDK-2258 ## Why `database.generated_types.typed_queries` and `database.generated_types.typed_rpc` were added to the capability matrix in supabase/sdk#276, released in capability-matrix v1.16.0. Both are already implemented here: typed tables through `table()`, and typed function calls through `PostgrestRpc.rows`/`PostgrestRpc.value` (#1958, generated by #1959). They show up as unregistered rather than missing. ## What - Bumps the supabase/sdk pins in `validate-capabilities.yml` and `sync-compliance.yml` from v1.15.0 to v1.16.0, the first tag that defines the two IDs. The reusable workflows are unchanged between the tags. - Registers `database.generated_types.typed_queries` with `PostgrestClient.table`, `SupabaseClient.table` and `SupabaseQuerySchema.table` as entry points and the typed builders plus `PostgrestTable` as supporting symbols. - Registers `database.generated_types.typed_rpc` with `PostgrestRpc.rows` and `PostgrestRpc.value` as entry points. ## Verification Against a supabase/sdk checkout at `capability-matrix/v1.16.0`: `validate-compliance`, `check-drift` and `check-api-symbols` all pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linear: SDK-2232. Stacked on #1958.
Why
postgrest-typegen 0.5.0 resolves which functions PostgREST exposes under
/rpc, how their overloads group and what a call returns intoGeneratorMetadata.rpcFunctions(supabase/sdk#271). With thePostgrestRpcruntime from #1958,supabase_typegencan now generate a typed method for every function instead of leavingrpcuntyped.What
DatabaseFunctions on PostgrestRpc, with a method per callable overload. Arguments are named parameters, optional where the function declares a default, converted to the wire the same way insert values are (enums, dates, timestamps, ranges,bytea, vectors, arrays, row values).PostgrestTypedFilterBuilder<BooksRow, List<BooksRow>>, filterable with that table's column tokens.RETURNS TABLE (…)function gets its own row type and column tokens (AuthorBookCountsRow,AuthorBookCounts.bookCount), every column nullable.null. Scalars and sets of scalars come back converted and nullable,voidtovoid, anything else toObject?.publiccarry the schema as a prefix (inventoryRestock). Of overloads, the one with the fewest arguments keeps the plain name and the others spell out their arguments (booksOfWithAuthorNameAndMaxPrice). Names stay clear ofPostgrestRpc's own members (call,rows,value), the core types the bodies name (int,num, …) and the codecs they call, and an overload taking the unnamed json body is named…WithBody.error), or one taking an unnamed parameter other than a solejson/jsonbone. Each gets a line in the extension's doc comment saying why, except computed fields and relationships, which stay reachable through their table.postgrest-typegen/v0.5.0. The SQL is unchanged;rpc_functions.dartportsresolveRpcFunctions,introspectattaches its result andsortGeneratorMetadataorders it. The parser readsrpcFunctionsand falls back to the port for documents that predate it. The port already carries the fixes of fix(postgrest-typegen): narrow the computed-field fallback and key RPC groups safely sdk#272 (no dot-joined keys, narrower computed-field fallback).Deviation from the TypeScript resolver
The resolver treats a sole unnamed row parameter as callable when the function returns rows (
recent_books(public.authors)), but PostgREST answers that call withPGRST202. The port keeps the upstream semantics so it stays byte-identical to 0.5.0, and the generator refuses that case itself. Upstream fix tracked in SDK-2231.Tests
rpc_functions_test.dart: the Dart resolver reproduces the TypeScriptrpcFunctionsof the fixture exactly, plus callable filtering, input modes,RETURNS TABLEcolumns,setof_options, computed fields, both conflict errors, overload order and schema keys with dots.typed_dataimport; the generated methods are exercised throughMockSupabaseHttpClientfor the wire request and the conversions.seed.sqlgains functions covering each shape; the fixture is regenerated with postgrest-typegen v0.5.0 (insertions only, existing object ids unchanged) and the hostile fixture gains functions namedcall,rows,classandmap.postgres:15. The generated golden was also run end to end against a real PostgREST on the fixture database, every method included.main's text, which the SDK formatter accepts unchanged.