|
1 |
| -import fetch from 'cross-fetch' |
2 |
| - |
3 |
| -/** |
4 |
| - * Error format |
5 |
| - * |
6 |
| - * {@link https://postgrest.org/en/stable/api.html?highlight=options#errors-and-http-status-codes} |
7 |
| - */ |
8 |
| -interface PostgrestError { |
9 |
| - message: string |
10 |
| - details: string |
11 |
| - hint: string |
12 |
| - code: string |
13 |
| -} |
14 |
| - |
15 |
| -/** |
16 |
| - * Response format |
17 |
| - * |
18 |
| - * {@link https://github.com/supabase/supabase-js/issues/32} |
19 |
| - */ |
20 |
| -interface PostgrestResponse<T> { |
21 |
| - error: PostgrestError | null |
22 |
| - data: T | T[] | null |
23 |
| - status: number |
24 |
| - statusText: string |
25 |
| - // For backward compatibility: body === data |
26 |
| - body: T | T[] | null |
27 |
| -} |
28 |
| - |
29 |
| -/** |
30 |
| - * Base builder |
31 |
| - */ |
32 |
| - |
33 |
| -export abstract class PostgrestBuilder<T> implements PromiseLike<any> { |
34 |
| - method!: 'GET' | 'HEAD' | 'POST' | 'PATCH' | 'DELETE' |
35 |
| - url!: URL |
36 |
| - headers!: { [key: string]: string } |
37 |
| - schema?: string |
38 |
| - body?: Partial<T> | Partial<T>[] |
39 |
| - |
40 |
| - constructor(builder: PostgrestBuilder<T>) { |
41 |
| - Object.assign(this, builder) |
42 |
| - } |
43 |
| - |
44 |
| - then(onfulfilled?: (value: any) => any, onrejected?: (value: any) => any): Promise<any> { |
45 |
| - // https://postgrest.org/en/stable/api.html#switching-schemas |
46 |
| - if (typeof this.schema === 'undefined') { |
47 |
| - // skip |
48 |
| - } else if (['GET', 'HEAD'].includes(this.method)) { |
49 |
| - this.headers['Accept-Profile'] = this.schema |
50 |
| - } else { |
51 |
| - this.headers['Content-Profile'] = this.schema |
52 |
| - } |
53 |
| - if (this.method !== 'GET' && this.method !== 'HEAD') { |
54 |
| - this.headers['Content-Type'] = 'application/json' |
55 |
| - } |
56 |
| - |
57 |
| - return fetch(this.url.toString(), { |
58 |
| - method: this.method, |
59 |
| - headers: this.headers, |
60 |
| - body: JSON.stringify(this.body), |
61 |
| - }) |
62 |
| - .then(async (res) => { |
63 |
| - let error, data |
64 |
| - if (res.ok) { |
65 |
| - error = null |
66 |
| - data = await res.json() |
67 |
| - } else { |
68 |
| - error = await res.json() |
69 |
| - data = null |
70 |
| - } |
71 |
| - return { |
72 |
| - error, |
73 |
| - data, |
74 |
| - status: res.status, |
75 |
| - statusText: res.statusText, |
76 |
| - body: data, |
77 |
| - } as PostgrestResponse<T> |
78 |
| - }) |
79 |
| - .then(onfulfilled, onrejected) |
80 |
| - } |
81 |
| -} |
82 |
| - |
83 |
| -/** |
84 |
| - * CRUD |
85 |
| - */ |
86 |
| - |
87 |
| -export class PostgrestQueryBuilder<T> extends PostgrestBuilder<T> { |
88 |
| - constructor( |
89 |
| - url: string, |
90 |
| - { headers = {}, schema }: { headers?: { [key: string]: string }; schema?: string } = {} |
91 |
| - ) { |
92 |
| - super({} as PostgrestBuilder<T>) |
93 |
| - this.url = new URL(url) |
94 |
| - this.headers = { ...headers } |
95 |
| - this.schema = schema |
96 |
| - } |
97 |
| - |
98 |
| - /** |
99 |
| - * Performs horizontal filtering with SELECT. |
100 |
| - * |
101 |
| - * @param columns The columns to retrieve, separated by commas. |
102 |
| - */ |
103 |
| - select(columns = '*'): PostgrestFilterBuilder<T> { |
104 |
| - this.method = 'GET' |
105 |
| - // Remove whitespaces except when quoted |
106 |
| - let quoted = false |
107 |
| - const cleanedColumns = columns |
108 |
| - .split('') |
109 |
| - .map((c) => { |
110 |
| - if (/\s/.test(c) && !quoted) { |
111 |
| - return '' |
112 |
| - } |
113 |
| - if (c === '"') { |
114 |
| - quoted = !quoted |
115 |
| - } |
116 |
| - return c |
117 |
| - }) |
118 |
| - .join('') |
119 |
| - this.url.searchParams.set('select', cleanedColumns) |
120 |
| - return new PostgrestFilterBuilder(this) |
121 |
| - } |
122 |
| - |
123 |
| - /** |
124 |
| - * Performs an INSERT into the table. |
125 |
| - * |
126 |
| - * @param values The values to insert. |
127 |
| - * @param upsert If `true`, performs an UPSERT. |
128 |
| - * @param onConflict By specifying the `on_conflict` query parameter, you can make UPSERT work on a column(s) that has a UNIQUE constraint. |
129 |
| - */ |
130 |
| - insert( |
131 |
| - values: Partial<T> | Partial<T>[], |
132 |
| - { upsert = false, onConflict }: { upsert?: boolean; onConflict?: string } = {} |
133 |
| - ): PostgrestFilterBuilder<T> { |
134 |
| - this.method = 'POST' |
135 |
| - this.headers['Prefer'] = upsert |
136 |
| - ? 'return=representation,resolution=merge-duplicates' |
137 |
| - : 'return=representation' |
138 |
| - if (upsert && onConflict !== undefined) this.url.searchParams.set('on_conflict', onConflict) |
139 |
| - this.body = values |
140 |
| - return new PostgrestFilterBuilder(this) |
141 |
| - } |
142 |
| - |
143 |
| - /** |
144 |
| - * Performs an UPDATE on the table. |
145 |
| - * |
146 |
| - * @param values The values to update. |
147 |
| - */ |
148 |
| - update(values: Partial<T>): PostgrestFilterBuilder<T> { |
149 |
| - this.method = 'PATCH' |
150 |
| - this.headers['Prefer'] = 'return=representation' |
151 |
| - this.body = values |
152 |
| - return new PostgrestFilterBuilder(this) |
153 |
| - } |
154 |
| - |
155 |
| - /** |
156 |
| - * Performs a DELETE on the table. |
157 |
| - */ |
158 |
| - delete(): PostgrestFilterBuilder<T> { |
159 |
| - this.method = 'DELETE' |
160 |
| - this.headers['Prefer'] = 'return=representation' |
161 |
| - return new PostgrestFilterBuilder(this) |
162 |
| - } |
163 |
| - |
164 |
| - /** @internal */ |
165 |
| - rpc(params?: object): PostgrestBuilder<T> { |
166 |
| - this.method = 'POST' |
167 |
| - this.body = params |
168 |
| - return this |
169 |
| - } |
170 |
| -} |
171 |
| - |
172 |
| -/** |
173 |
| - * Post-filters (transforms) |
174 |
| - */ |
175 |
| - |
176 |
| -class PostgrestTransformBuilder<T> extends PostgrestBuilder<T> { |
177 |
| - /** |
178 |
| - * Orders the result with the specified `column`. |
179 |
| - * |
180 |
| - * @param column The column to order on. |
181 |
| - * @param ascending If `true`, the result will be in ascending order. |
182 |
| - * @param nullsFirst If `true`, `null`s appear first. |
183 |
| - * @param foreignTable The foreign table to use (if `column` is a foreign column). |
184 |
| - */ |
185 |
| - order( |
186 |
| - column: keyof T, |
187 |
| - { |
188 |
| - ascending = true, |
189 |
| - nullsFirst = false, |
190 |
| - foreignTable, |
191 |
| - }: { ascending?: boolean; nullsFirst?: boolean; foreignTable?: string } = {} |
192 |
| - ): PostgrestTransformBuilder<T> { |
193 |
| - const key = typeof foreignTable === 'undefined' ? 'order' : `"${foreignTable}".order` |
194 |
| - this.url.searchParams.set( |
195 |
| - key, |
196 |
| - `"${column}".${ascending ? 'asc' : 'desc'}.${nullsFirst ? 'nullsfirst' : 'nullslast'}` |
197 |
| - ) |
198 |
| - return this |
199 |
| - } |
200 |
| - |
201 |
| - /** |
202 |
| - * Limits the result with the specified `count`. |
203 |
| - * |
204 |
| - * @param count The maximum no. of rows to limit to. |
205 |
| - * @param foreignTable The foreign table to use (for foreign columns). |
206 |
| - */ |
207 |
| - limit( |
208 |
| - count: number, |
209 |
| - { foreignTable }: { foreignTable?: string } = {} |
210 |
| - ): PostgrestTransformBuilder<T> { |
211 |
| - const key = typeof foreignTable === 'undefined' ? 'limit' : `"${foreignTable}".limit` |
212 |
| - this.url.searchParams.set(key, `${count}`) |
213 |
| - return this |
214 |
| - } |
215 |
| - |
216 |
| - /** |
217 |
| - * Limits the result to rows within the specified range, inclusive. |
218 |
| - * |
219 |
| - * @param from The starting index from which to limit the result, inclusive. |
220 |
| - * @param to The last index to which to limit the result, inclusive. |
221 |
| - * @param foreignTable The foreign table to use (for foreign columns). |
222 |
| - */ |
223 |
| - range( |
224 |
| - from: number, |
225 |
| - to: number, |
226 |
| - { foreignTable }: { foreignTable?: string } = {} |
227 |
| - ): PostgrestTransformBuilder<T> { |
228 |
| - const keyOffset = typeof foreignTable === 'undefined' ? 'offset' : `"${foreignTable}".offset` |
229 |
| - const keyLimit = typeof foreignTable === 'undefined' ? 'limit' : `"${foreignTable}".limit` |
230 |
| - this.url.searchParams.set(keyOffset, `${from}`) |
231 |
| - // Range is inclusive, so add 1 |
232 |
| - this.url.searchParams.set(keyLimit, `${to - from + 1}`) |
233 |
| - return this |
234 |
| - } |
235 |
| - |
236 |
| - /** |
237 |
| - * Retrieves only one row from the result. Result must be one row (e.g. using |
238 |
| - * `limit`), otherwise this will result in an error. |
239 |
| - */ |
240 |
| - single(): PostgrestTransformBuilder<T> { |
241 |
| - this.headers['Accept'] = 'application/vnd.pgrst.object+json' |
242 |
| - return this |
243 |
| - } |
244 |
| -} |
| 1 | +import PostgrestTransformBuilder from './PostgrestTransformBuilder' |
245 | 2 |
|
246 | 3 | /**
|
247 | 4 | * Filters
|
@@ -273,7 +30,7 @@ type FilterOperator =
|
273 | 30 | | 'phfts'
|
274 | 31 | | 'wfts'
|
275 | 32 |
|
276 |
| -class PostgrestFilterBuilder<T> extends PostgrestTransformBuilder<T> { |
| 33 | +export default class PostgrestFilterBuilder<T> extends PostgrestTransformBuilder<T> { |
277 | 34 | /**
|
278 | 35 | * Finds all rows which doesn't satisfy the filter.
|
279 | 36 | *
|
|
0 commit comments