@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.
@@ -1,2 +1,2 @@
1
- export declare const version = "1.0.0-rc.3";
1
+ export declare const version = "1.0.0-rc.4";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.version = void 0;
4
- exports.version = '1.0.0-rc.3';
4
+ exports.version = '1.0.0-rc.4';
5
5
  //# sourceMappingURL=version.js.map
@@ -1,2 +1,2 @@
1
- export declare const version = "1.0.0-rc.3";
1
+ export declare const version = "1.0.0-rc.4";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,2 +1,2 @@
1
- export const version = '1.0.0-rc.3';
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",
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
+ }