-
-
Notifications
You must be signed in to change notification settings - Fork 143
/
PostgrestTransformBuilder.ts
138 lines (127 loc) · 4.32 KB
/
PostgrestTransformBuilder.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
import { PostgrestBuilder, PostgrestMaybeSingleResponse, PostgrestSingleResponse } from './types'
/**
* Post-filters (transforms)
*/
export default class PostgrestTransformBuilder<T> extends PostgrestBuilder<T> {
/**
* Performs vertical filtering with SELECT.
*
* @param columns The columns to retrieve, separated by commas.
*/
select(columns = '*'): this {
// Remove whitespaces except when quoted
let quoted = false
const cleanedColumns = columns
.split('')
.map((c) => {
if (/\s/.test(c) && !quoted) {
return ''
}
if (c === '"') {
quoted = !quoted
}
return c
})
.join('')
this.url.searchParams.set('select', cleanedColumns)
return this
}
/**
* Orders the result with the specified `column`.
*
* @param column The column to order on.
* @param ascending If `true`, the result will be in ascending order.
* @param nullsFirst If `true`, `null`s appear first.
* @param foreignTable The foreign table to use (if `column` is a foreign column).
*/
order(
column: keyof T,
{
ascending = true,
nullsFirst = false,
foreignTable,
}: { ascending?: boolean; nullsFirst?: boolean; foreignTable?: string } = {}
): this {
const key = typeof foreignTable === 'undefined' ? 'order' : `${foreignTable}.order`
const existingOrder = this.url.searchParams.get(key)
this.url.searchParams.set(
key,
`${existingOrder ? `${existingOrder},` : ''}${column}.${ascending ? 'asc' : 'desc'}.${
nullsFirst ? 'nullsfirst' : 'nullslast'
}`
)
return this
}
/**
* Limits the result with the specified `count`.
*
* @param count The maximum no. of rows to limit to.
* @param foreignTable The foreign table to use (for foreign columns).
*/
limit(count: number, { foreignTable }: { foreignTable?: string } = {}): this {
const key = typeof foreignTable === 'undefined' ? 'limit' : `${foreignTable}.limit`
this.url.searchParams.set(key, `${count}`)
return this
}
/**
* Limits the result to rows within the specified range, inclusive.
*
* @param from The starting index from which to limit the result, inclusive.
* @param to The last index to which to limit the result, inclusive.
* @param foreignTable The foreign table to use (for foreign columns).
*/
range(from: number, to: number, { foreignTable }: { foreignTable?: string } = {}): this {
const keyOffset = typeof foreignTable === 'undefined' ? 'offset' : `${foreignTable}.offset`
const keyLimit = typeof foreignTable === 'undefined' ? 'limit' : `${foreignTable}.limit`
this.url.searchParams.set(keyOffset, `${from}`)
// Range is inclusive, so add 1
this.url.searchParams.set(keyLimit, `${to - from + 1}`)
return this
}
/**
* Sets the AbortSignal for the fetch request.
*/
abortSignal(signal: AbortSignal): this {
this.signal = signal
return this
}
/**
* Retrieves only one row from the result. Result must be one row (e.g. using
* `limit`), otherwise this will result in an error.
*/
single(): PromiseLike<PostgrestSingleResponse<T>> {
this.headers['Accept'] = 'application/vnd.pgrst.object+json'
return this as PromiseLike<PostgrestSingleResponse<T>>
}
/**
* Retrieves at most one row from the result. Result must be at most one row
* (e.g. using `eq` on a UNIQUE column), otherwise this will result in an
* error.
*/
maybeSingle(): PromiseLike<PostgrestMaybeSingleResponse<T>> {
this.headers['Accept'] = 'application/vnd.pgrst.object+json'
const _this = new PostgrestTransformBuilder(this)
_this.then = ((onfulfilled: any, onrejected: any) =>
this.then((res: any): any => {
if (res.error?.details?.includes('Results contain 0 rows')) {
return onfulfilled({
error: null,
data: null,
count: res.count,
status: 200,
statusText: 'OK',
body: null,
})
}
return onfulfilled(res)
}, onrejected)) as any
return _this as PromiseLike<PostgrestMaybeSingleResponse<T>>
}
/**
* Set the response type to CSV.
*/
csv(): PromiseLike<PostgrestSingleResponse<string>> {
this.headers['Accept'] = 'text/csv'
return this as PromiseLike<PostgrestSingleResponse<string>>
}
}