Skip to content
This repository was archived by the owner on Oct 9, 2025. It is now read-only.

Commit 38d604d

Browse files
kiwicopplesoedirgo
authored andcommitted
feat: refactor the library with additional exports
1 parent c96ccfb commit 38d604d

File tree

7 files changed

+309
-301
lines changed

7 files changed

+309
-301
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
"build": "run-s clean format build:*",
2323
"build:main": "tsc -p tsconfig.json",
2424
"build:module": "tsc -p tsconfig.module.json",
25-
"test": "run-s test:db && jest -i",
25+
"test": "run-s test:db && jest --runInBand",
26+
"test:clean": "cd test/db && docker-compose down",
2627
"test:db": "cd test/db && docker-compose down && docker-compose up -d && sleep 5",
2728
"docs": "typedoc --mode file --target ES6 --theme minimal",
2829
"docs:json": "typedoc --json docs/spec.json --mode modules --includeDeclarations --excludeExternals"

src/PostgrestClient.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import PostgrestQueryBuilder from './lib/PostgrestQueryBuilder'
2+
import { PostgrestBuilder } from './lib/types'
3+
4+
export default class PostgrestClient {
5+
url: string
6+
headers: { [key: string]: string }
7+
schema?: string
8+
9+
/**
10+
* Creates a PostgREST client.
11+
*
12+
* @param url URL of the PostgREST endpoint.
13+
* @param headers Custom headers.
14+
* @param schema Postgres schema to switch to.
15+
*/
16+
constructor(
17+
url: string,
18+
{ headers = {}, schema }: { headers?: { [key: string]: string }; schema?: string } = {}
19+
) {
20+
this.url = url
21+
this.headers = headers
22+
this.schema = schema
23+
}
24+
25+
/**
26+
* Authenticates the request with JWT.
27+
*
28+
* @param token The JWT token to use.
29+
*/
30+
auth(token: string): this {
31+
this.headers['Authorization'] = `Bearer ${token}`
32+
return this
33+
}
34+
35+
/**
36+
* Perform a table operation.
37+
*
38+
* @param table The table name to operate on.
39+
*/
40+
from<T = any>(table: string): PostgrestQueryBuilder<T> {
41+
const url = `${this.url}/${table}`
42+
return new PostgrestQueryBuilder(url, { headers: this.headers, schema: this.schema })
43+
}
44+
45+
/**
46+
* Perform a stored procedure call.
47+
*
48+
* @param fn The function name to call.
49+
* @param params The parameters to pass to the function call.
50+
*/
51+
rpc<T = any>(fn: string, params?: object): PostgrestBuilder<T> {
52+
const url = `${this.url}/rpc/${fn}`
53+
return new PostgrestQueryBuilder<T>(url, { headers: this.headers, schema: this.schema }).rpc(
54+
params
55+
)
56+
}
57+
}

src/index.ts

Lines changed: 5 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,6 @@
1-
import { PostgrestBuilder, PostgrestQueryBuilder } from './builder'
1+
import PostgrestClient from './PostgrestClient'
2+
import PostgrestFilterBuilder from './lib/PostgrestFilterBuilder'
3+
import PostgrestQueryBuilder from './lib/PostgrestQueryBuilder'
4+
import { PostgrestBuilder } from './lib/types'
25

3-
export class PostgrestClient {
4-
url: string
5-
headers: { [key: string]: string }
6-
schema?: string
7-
8-
/**
9-
* Creates a PostgREST client.
10-
*
11-
* @param url URL of the PostgREST endpoint.
12-
* @param headers Custom headers.
13-
* @param schema Postgres schema to switch to.
14-
*/
15-
constructor(
16-
url: string,
17-
{ headers = {}, schema }: { headers?: { [key: string]: string }; schema?: string } = {}
18-
) {
19-
this.url = url
20-
this.headers = headers
21-
this.schema = schema
22-
}
23-
24-
/**
25-
* Authenticates the request with JWT.
26-
*
27-
* @param token The JWT token to use.
28-
*/
29-
auth(token: string): this {
30-
this.headers['Authorization'] = `Bearer ${token}`
31-
return this
32-
}
33-
34-
/**
35-
* Perform a table operation.
36-
*
37-
* @param table The table name to operate on.
38-
*/
39-
from<T = any>(table: string): PostgrestQueryBuilder<T> {
40-
const url = `${this.url}/${table}`
41-
return new PostgrestQueryBuilder(url, { headers: this.headers, schema: this.schema })
42-
}
43-
44-
/**
45-
* Perform a stored procedure call.
46-
*
47-
* @param fn The function name to call.
48-
* @param params The parameters to pass to the function call.
49-
*/
50-
rpc<T = any>(fn: string, params?: object): PostgrestBuilder<T> {
51-
const url = `${this.url}/rpc/${fn}`
52-
return new PostgrestQueryBuilder<T>(url, { headers: this.headers, schema: this.schema }).rpc(
53-
params
54-
)
55-
}
56-
}
6+
export { PostgrestClient, PostgrestFilterBuilder, PostgrestQueryBuilder, PostgrestBuilder }

src/builder.ts renamed to src/lib/PostgrestFilterBuilder.ts

Lines changed: 2 additions & 245 deletions
Original file line numberDiff line numberDiff line change
@@ -1,247 +1,4 @@
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'
2452

2463
/**
2474
* Filters
@@ -273,7 +30,7 @@ type FilterOperator =
27330
| 'phfts'
27431
| 'wfts'
27532

276-
class PostgrestFilterBuilder<T> extends PostgrestTransformBuilder<T> {
33+
export default class PostgrestFilterBuilder<T> extends PostgrestTransformBuilder<T> {
27734
/**
27835
* Finds all rows which doesn't satisfy the filter.
27936
*

0 commit comments

Comments
 (0)