From 72de490d8b2083ed99384096249a177c0e6d5a64 Mon Sep 17 00:00:00 2001 From: 7ttp <117663341+7ttp@users.noreply.github.com> Date: Wed, 26 Nov 2025 23:31:48 +0530 Subject: [PATCH 1/2] fix(postgrest): cross-schema rpc setof type inference fall back to returns type when table is in different schema fixes supabase/supabase-js#1845 --- .../core/postgrest-js/src/PostgrestClient.ts | 9 ++++++++ .../core/postgrest-js/src/types/common/rpc.ts | 21 +++++++++++++++---- .../src/lib/rest/types/common/rpc.ts | 21 +++++++++++++++---- 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/packages/core/postgrest-js/src/PostgrestClient.ts b/packages/core/postgrest-js/src/PostgrestClient.ts index 6cefadd00..dbc11bc60 100644 --- a/packages/core/postgrest-js/src/PostgrestClient.ts +++ b/packages/core/postgrest-js/src/PostgrestClient.ts @@ -144,6 +144,15 @@ export default class PostgrestClient< * * `"estimated"`: Uses exact count for low numbers and planned count for high * numbers. + * + * @example + * ```ts + * // For cross-schema functions where type inference fails, use overrideTypes: + * const { data } = await supabase + * .schema('schema_b') + * .rpc('function_a', {}) + * .overrideTypes<{ id: string; user_id: string }[]>() + * ``` */ rpc< FnName extends string & keyof Schema['Functions'], diff --git a/packages/core/postgrest-js/src/types/common/rpc.ts b/packages/core/postgrest-js/src/types/common/rpc.ts index 52e57419a..ecbb768c0 100644 --- a/packages/core/postgrest-js/src/types/common/rpc.ts +++ b/packages/core/postgrest-js/src/types/common/rpc.ts @@ -62,6 +62,10 @@ type RpcFunctionNotFound = { Relationships: null } +type CrossSchemaError = { + error: true +} & `Function returns SETOF from a different schema ('${TableRef}'). Use .rpc() to specify the return type explicitly.` + export type GetRpcFunctionFilterBuilderByArgs< Schema extends GenericSchema, FnName extends string & keyof Schema['Functions'], @@ -98,13 +102,20 @@ export type GetRpcFunctionFilterBuilderByArgs< ? // If we are dealing with an non-typed client everything is any IsAny extends true ? { Row: any; Result: any; RelationName: FnName; Relationships: null } - : // Otherwise, we use the arguments based function definition narrowing to get the rigt value + : // Otherwise, we use the arguments based function definition narrowing to get the right value Fn extends GenericFunction ? { Row: Fn['SetofOptions'] extends GenericSetofOption - ? Fn['SetofOptions']['isSetofReturn'] extends true + ? Fn['SetofOptions']['to'] extends keyof TablesAndViews ? TablesAndViews[Fn['SetofOptions']['to']]['Row'] - : TablesAndViews[Fn['SetofOptions']['to']]['Row'] + : // Cross-schema fallback: use Returns type when table is not in current schema + Fn['Returns'] extends any[] + ? Fn['Returns'][number] extends Record + ? Fn['Returns'][number] + : CrossSchemaError + : Fn['Returns'] extends Record + ? Fn['Returns'] + : CrossSchemaError : Fn['Returns'] extends any[] ? Fn['Returns'][number] extends Record ? Fn['Returns'][number] @@ -125,7 +136,9 @@ export type GetRpcFunctionFilterBuilderByArgs< Relationships: Fn['SetofOptions'] extends GenericSetofOption ? Fn['SetofOptions']['to'] extends keyof Schema['Tables'] ? Schema['Tables'][Fn['SetofOptions']['to']]['Relationships'] - : Schema['Views'][Fn['SetofOptions']['to']]['Relationships'] + : Fn['SetofOptions']['to'] extends keyof Schema['Views'] + ? Schema['Views'][Fn['SetofOptions']['to']]['Relationships'] + : null : null } : // If we failed to find the function by argument, we still pass with any but also add an overridable diff --git a/packages/core/supabase-js/src/lib/rest/types/common/rpc.ts b/packages/core/supabase-js/src/lib/rest/types/common/rpc.ts index fe457bded..974402d53 100644 --- a/packages/core/supabase-js/src/lib/rest/types/common/rpc.ts +++ b/packages/core/supabase-js/src/lib/rest/types/common/rpc.ts @@ -72,6 +72,10 @@ type RpcFunctionNotFound = { Relationships: null } +type CrossSchemaError = { + error: true +} & `Function returns SETOF from a different schema ('${TableRef}'). Use .rpc() to specify the return type explicitly.` + export type GetRpcFunctionFilterBuilderByArgs< Schema extends GenericSchema, FnName extends string & keyof Schema['Functions'], @@ -108,13 +112,20 @@ export type GetRpcFunctionFilterBuilderByArgs< ? // If we are dealing with an non-typed client everything is any IsAny extends true ? { Row: any; Result: any; RelationName: FnName; Relationships: null } - : // Otherwise, we use the arguments based function definition narrowing to get the rigt value + : // Otherwise, we use the arguments based function definition narrowing to get the right value Fn extends GenericFunction ? { Row: Fn['SetofOptions'] extends GenericSetofOption - ? Fn['SetofOptions']['isSetofReturn'] extends true + ? Fn['SetofOptions']['to'] extends keyof TablesAndViews ? TablesAndViews[Fn['SetofOptions']['to']]['Row'] - : TablesAndViews[Fn['SetofOptions']['to']]['Row'] + : // Cross-schema fallback: use Returns type when table is not in current schema + Fn['Returns'] extends any[] + ? Fn['Returns'][number] extends Record + ? Fn['Returns'][number] + : CrossSchemaError + : Fn['Returns'] extends Record + ? Fn['Returns'] + : CrossSchemaError : Fn['Returns'] extends any[] ? Fn['Returns'][number] extends Record ? Fn['Returns'][number] @@ -135,7 +146,9 @@ export type GetRpcFunctionFilterBuilderByArgs< Relationships: Fn['SetofOptions'] extends GenericSetofOption ? Fn['SetofOptions']['to'] extends keyof Schema['Tables'] ? Schema['Tables'][Fn['SetofOptions']['to']]['Relationships'] - : Schema['Views'][Fn['SetofOptions']['to']]['Relationships'] + : Fn['SetofOptions']['to'] extends keyof Schema['Views'] + ? Schema['Views'][Fn['SetofOptions']['to']]['Relationships'] + : null : null } : // If we failed to find the function by argument, we still pass with any but also add an overridable From c2556668ca3614e8425ee46bb1ea75d06200608f Mon Sep 17 00:00:00 2001 From: 7ttp <117663341+7ttp@users.noreply.github.com> Date: Wed, 3 Dec 2025 15:49:32 +0530 Subject: [PATCH 2/2] chore(postgrest): update cross-schema error message and add type test --- packages/core/postgrest-js/src/types/common/rpc.ts | 2 +- .../core/postgrest-js/test/override-types.test-d.ts | 9 +++++++++ packages/core/postgrest-js/test/types.override.ts | 12 ++++++++++++ .../supabase-js/src/lib/rest/types/common/rpc.ts | 2 +- 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/core/postgrest-js/src/types/common/rpc.ts b/packages/core/postgrest-js/src/types/common/rpc.ts index ecbb768c0..f9b789211 100644 --- a/packages/core/postgrest-js/src/types/common/rpc.ts +++ b/packages/core/postgrest-js/src/types/common/rpc.ts @@ -64,7 +64,7 @@ type RpcFunctionNotFound = { type CrossSchemaError = { error: true -} & `Function returns SETOF from a different schema ('${TableRef}'). Use .rpc() to specify the return type explicitly.` +} & `Function returns SETOF from a different schema ('${TableRef}'). Use .overrideTypes() to specify the return type explicitly.` export type GetRpcFunctionFilterBuilderByArgs< Schema extends GenericSchema, diff --git a/packages/core/postgrest-js/test/override-types.test-d.ts b/packages/core/postgrest-js/test/override-types.test-d.ts index c144ad498..367e25b76 100644 --- a/packages/core/postgrest-js/test/override-types.test-d.ts +++ b/packages/core/postgrest-js/test/override-types.test-d.ts @@ -548,3 +548,12 @@ const postgrest = new PostgrestClient(REST_URL) > >(true) } + +// Test cross-schema rpc falls back to Returns type +{ + const result = await postgrest.schema('personal').rpc('get_public_users', {}) + if (result.error) { + throw new Error(result.error.message) + } + expectType>(true) +} diff --git a/packages/core/postgrest-js/test/types.override.ts b/packages/core/postgrest-js/test/types.override.ts index 1f6568eb0..df1047891 100644 --- a/packages/core/postgrest-js/test/types.override.ts +++ b/packages/core/postgrest-js/test/types.override.ts @@ -32,6 +32,18 @@ export type Database = MergeDeep< } } } + Functions: { + get_public_users: { + Args: Record + Returns: { id: string; user_id: string }[] + SetofOptions: { + from: '*' + to: 'public.users' + isOneToOne: false + isSetofReturn: true + } + } + } Views: {} Enums: {} CompositeTypes: {} diff --git a/packages/core/supabase-js/src/lib/rest/types/common/rpc.ts b/packages/core/supabase-js/src/lib/rest/types/common/rpc.ts index 974402d53..25285efe2 100644 --- a/packages/core/supabase-js/src/lib/rest/types/common/rpc.ts +++ b/packages/core/supabase-js/src/lib/rest/types/common/rpc.ts @@ -74,7 +74,7 @@ type RpcFunctionNotFound = { type CrossSchemaError = { error: true -} & `Function returns SETOF from a different schema ('${TableRef}'). Use .rpc() to specify the return type explicitly.` +} & `Function returns SETOF from a different schema ('${TableRef}'). Use .overrideTypes() to specify the return type explicitly.` export type GetRpcFunctionFilterBuilderByArgs< Schema extends GenericSchema,