Skip to content

Commit 90bd357

Browse files
sjones6soedirgo
authored andcommitted
feat: enable dynamic schema selection on a per-query basis
Resolves supabase/postgrest-js#280
1 parent c07ce23 commit 90bd357

File tree

6 files changed

+235
-6
lines changed

6 files changed

+235
-6
lines changed

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
"dependencies": {
4040
"@supabase/functions-js": "^2.1.0",
4141
"@supabase/gotrue-js": "^2.46.1",
42-
"@supabase/postgrest-js": "^1.7.0",
42+
"@supabase/postgrest-js": "^1.8.0",
4343
"@supabase/realtime-js": "^2.7.3",
4444
"@supabase/storage-js": "^2.5.1",
4545
"cross-fetch": "^3.1.5"

src/SupabaseClient.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,24 @@ export default class SupabaseClient<
160160
return this.rest.from(relation)
161161
}
162162

163+
/**
164+
* Perform a query on a schema distinct from the default schema supplied via
165+
* the `options.db.schema` constructor parameter.
166+
*
167+
* The schema needs to be on the list of exposed schemas inside Supabase.
168+
*
169+
* @param schema - The name of the schema to query
170+
*/
171+
schema<DynamicSchema extends string & keyof Database>(
172+
schema: DynamicSchema
173+
): PostgrestClient<
174+
Database,
175+
DynamicSchema,
176+
Database[DynamicSchema] extends GenericSchema ? Database[DynamicSchema] : any
177+
> {
178+
return this.rest.schema<DynamicSchema>(schema)
179+
}
180+
163181
/**
164182
* Perform a function call.
165183
*

src/lib/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export type SupabaseClientOptions<SchemaName> = {
4242
flowType?: SupabaseAuthClientOptions['flowType']
4343
/**
4444
* If debug messages for authentication client are emitted. Can be used to inspect the behavior of the library.
45-
*/
45+
*/
4646
debug?: boolean
4747
}
4848
/**

test/client.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import { PostgrestClient } from '@supabase/postgrest-js'
12
import { createClient, SupabaseClient } from '../src/index'
3+
import { Database } from './types'
24

35
const URL = 'http://localhost:3000'
46
const KEY = 'some.fake.key'
@@ -57,6 +59,14 @@ describe('Realtime url', () => {
5759
})
5860
})
5961

62+
describe('Dynamic schema', () => {
63+
test('should swap schemas', async () => {
64+
const client = createClient<Database>('HTTP://localhost:3000', KEY)
65+
expect(client.schema('personal')).toBeInstanceOf(PostgrestClient)
66+
expect(client.schema('personal').from('users').schema).toBe('personal')
67+
})
68+
})
69+
6070
// Socket should close when there are no open connections
6171
// https://github.com/supabase/supabase-js/issues/44
6272

test/types.ts

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
export type Json = string | number | boolean | null | { [key: string]: Json } | Json[]
2+
3+
export interface Database {
4+
personal: {
5+
Tables: {
6+
users: {
7+
Row: {
8+
age_range: unknown | null
9+
data: Json | null
10+
status: Database['public']['Enums']['user_status'] | null
11+
username: string
12+
}
13+
Insert: {
14+
age_range?: unknown | null
15+
data?: Json | null
16+
status?: Database['public']['Enums']['user_status'] | null
17+
username: string
18+
}
19+
Update: {
20+
age_range?: unknown | null
21+
data?: Json | null
22+
status?: Database['public']['Enums']['user_status'] | null
23+
username?: string
24+
}
25+
Relationships: []
26+
}
27+
}
28+
Views: {
29+
[_ in never]: never
30+
}
31+
Functions: {
32+
get_status: {
33+
Args: {
34+
name_param: string
35+
}
36+
Returns: Database['public']['Enums']['user_status']
37+
}
38+
}
39+
Enums: {
40+
user_status: 'ONLINE' | 'OFFLINE'
41+
}
42+
CompositeTypes: {
43+
[_ in never]: never
44+
}
45+
}
46+
public: {
47+
Tables: {
48+
channels: {
49+
Row: {
50+
data: Json | null
51+
id: number
52+
slug: string | null
53+
}
54+
Insert: {
55+
data?: Json | null
56+
id?: number
57+
slug?: string | null
58+
}
59+
Update: {
60+
data?: Json | null
61+
id?: number
62+
slug?: string | null
63+
}
64+
Relationships: []
65+
}
66+
messages: {
67+
Row: {
68+
channel_id: number
69+
data: Json | null
70+
id: number
71+
message: string | null
72+
username: string
73+
}
74+
Insert: {
75+
channel_id: number
76+
data?: Json | null
77+
id?: number
78+
message?: string | null
79+
username: string
80+
}
81+
Update: {
82+
channel_id?: number
83+
data?: Json | null
84+
id?: number
85+
message?: string | null
86+
username?: string
87+
}
88+
Relationships: [
89+
{
90+
foreignKeyName: 'messages_username_fkey'
91+
columns: ['username']
92+
referencedRelation: 'users'
93+
referencedColumns: ['username']
94+
},
95+
{
96+
foreignKeyName: 'messages_channel_id_fkey'
97+
columns: ['channel_id']
98+
referencedRelation: 'channels'
99+
referencedColumns: ['id']
100+
}
101+
]
102+
}
103+
shops: {
104+
Row: {
105+
address: string | null
106+
id: number
107+
shop_geom: unknown | null
108+
}
109+
Insert: {
110+
address?: string | null
111+
id: number
112+
shop_geom?: unknown | null
113+
}
114+
Update: {
115+
address?: string | null
116+
id?: number
117+
shop_geom?: unknown | null
118+
}
119+
Relationships: []
120+
}
121+
users: {
122+
Row: {
123+
age_range: unknown | null
124+
catchphrase: unknown | null
125+
data: Json | null
126+
status: Database['public']['Enums']['user_status'] | null
127+
username: string
128+
}
129+
Insert: {
130+
age_range?: unknown | null
131+
catchphrase?: unknown | null
132+
data?: Json | null
133+
status?: Database['public']['Enums']['user_status'] | null
134+
username: string
135+
}
136+
Update: {
137+
age_range?: unknown | null
138+
catchphrase?: unknown | null
139+
data?: Json | null
140+
status?: Database['public']['Enums']['user_status'] | null
141+
username?: string
142+
}
143+
Relationships: []
144+
}
145+
}
146+
Views: {
147+
non_updatable_view: {
148+
Row: {
149+
username: string | null
150+
}
151+
}
152+
updatable_view: {
153+
Row: {
154+
non_updatable_column: number | null
155+
username: string | null
156+
}
157+
Insert: {
158+
non_updatable_column?: never
159+
username?: string | null
160+
}
161+
Update: {
162+
non_updatable_column?: never
163+
username?: string | null
164+
}
165+
}
166+
}
167+
Functions: {
168+
get_status: {
169+
Args: {
170+
name_param: string
171+
}
172+
Returns: Database['public']['Enums']['user_status']
173+
}
174+
get_username_and_status: {
175+
Args: {
176+
name_param: string
177+
}
178+
Returns: {
179+
username: string
180+
status: Database['public']['Enums']['user_status']
181+
}[]
182+
}
183+
offline_user: {
184+
Args: {
185+
name_param: string
186+
}
187+
Returns: Database['public']['Enums']['user_status']
188+
}
189+
void_func: {
190+
Args: Record<PropertyKey, never>
191+
Returns: undefined
192+
}
193+
}
194+
Enums: {
195+
user_status: 'ONLINE' | 'OFFLINE'
196+
}
197+
CompositeTypes: {
198+
[_ in never]: never
199+
}
200+
}
201+
}

0 commit comments

Comments
 (0)