Skip to content

Commit f0a3691

Browse files
committed
feat: postgrest-js@1
1 parent 801bfd1 commit f0a3691

File tree

5 files changed

+95
-65
lines changed

5 files changed

+95
-65
lines changed

package-lock.json

Lines changed: 9 additions & 9 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": "^1.3.3",
4141
"@supabase/gotrue-js": "^1.23.0-next.3",
42-
"@supabase/postgrest-js": "^0.37.2",
42+
"@supabase/postgrest-js": "^1.0.0-next.2",
4343
"@supabase/realtime-js": "^1.7.2",
4444
"@supabase/storage-js": "^1.7.0",
4545
"cross-fetch": "^3.1.5"

src/SupabaseClient.ts

Lines changed: 50 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import { FunctionsClient } from '@supabase/functions-js'
22
import { AuthChangeEvent } from '@supabase/gotrue-js'
3-
import { PostgrestClient, PostgrestQueryBuilder } from '@supabase/postgrest-js'
3+
import {
4+
PostgrestClient,
5+
PostgrestFilterBuilder,
6+
PostgrestQueryBuilder,
7+
} from '@supabase/postgrest-js'
48
import { RealtimeChannel, RealtimeClient, RealtimeClientOptions } from '@supabase/realtime-js'
59
import { SupabaseStorageClient } from '@supabase/storage-js'
610
import { DEFAULT_HEADERS, STORAGE_KEY } from './lib/constants'
711
import { fetchWithAuth } from './lib/fetch'
812
import { isBrowser, stripTrailingSlash } from './lib/helpers'
913
import { SupabaseAuthClient } from './lib/SupabaseAuthClient'
1014
import { SupabaseRealtimeClient } from './lib/SupabaseRealtimeClient'
11-
import { Fetch, SupabaseClientOptions } from './lib/types'
15+
import { Fetch, GenericSchema, SupabaseClientOptions } from './lib/types'
1216

1317
const DEFAULT_OPTIONS = {
1418
schema: 'public',
@@ -24,19 +28,26 @@ const DEFAULT_OPTIONS = {
2428
*
2529
* An isomorphic Javascript client for interacting with Postgres.
2630
*/
27-
export default class SupabaseClient {
31+
export default class SupabaseClient<
32+
Database = any,
33+
SchemaName extends string & keyof Database = 'public' extends keyof Database
34+
? 'public'
35+
: string & keyof Database,
36+
Schema extends GenericSchema = Database[SchemaName] extends GenericSchema
37+
? Database[SchemaName]
38+
: any
39+
> {
2840
/**
2941
* Supabase Auth allows you to create and manage user sessions for access to data that is secured by access policies.
3042
*/
3143
auth: SupabaseAuthClient
3244

33-
protected schema: string
34-
protected restUrl: string
3545
protected realtimeUrl: string
3646
protected authUrl: string
3747
protected storageUrl: string
3848
protected functionsUrl: string
3949
protected realtime: RealtimeClient
50+
protected rest: PostgrestClient<Database, SchemaName>
4051
protected multiTab: boolean
4152
protected fetch?: Fetch
4253
protected changedAccessToken: string | undefined
@@ -62,15 +73,14 @@ export default class SupabaseClient {
6273
constructor(
6374
protected supabaseUrl: string,
6475
protected supabaseKey: string,
65-
options?: SupabaseClientOptions
76+
options?: SupabaseClientOptions<SchemaName>
6677
) {
6778
if (!supabaseUrl) throw new Error('supabaseUrl is required.')
6879
if (!supabaseKey) throw new Error('supabaseKey is required.')
6980

7081
const _supabaseUrl = stripTrailingSlash(supabaseUrl)
7182
const settings = { ...DEFAULT_OPTIONS, ...options }
7283

73-
this.restUrl = `${_supabaseUrl}/rest/v1`
7484
this.realtimeUrl = `${_supabaseUrl}/realtime/v1`.replace('http', 'ws')
7585
this.authUrl = `${_supabaseUrl}/auth/v1`
7686
this.storageUrl = `${_supabaseUrl}/storage/v1`
@@ -83,15 +93,20 @@ export default class SupabaseClient {
8393
this.functionsUrl = `${_supabaseUrl}/functions/v1`
8494
}
8595

86-
this.schema = settings.schema
8796
this.multiTab = settings.multiTab
8897
this.headers = { ...DEFAULT_HEADERS, ...options?.headers }
8998
this.shouldThrowOnError = settings.shouldThrowOnError || false
9099

100+
this.fetch = fetchWithAuth(supabaseKey, this._getAccessToken.bind(this), settings.fetch)
101+
91102
this.auth = this._initSupabaseAuthClient(settings)
92103
this.realtime = this._initRealtimeClient({ headers: this.headers, ...settings.realtime })
93-
94-
this.fetch = fetchWithAuth(supabaseKey, this._getAccessToken.bind(this), settings.fetch)
104+
this.rest = new PostgrestClient(`${_supabaseUrl}/rest/v1`, {
105+
headers: this.headers,
106+
schema: options?.schema,
107+
fetch: this.fetch,
108+
throwOnError: this.shouldThrowOnError,
109+
})
95110

96111
this._listenForAuthEvents()
97112
this._listenForMultiTabEvents()
@@ -124,14 +139,11 @@ export default class SupabaseClient {
124139
*
125140
* @param table The table name to operate on.
126141
*/
127-
from<T = any>(table: string): PostgrestQueryBuilder<T> {
128-
const url = `${this.restUrl}/${table}`
129-
return new PostgrestQueryBuilder<T>(url, {
130-
headers: this.headers,
131-
schema: this.schema,
132-
fetch: this.fetch,
133-
shouldThrowOnError: this.shouldThrowOnError,
134-
})
142+
from<
143+
TableName extends string & keyof Schema['Tables'],
144+
Table extends Schema['Tables'][TableName]
145+
>(table: TableName): PostgrestQueryBuilder<Table> {
146+
return this.rest.from(table)
135147
}
136148

137149
/**
@@ -143,16 +155,25 @@ export default class SupabaseClient {
143155
* @param count Count algorithm to use to count rows in a table.
144156
*
145157
*/
146-
rpc<T = any>(
147-
fn: string,
148-
params?: object,
149-
{
150-
head = false,
151-
count = null,
152-
}: { head?: boolean; count?: null | 'exact' | 'planned' | 'estimated' } = {}
153-
) {
154-
const rest = this._initPostgRESTClient()
155-
return rest.rpc<T>(fn, params, { head, count })
158+
rpc<
159+
FunctionName extends string & keyof Schema['Functions'],
160+
Function_ extends Schema['Functions'][FunctionName]
161+
>(
162+
fn: FunctionName,
163+
args: Function_['Args'] = {},
164+
options?: {
165+
head?: boolean
166+
count?: 'exact' | 'planned' | 'estimated'
167+
}
168+
): PostgrestFilterBuilder<
169+
Function_['Returns'] extends any[]
170+
? Function_['Returns'][number] extends Record<string, unknown>
171+
? Function_['Returns'][number]
172+
: never
173+
: never,
174+
Function_['Returns']
175+
> {
176+
return this.rest.rpc(fn, args, options)
156177
}
157178

158179
/**
@@ -249,7 +270,7 @@ export default class SupabaseClient {
249270
fetch,
250271
cookieOptions,
251272
multiTab,
252-
}: SupabaseClientOptions) {
273+
}: SupabaseClientOptions<string>) {
253274
const authHeaders = {
254275
Authorization: `Bearer ${this.supabaseKey}`,
255276
apikey: `${this.supabaseKey}`,
@@ -274,15 +295,6 @@ export default class SupabaseClient {
274295
})
275296
}
276297

277-
private _initPostgRESTClient() {
278-
return new PostgrestClient(this.restUrl, {
279-
headers: this.headers,
280-
schema: this.schema,
281-
fetch: this.fetch,
282-
throwOnError: this.shouldThrowOnError,
283-
})
284-
}
285-
286298
private _listenForMultiTabEvents() {
287299
if (!this.multiTab || !isBrowser() || !window?.addEventListener) {
288300
return null

src/index.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,33 @@
11
import SupabaseClient from './SupabaseClient'
2-
import { SupabaseClientOptions, SupabaseRealtimePayload } from './lib/types'
3-
import { User as AuthUser, Session as AuthSession } from '@supabase/gotrue-js'
2+
import type { GenericSchema, SupabaseClientOptions } from './lib/types'
3+
44
export * from '@supabase/gotrue-js'
5-
export {
5+
export type { User as AuthUser, Session as AuthSession } from '@supabase/gotrue-js'
6+
export type {
67
PostgrestResponse,
78
PostgrestSingleResponse,
89
PostgrestMaybeSingleResponse,
910
PostgrestError,
1011
} from '@supabase/postgrest-js'
1112
export * from '@supabase/realtime-js'
13+
export { default as SupabaseClient } from './SupabaseClient'
14+
export type { SupabaseClientOptions, SupabaseRealtimePayload } from './lib/types'
1215

1316
/**
1417
* Creates a new Supabase Client.
1518
*/
16-
const createClient = (
19+
export const createClient = <
20+
Database = any,
21+
SchemaName extends string & keyof Database = 'public' extends keyof Database
22+
? 'public'
23+
: string & keyof Database,
24+
Schema extends GenericSchema = Database[SchemaName] extends GenericSchema
25+
? Database[SchemaName]
26+
: any
27+
>(
1728
supabaseUrl: string,
1829
supabaseKey: string,
19-
options?: SupabaseClientOptions
20-
): SupabaseClient => {
30+
options?: SupabaseClientOptions<SchemaName>
31+
): SupabaseClient<Database, SchemaName, Schema> => {
2132
return new SupabaseClient(supabaseUrl, supabaseKey, options)
2233
}
23-
24-
export {
25-
createClient,
26-
SupabaseClient,
27-
SupabaseClientOptions,
28-
SupabaseRealtimePayload,
29-
AuthUser,
30-
AuthSession,
31-
}

src/lib/types.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ export interface SupabaseAuthClientOptions extends GoTrueClientOptions {}
77

88
export type Fetch = typeof fetch
99

10-
export type SupabaseClientOptions = {
10+
export type SupabaseClientOptions<SchemaName> = {
1111
/**
1212
* The Postgres schema which your tables belong to. Must be on the list of exposed schemas in Supabase. Defaults to 'public'.
1313
*/
14-
schema?: string
14+
schema?: SchemaName
1515
/**
1616
* Optional headers for initializing the client.
1717
*/
@@ -69,3 +69,19 @@ export type SupabaseRealtimePayload<T> = {
6969
old: T
7070
errors: string[] | null
7171
}
72+
73+
export type GenericTable = {
74+
Row: Record<string, unknown>
75+
Insert: Record<string, unknown>
76+
Update: Record<string, unknown>
77+
}
78+
79+
export type GenericFunction = {
80+
Args: Record<string, unknown>
81+
Returns: unknown
82+
}
83+
84+
export type GenericSchema = {
85+
Tables: Record<string, GenericTable>
86+
Functions: Record<string, GenericFunction>
87+
}

0 commit comments

Comments
 (0)