Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/core/postgrest-js/src/PostgrestClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
Expand Down
21 changes: 17 additions & 4 deletions packages/core/postgrest-js/src/types/common/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ type RpcFunctionNotFound<FnName> = {
Relationships: null
}

type CrossSchemaError<TableRef extends string> = {
error: true
} & `Function returns SETOF from a different schema ('${TableRef}'). Use .overrideTypes<YourReturnType>() to specify the return type explicitly.`

export type GetRpcFunctionFilterBuilderByArgs<
Schema extends GenericSchema,
FnName extends string & keyof Schema['Functions'],
Expand Down Expand Up @@ -98,13 +102,20 @@ export type GetRpcFunctionFilterBuilderByArgs<
? // If we are dealing with an non-typed client everything is any
IsAny<Fn> 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<Schema>
? TablesAndViews<Schema>[Fn['SetofOptions']['to']]['Row']
: TablesAndViews<Schema>[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<string, unknown>
? Fn['Returns'][number]
: CrossSchemaError<Fn['SetofOptions']['to'] & string>
: Fn['Returns'] extends Record<string, unknown>
? Fn['Returns']
: CrossSchemaError<Fn['SetofOptions']['to'] & string>
: Fn['Returns'] extends any[]
? Fn['Returns'][number] extends Record<string, unknown>
? Fn['Returns'][number]
Expand All @@ -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
Expand Down
9 changes: 9 additions & 0 deletions packages/core/postgrest-js/test/override-types.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,3 +548,12 @@ const postgrest = new PostgrestClient<Database>(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<TypeEqual<typeof result.data, { id: string; user_id: string }[]>>(true)
}
12 changes: 12 additions & 0 deletions packages/core/postgrest-js/test/types.override.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ export type Database = MergeDeep<
}
}
}
Functions: {
get_public_users: {
Args: Record<PropertyKey, never>
Returns: { id: string; user_id: string }[]
SetofOptions: {
from: '*'
to: 'public.users'
isOneToOne: false
isSetofReturn: true
}
}
}
Views: {}
Enums: {}
CompositeTypes: {}
Expand Down
21 changes: 17 additions & 4 deletions packages/core/supabase-js/src/lib/rest/types/common/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ type RpcFunctionNotFound<FnName> = {
Relationships: null
}

type CrossSchemaError<TableRef extends string> = {
error: true
} & `Function returns SETOF from a different schema ('${TableRef}'). Use .overrideTypes<YourReturnType>() to specify the return type explicitly.`

export type GetRpcFunctionFilterBuilderByArgs<
Schema extends GenericSchema,
FnName extends string & keyof Schema['Functions'],
Expand Down Expand Up @@ -108,13 +112,20 @@ export type GetRpcFunctionFilterBuilderByArgs<
? // If we are dealing with an non-typed client everything is any
IsAny<Fn> 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<Schema>
? TablesAndViews<Schema>[Fn['SetofOptions']['to']]['Row']
: TablesAndViews<Schema>[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<string, unknown>
? Fn['Returns'][number]
: CrossSchemaError<Fn['SetofOptions']['to'] & string>
: Fn['Returns'] extends Record<string, unknown>
? Fn['Returns']
: CrossSchemaError<Fn['SetofOptions']['to'] & string>
: Fn['Returns'] extends any[]
? Fn['Returns'][number] extends Record<string, unknown>
? Fn['Returns'][number]
Expand All @@ -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
Expand Down