@supabase/postgrest-js 1.0.0-rc.3 → 1.0.0-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main/version.d.ts +1 -1
- package/dist/main/version.js +1 -1
- package/dist/module/version.d.ts +1 -1
- package/dist/module/version.js +1 -1
- package/package.json +3 -2
- package/src/PostgrestBuilder.ts +154 -0
- package/src/PostgrestClient.ts +124 -0
- package/src/PostgrestFilterBuilder.ts +431 -0
- package/src/PostgrestQueryBuilder.ts +235 -0
- package/src/PostgrestTransformBuilder.ts +204 -0
- package/src/constants.ts +2 -0
- package/src/index.ts +11 -0
- package/src/select-query-parser.ts +297 -0
- package/src/types.ts +61 -0
- package/src/version.ts +1 -0
package/dist/main/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version = "1.0.0-rc.
|
|
1
|
+
export declare const version = "1.0.0-rc.4";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/main/version.js
CHANGED
package/dist/module/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version = "1.0.0-rc.
|
|
1
|
+
export declare const version = "1.0.0-rc.4";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/module/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const version = '1.0.0-rc.
|
|
1
|
+
export const version = '1.0.0-rc.4';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supabase/postgrest-js",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.4",
|
|
4
4
|
"description": "Isomorphic PostgREST client",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"postgrest",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"author": "Supabase",
|
|
13
13
|
"files": [
|
|
14
|
-
"dist"
|
|
14
|
+
"dist",
|
|
15
|
+
"src"
|
|
15
16
|
],
|
|
16
17
|
"main": "dist/main/index.js",
|
|
17
18
|
"module": "dist/module/index.js",
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import crossFetch from 'cross-fetch'
|
|
2
|
+
|
|
3
|
+
import type { Fetch, PostgrestResponse } from './types'
|
|
4
|
+
|
|
5
|
+
export default abstract class PostgrestBuilder<Result>
|
|
6
|
+
implements PromiseLike<PostgrestResponse<Result>>
|
|
7
|
+
{
|
|
8
|
+
protected method: 'GET' | 'HEAD' | 'POST' | 'PATCH' | 'DELETE'
|
|
9
|
+
protected url: URL
|
|
10
|
+
protected headers: Record<string, string>
|
|
11
|
+
protected schema?: string
|
|
12
|
+
protected body?: unknown
|
|
13
|
+
protected shouldThrowOnError = false
|
|
14
|
+
protected signal?: AbortSignal
|
|
15
|
+
protected fetch: Fetch
|
|
16
|
+
protected allowEmpty: boolean
|
|
17
|
+
|
|
18
|
+
constructor(builder: PostgrestBuilder<Result>) {
|
|
19
|
+
this.method = builder.method
|
|
20
|
+
this.url = builder.url
|
|
21
|
+
this.headers = builder.headers
|
|
22
|
+
this.schema = builder.schema
|
|
23
|
+
this.body = builder.body
|
|
24
|
+
this.shouldThrowOnError = builder.shouldThrowOnError
|
|
25
|
+
this.signal = builder.signal
|
|
26
|
+
this.allowEmpty = builder.allowEmpty
|
|
27
|
+
|
|
28
|
+
if (builder.fetch) {
|
|
29
|
+
this.fetch = builder.fetch
|
|
30
|
+
} else if (typeof fetch === 'undefined') {
|
|
31
|
+
this.fetch = crossFetch
|
|
32
|
+
} else {
|
|
33
|
+
this.fetch = fetch
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* If there's an error with the query, throwOnError will reject the promise by
|
|
39
|
+
* throwing the error instead of returning it as part of a successful response.
|
|
40
|
+
*
|
|
41
|
+
* {@link https://github.com/supabase/supabase-js/issues/92}
|
|
42
|
+
*/
|
|
43
|
+
throwOnError(): this {
|
|
44
|
+
this.shouldThrowOnError = true
|
|
45
|
+
return this
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
then<TResult1 = PostgrestResponse<Result>, TResult2 = never>(
|
|
49
|
+
onfulfilled?:
|
|
50
|
+
| ((value: PostgrestResponse<Result>) => TResult1 | PromiseLike<TResult1>)
|
|
51
|
+
| undefined
|
|
52
|
+
| null,
|
|
53
|
+
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null
|
|
54
|
+
): PromiseLike<TResult1 | TResult2> {
|
|
55
|
+
// https://postgrest.org/en/stable/api.html#switching-schemas
|
|
56
|
+
if (typeof this.schema === 'undefined') {
|
|
57
|
+
// skip
|
|
58
|
+
} else if (['GET', 'HEAD'].includes(this.method)) {
|
|
59
|
+
this.headers['Accept-Profile'] = this.schema
|
|
60
|
+
} else {
|
|
61
|
+
this.headers['Content-Profile'] = this.schema
|
|
62
|
+
}
|
|
63
|
+
if (this.method !== 'GET' && this.method !== 'HEAD') {
|
|
64
|
+
this.headers['Content-Type'] = 'application/json'
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// NOTE: Invoke w/o `this` to avoid illegal invocation error.
|
|
68
|
+
// https://github.com/supabase/postgrest-js/pull/247
|
|
69
|
+
const _fetch = this.fetch
|
|
70
|
+
let res = _fetch(this.url.toString(), {
|
|
71
|
+
method: this.method,
|
|
72
|
+
headers: this.headers,
|
|
73
|
+
body: JSON.stringify(this.body),
|
|
74
|
+
signal: this.signal,
|
|
75
|
+
}).then(async (res) => {
|
|
76
|
+
let error = undefined
|
|
77
|
+
let data = undefined
|
|
78
|
+
let count = undefined
|
|
79
|
+
let status = res.status
|
|
80
|
+
let statusText = res.statusText
|
|
81
|
+
|
|
82
|
+
if (res.ok) {
|
|
83
|
+
const isReturnMinimal = this.headers['Prefer']?.split(',').includes('return=minimal')
|
|
84
|
+
if (this.method !== 'HEAD' && !isReturnMinimal) {
|
|
85
|
+
const text = await res.text()
|
|
86
|
+
if (!text) {
|
|
87
|
+
// discard `text`
|
|
88
|
+
} else if (this.headers['Accept'] === 'text/csv') {
|
|
89
|
+
data = text
|
|
90
|
+
} else if (
|
|
91
|
+
this.headers['Accept'] &&
|
|
92
|
+
this.headers['Accept'].indexOf('application/vnd.pgrst.plan+text') !== -1
|
|
93
|
+
) {
|
|
94
|
+
data = text
|
|
95
|
+
} else {
|
|
96
|
+
data = JSON.parse(text)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const countHeader = this.headers['Prefer']?.match(/count=(exact|planned|estimated)/)
|
|
101
|
+
const contentRange = res.headers.get('content-range')?.split('/')
|
|
102
|
+
if (countHeader && contentRange && contentRange.length > 1) {
|
|
103
|
+
count = parseInt(contentRange[1])
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
const body = await res.text()
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
error = JSON.parse(body)
|
|
110
|
+
} catch {
|
|
111
|
+
error = {
|
|
112
|
+
message: body,
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (error && this.allowEmpty && error?.details?.includes('Results contain 0 rows')) {
|
|
117
|
+
error = undefined
|
|
118
|
+
status = 200
|
|
119
|
+
statusText = 'OK'
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (error && this.shouldThrowOnError) {
|
|
123
|
+
throw error
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const postgrestResponse = {
|
|
128
|
+
error,
|
|
129
|
+
data,
|
|
130
|
+
count,
|
|
131
|
+
status,
|
|
132
|
+
statusText,
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return postgrestResponse
|
|
136
|
+
})
|
|
137
|
+
if (!this.shouldThrowOnError) {
|
|
138
|
+
res = res.catch((fetchError) => ({
|
|
139
|
+
error: {
|
|
140
|
+
message: `FetchError: ${fetchError.message}`,
|
|
141
|
+
details: '',
|
|
142
|
+
hint: '',
|
|
143
|
+
code: fetchError.code || '',
|
|
144
|
+
},
|
|
145
|
+
data: undefined,
|
|
146
|
+
count: undefined,
|
|
147
|
+
status: 400,
|
|
148
|
+
statusText: 'Bad Request',
|
|
149
|
+
}))
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return res.then(onfulfilled, onrejected)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import PostgrestQueryBuilder from './PostgrestQueryBuilder'
|
|
2
|
+
import PostgrestFilterBuilder from './PostgrestFilterBuilder'
|
|
3
|
+
import PostgrestBuilder from './PostgrestBuilder'
|
|
4
|
+
import { DEFAULT_HEADERS } from './constants'
|
|
5
|
+
import { Fetch, GenericSchema } from './types'
|
|
6
|
+
|
|
7
|
+
export default class PostgrestClient<
|
|
8
|
+
Database = any,
|
|
9
|
+
SchemaName extends string & keyof Database = 'public' extends keyof Database
|
|
10
|
+
? 'public'
|
|
11
|
+
: string & keyof Database,
|
|
12
|
+
Schema extends GenericSchema = Database[SchemaName] extends GenericSchema
|
|
13
|
+
? Database[SchemaName]
|
|
14
|
+
: any
|
|
15
|
+
> {
|
|
16
|
+
url: string
|
|
17
|
+
headers: Record<string, string>
|
|
18
|
+
schema?: SchemaName
|
|
19
|
+
fetch?: Fetch
|
|
20
|
+
|
|
21
|
+
// TODO: Add back shouldThrowOnError once we figure out the typings
|
|
22
|
+
/**
|
|
23
|
+
* Creates a PostgREST client.
|
|
24
|
+
*
|
|
25
|
+
* @param url URL of the PostgREST endpoint.
|
|
26
|
+
* @param headers Custom headers.
|
|
27
|
+
* @param schema Postgres schema to switch to.
|
|
28
|
+
*/
|
|
29
|
+
constructor(
|
|
30
|
+
url: string,
|
|
31
|
+
{
|
|
32
|
+
headers = {},
|
|
33
|
+
schema,
|
|
34
|
+
fetch,
|
|
35
|
+
}: {
|
|
36
|
+
headers?: Record<string, string>
|
|
37
|
+
schema?: SchemaName
|
|
38
|
+
fetch?: Fetch
|
|
39
|
+
} = {}
|
|
40
|
+
) {
|
|
41
|
+
this.url = url
|
|
42
|
+
this.headers = { ...DEFAULT_HEADERS, ...headers }
|
|
43
|
+
this.schema = schema
|
|
44
|
+
this.fetch = fetch
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Perform a table operation.
|
|
49
|
+
*
|
|
50
|
+
* @param table The table name to operate on.
|
|
51
|
+
*/
|
|
52
|
+
from<
|
|
53
|
+
TableName extends string & keyof Schema['Tables'],
|
|
54
|
+
Table extends Schema['Tables'][TableName]
|
|
55
|
+
>(table: TableName): PostgrestQueryBuilder<Table>
|
|
56
|
+
from(table: string): PostgrestQueryBuilder<any>
|
|
57
|
+
from(table: string): PostgrestQueryBuilder<any> {
|
|
58
|
+
const url = new URL(`${this.url}/${table}`)
|
|
59
|
+
return new PostgrestQueryBuilder<any>(url, {
|
|
60
|
+
headers: { ...this.headers },
|
|
61
|
+
schema: this.schema,
|
|
62
|
+
fetch: this.fetch,
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Perform a function call.
|
|
68
|
+
*
|
|
69
|
+
* @param fn The function name to call.
|
|
70
|
+
* @param args The parameters to pass to the function call.
|
|
71
|
+
* @param options Named parameters.
|
|
72
|
+
*/
|
|
73
|
+
rpc<
|
|
74
|
+
FunctionName extends string & keyof Schema['Functions'],
|
|
75
|
+
Function_ extends Schema['Functions'][FunctionName]
|
|
76
|
+
>(
|
|
77
|
+
fn: FunctionName,
|
|
78
|
+
args: Function_['Args'] = {},
|
|
79
|
+
{
|
|
80
|
+
head = false,
|
|
81
|
+
count,
|
|
82
|
+
}: {
|
|
83
|
+
/** When set to true, no data will be returned. */
|
|
84
|
+
head?: boolean
|
|
85
|
+
/** Count algorithm to use to count rows in a table. */
|
|
86
|
+
count?: 'exact' | 'planned' | 'estimated'
|
|
87
|
+
} = {}
|
|
88
|
+
): PostgrestFilterBuilder<
|
|
89
|
+
Function_['Returns'] extends any[]
|
|
90
|
+
? Function_['Returns'][number] extends Record<string, unknown>
|
|
91
|
+
? Function_['Returns'][number]
|
|
92
|
+
: never
|
|
93
|
+
: never,
|
|
94
|
+
Function_['Returns']
|
|
95
|
+
> {
|
|
96
|
+
let method: 'HEAD' | 'POST'
|
|
97
|
+
const url = new URL(`${this.url}/rpc/${fn}`)
|
|
98
|
+
let body: unknown | undefined
|
|
99
|
+
if (head) {
|
|
100
|
+
method = 'HEAD'
|
|
101
|
+
Object.entries(args).forEach(([name, value]) => {
|
|
102
|
+
url.searchParams.append(name, `${value}`)
|
|
103
|
+
})
|
|
104
|
+
} else {
|
|
105
|
+
method = 'POST'
|
|
106
|
+
body = args
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const headers = { ...this.headers }
|
|
110
|
+
if (count) {
|
|
111
|
+
headers['Prefer'] = `count=${count}`
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return new PostgrestFilterBuilder({
|
|
115
|
+
method,
|
|
116
|
+
url,
|
|
117
|
+
headers,
|
|
118
|
+
schema: this.schema,
|
|
119
|
+
body,
|
|
120
|
+
fetch: this.fetch,
|
|
121
|
+
allowEmpty: false,
|
|
122
|
+
} as unknown as PostgrestBuilder<Function_['Returns']>)
|
|
123
|
+
}
|
|
124
|
+
}
|