-
-
Notifications
You must be signed in to change notification settings - Fork 158
/
Copy pathPostgrestClient.ts
157 lines (151 loc) · 4.56 KB
/
PostgrestClient.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import PostgrestQueryBuilder from './PostgrestQueryBuilder'
import PostgrestFilterBuilder from './PostgrestFilterBuilder'
import PostgrestBuilder from './PostgrestBuilder'
import { DEFAULT_HEADERS } from './constants'
import { Fetch, GenericSchema } from './types'
/**
* PostgREST client.
*
* @typeParam Database - Types for the schema from the [type
* generator](https://supabase.com/docs/reference/javascript/next/typescript-support)
*
* @typeParam SchemaName - Postgres schema to switch to. Must be a string
* literal, the same one passed to the constructor. If the schema is not
* `"public"`, this must be supplied manually.
*/
export default class PostgrestClient<
Database = any,
SchemaName extends string & keyof Database = 'public' extends keyof Database
? 'public'
: string & keyof Database,
Schema extends GenericSchema = Database[SchemaName] extends GenericSchema
? Database[SchemaName]
: any
> {
url: string
headers: Record<string, string>
schema?: SchemaName
fetch?: Fetch
// TODO: Add back shouldThrowOnError once we figure out the typings
/**
* Creates a PostgREST client.
*
* @param url - URL of the PostgREST endpoint
* @param options - Named parameters
* @param options.headers - Custom headers
* @param options.schema - Postgres schema to switch to
* @param options.fetch - Custom fetch
*/
constructor(
url: string,
{
headers = {},
schema,
fetch,
}: {
headers?: Record<string, string>
schema?: SchemaName
fetch?: Fetch
} = {}
) {
this.url = url
this.headers = { ...DEFAULT_HEADERS, ...headers }
this.schema = schema
this.fetch = fetch
}
/**
* Perform a query on a table or a view.
*
* @param relation - The table or view name to query
*/
from<
TableName extends string & keyof Schema['Tables'],
Table extends Schema['Tables'][TableName],
ThrowOnError
>(relation: TableName): PostgrestQueryBuilder<Schema, Table, ThrowOnError>
from<
ViewName extends string & keyof Schema['Views'],
View extends Schema['Views'][ViewName],
ThrowOnError
>(relation: ViewName): PostgrestQueryBuilder<Schema, View, ThrowOnError>
from(relation: string): PostgrestQueryBuilder<Schema, any, false>
from(relation: string): PostgrestQueryBuilder<Schema, any, false> {
const url = new URL(`${this.url}/${relation}`)
return new PostgrestQueryBuilder<Schema, any, false>(url, {
headers: { ...this.headers },
schema: this.schema,
fetch: this.fetch,
})
}
/**
* Perform a function call.
*
* @param fn - The function name to call
* @param args - The arguments to pass to the function call
* @param options - Named parameters
* @param options.head - When set to `true`, `data` will not be returned.
* Useful if you only need the count.
* @param options.count - Count algorithm to use to count rows returned by the
* function. Only applicable for [set-returning
* functions](https://www.postgresql.org/docs/current/functions-srf.html).
*
* `"exact"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the
* hood.
*
* `"planned"`: Approximated but fast count algorithm. Uses the Postgres
* statistics under the hood.
*
* `"estimated"`: Uses exact count for low numbers and planned count for high
* numbers.
*/
rpc<
FunctionName extends string & keyof Schema['Functions'],
Function_ extends Schema['Functions'][FunctionName],
ThrowOnError
>(
fn: FunctionName,
args: Function_['Args'] = {},
{
head = false,
count,
}: {
head?: boolean
count?: 'exact' | 'planned' | 'estimated'
} = {}
): PostgrestFilterBuilder<
Schema,
Function_['Returns'] extends any[]
? Function_['Returns'][number] extends Record<string, unknown>
? Function_['Returns'][number]
: never
: never,
Function_['Returns'],
ThrowOnError
> {
let method: 'HEAD' | 'POST'
const url = new URL(`${this.url}/rpc/${fn}`)
let body: unknown | undefined
if (head) {
method = 'HEAD'
Object.entries(args).forEach(([name, value]) => {
url.searchParams.append(name, `${value}`)
})
} else {
method = 'POST'
body = args
}
const headers = { ...this.headers }
if (count) {
headers['Prefer'] = `count=${count}`
}
return new PostgrestFilterBuilder({
method,
url,
headers,
schema: this.schema,
body,
fetch: this.fetch,
allowEmpty: false,
} as unknown as PostgrestBuilder<Function_['Returns'], ThrowOnError>)
}
}