Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dynamic schemas on a per-query basis #828

Merged
merged 1 commit into from
Aug 7, 2023
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
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"dependencies": {
"@supabase/functions-js": "^2.1.0",
"@supabase/gotrue-js": "^2.46.1",
"@supabase/postgrest-js": "^1.7.0",
"@supabase/postgrest-js": "^1.8.0",
"@supabase/realtime-js": "^2.7.3",
"@supabase/storage-js": "^2.5.1",
"cross-fetch": "^3.1.5"
Expand Down
18 changes: 18 additions & 0 deletions src/SupabaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,24 @@ export default class SupabaseClient<
return this.rest.from(relation)
}

/**
* Perform a query on a schema distinct from the default schema supplied via
* the `options.db.schema` constructor parameter.
*
* The schema needs to be on the list of exposed schemas inside Supabase.
*
* @param schema - The name of the schema to query
*/
schema<DynamicSchema extends string & keyof Database>(
schema: DynamicSchema
): PostgrestClient<
Database,
DynamicSchema,
Database[DynamicSchema] extends GenericSchema ? Database[DynamicSchema] : any
> {
return this.rest.schema<DynamicSchema>(schema)
}

/**
* Perform a function call.
*
Expand Down
2 changes: 1 addition & 1 deletion src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export type SupabaseClientOptions<SchemaName> = {
flowType?: SupabaseAuthClientOptions['flowType']
/**
* If debug messages for authentication client are emitted. Can be used to inspect the behavior of the library.
*/
*/
debug?: boolean
}
/**
Expand Down
10 changes: 10 additions & 0 deletions test/client.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { PostgrestClient } from '@supabase/postgrest-js'
import { createClient, SupabaseClient } from '../src/index'
import { Database } from './types'

const URL = 'http://localhost:3000'
const KEY = 'some.fake.key'
Expand Down Expand Up @@ -57,6 +59,14 @@ describe('Realtime url', () => {
})
})

describe('Dynamic schema', () => {
test('should swap schemas', async () => {
const client = createClient<Database>('HTTP://localhost:3000', KEY)
expect(client.schema('personal')).toBeInstanceOf(PostgrestClient)
expect(client.schema('personal').from('users').schema).toBe('personal')
})
})

// Socket should close when there are no open connections
// https://github.com/supabase/supabase-js/issues/44

Expand Down
201 changes: 201 additions & 0 deletions test/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
export type Json = string | number | boolean | null | { [key: string]: Json } | Json[]

export interface Database {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied from postgrest-js. Didn't bring over the the whole database setup that postgrest-js has, since that seems like a lot for this change.

personal: {
Tables: {
users: {
Row: {
age_range: unknown | null
data: Json | null
status: Database['public']['Enums']['user_status'] | null
username: string
}
Insert: {
age_range?: unknown | null
data?: Json | null
status?: Database['public']['Enums']['user_status'] | null
username: string
}
Update: {
age_range?: unknown | null
data?: Json | null
status?: Database['public']['Enums']['user_status'] | null
username?: string
}
Relationships: []
}
}
Views: {
[_ in never]: never
}
Functions: {
get_status: {
Args: {
name_param: string
}
Returns: Database['public']['Enums']['user_status']
}
}
Enums: {
user_status: 'ONLINE' | 'OFFLINE'
}
CompositeTypes: {
[_ in never]: never
}
}
public: {
Tables: {
channels: {
Row: {
data: Json | null
id: number
slug: string | null
}
Insert: {
data?: Json | null
id?: number
slug?: string | null
}
Update: {
data?: Json | null
id?: number
slug?: string | null
}
Relationships: []
}
messages: {
Row: {
channel_id: number
data: Json | null
id: number
message: string | null
username: string
}
Insert: {
channel_id: number
data?: Json | null
id?: number
message?: string | null
username: string
}
Update: {
channel_id?: number
data?: Json | null
id?: number
message?: string | null
username?: string
}
Relationships: [
{
foreignKeyName: 'messages_username_fkey'
columns: ['username']
referencedRelation: 'users'
referencedColumns: ['username']
},
{
foreignKeyName: 'messages_channel_id_fkey'
columns: ['channel_id']
referencedRelation: 'channels'
referencedColumns: ['id']
}
]
}
shops: {
Row: {
address: string | null
id: number
shop_geom: unknown | null
}
Insert: {
address?: string | null
id: number
shop_geom?: unknown | null
}
Update: {
address?: string | null
id?: number
shop_geom?: unknown | null
}
Relationships: []
}
users: {
Row: {
age_range: unknown | null
catchphrase: unknown | null
data: Json | null
status: Database['public']['Enums']['user_status'] | null
username: string
}
Insert: {
age_range?: unknown | null
catchphrase?: unknown | null
data?: Json | null
status?: Database['public']['Enums']['user_status'] | null
username: string
}
Update: {
age_range?: unknown | null
catchphrase?: unknown | null
data?: Json | null
status?: Database['public']['Enums']['user_status'] | null
username?: string
}
Relationships: []
}
}
Views: {
non_updatable_view: {
Row: {
username: string | null
}
}
updatable_view: {
Row: {
non_updatable_column: number | null
username: string | null
}
Insert: {
non_updatable_column?: never
username?: string | null
}
Update: {
non_updatable_column?: never
username?: string | null
}
}
}
Functions: {
get_status: {
Args: {
name_param: string
}
Returns: Database['public']['Enums']['user_status']
}
get_username_and_status: {
Args: {
name_param: string
}
Returns: {
username: string
status: Database['public']['Enums']['user_status']
}[]
}
offline_user: {
Args: {
name_param: string
}
Returns: Database['public']['Enums']['user_status']
}
void_func: {
Args: Record<PropertyKey, never>
Returns: undefined
}
}
Enums: {
user_status: 'ONLINE' | 'OFFLINE'
}
CompositeTypes: {
[_ in never]: never
}
}
}