Skip to content

Commit fe3e80f

Browse files
committed
chore: refactor in favor of Headers API
1 parent 5017cd3 commit fe3e80f

9 files changed

+83
-303
lines changed

src/PostgrestBuilder.ts

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,33 @@ export default abstract class PostgrestBuilder<
2424
{
2525
protected method: 'GET' | 'HEAD' | 'POST' | 'PATCH' | 'DELETE'
2626
protected url: URL
27-
protected headers: Record<string, string>
27+
protected headers: Headers
2828
protected schema?: string
2929
protected body?: unknown
3030
protected shouldThrowOnError = false
3131
protected signal?: AbortSignal
3232
protected fetch: Fetch
3333
protected isMaybeSingle: boolean
3434

35-
constructor(builder: PostgrestBuilder<ClientOptions, Result>) {
35+
constructor(builder: {
36+
method: 'GET' | 'HEAD' | 'POST' | 'PATCH' | 'DELETE'
37+
url: URL
38+
headers: HeadersInit
39+
schema?: string
40+
body?: unknown
41+
shouldThrowOnError?: boolean
42+
signal?: AbortSignal
43+
fetch?: Fetch
44+
isMaybeSingle?: boolean
45+
}) {
3646
this.method = builder.method
3747
this.url = builder.url
38-
this.headers = builder.headers
48+
this.headers = new Headers(builder.headers)
3949
this.schema = builder.schema
4050
this.body = builder.body
41-
this.shouldThrowOnError = builder.shouldThrowOnError
51+
this.shouldThrowOnError = builder.shouldThrowOnError ?? false
4252
this.signal = builder.signal
43-
this.isMaybeSingle = builder.isMaybeSingle
53+
this.isMaybeSingle = builder.isMaybeSingle ?? false
4454

4555
if (builder.fetch) {
4656
this.fetch = builder.fetch
@@ -66,8 +76,8 @@ export default abstract class PostgrestBuilder<
6676
* Set an HTTP header for the request.
6777
*/
6878
setHeader(name: string, value: string): this {
69-
this.headers = { ...this.headers }
70-
this.headers[name] = value
79+
this.headers = new Headers(this.headers)
80+
this.headers.set(name, value)
7181
return this
7282
}
7383

@@ -91,12 +101,12 @@ export default abstract class PostgrestBuilder<
91101
if (this.schema === undefined) {
92102
// skip
93103
} else if (['GET', 'HEAD'].includes(this.method)) {
94-
this.headers['Accept-Profile'] = this.schema
104+
this.headers.set('Accept-Profile', this.schema)
95105
} else {
96-
this.headers['Content-Profile'] = this.schema
106+
this.headers.set('Content-Profile', this.schema)
97107
}
98108
if (this.method !== 'GET' && this.method !== 'HEAD') {
99-
this.headers['Content-Type'] = 'application/json'
109+
this.headers.set('Content-Type', 'application/json')
100110
}
101111

102112
// NOTE: Invoke w/o `this` to avoid illegal invocation error.
@@ -119,19 +129,19 @@ export default abstract class PostgrestBuilder<
119129
const body = await res.text()
120130
if (body === '') {
121131
// Prefer: return=minimal
122-
} else if (this.headers['Accept'] === 'text/csv') {
132+
} else if (this.headers.get('Accept') === 'text/csv') {
123133
data = body
124134
} else if (
125-
this.headers['Accept'] &&
126-
this.headers['Accept'].includes('application/vnd.pgrst.plan+text')
135+
this.headers.get('Accept') &&
136+
this.headers.get('Accept')?.includes('application/vnd.pgrst.plan+text')
127137
) {
128138
data = body
129139
} else {
130140
data = JSON.parse(body)
131141
}
132142
}
133143

134-
const countHeader = this.headers['Prefer']?.match(/count=(exact|planned|estimated)/)
144+
const countHeader = this.headers.get('Prefer')?.match(/count=(exact|planned|estimated)/)
135145
const contentRange = res.headers.get('content-range')?.split('/')
136146
if (countHeader && contentRange && contentRange.length > 1) {
137147
count = parseInt(contentRange[1])

src/PostgrestClient.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import PostgrestQueryBuilder from './PostgrestQueryBuilder'
22
import PostgrestFilterBuilder from './PostgrestFilterBuilder'
3-
import PostgrestBuilder from './PostgrestBuilder'
4-
import { DEFAULT_HEADERS } from './constants'
53
import { Fetch, GenericSchema, ClientServerOptions, GetGenericDatabaseWithOptions } from './types'
64

75
/**
@@ -29,7 +27,7 @@ export default class PostgrestClient<
2927
: any
3028
> {
3129
url: string
32-
headers: Record<string, string>
30+
headers: Headers
3331
schemaName?: SchemaName
3432
fetch?: Fetch
3533

@@ -50,17 +48,16 @@ export default class PostgrestClient<
5048
schema,
5149
fetch,
5250
}: {
53-
headers?: Record<string, string>
51+
headers?: HeadersInit
5452
schema?: SchemaName
5553
fetch?: Fetch
5654
} = {}
5755
) {
5856
this.url = url
59-
this.headers = { ...DEFAULT_HEADERS, ...headers }
57+
this.headers = new Headers(headers)
6058
this.schemaName = schema
6159
this.fetch = fetch
6260
}
63-
6461
from<
6562
TableName extends string & keyof Schema['Tables'],
6663
Table extends Schema['Tables'][TableName]
@@ -76,7 +73,7 @@ export default class PostgrestClient<
7673
from(relation: string): PostgrestQueryBuilder<ClientOptions, Schema, any, any> {
7774
const url = new URL(`${this.url}/${relation}`)
7875
return new PostgrestQueryBuilder(url, {
79-
headers: { ...this.headers },
76+
headers: new Headers(this.headers),
8077
schema: this.schemaName,
8178
fetch: this.fetch,
8279
})
@@ -170,9 +167,9 @@ export default class PostgrestClient<
170167
body = args
171168
}
172169

173-
const headers = { ...this.headers }
170+
const headers = new Headers(this.headers)
174171
if (count) {
175-
headers['Prefer'] = `count=${count}`
172+
headers.set('Prefer', `count=${count}`)
176173
}
177174

178175
return new PostgrestFilterBuilder({
@@ -181,8 +178,7 @@ export default class PostgrestClient<
181178
headers,
182179
schema: this.schemaName,
183180
body,
184-
fetch: this.fetch,
185-
allowEmpty: false,
186-
} as unknown as PostgrestBuilder<ClientOptions, Fn['Returns']>)
181+
fetch: this.fetch ?? fetch,
182+
})
187183
}
188184
}

src/PostgrestFilterBuilder.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import PostgrestTransformBuilder from './PostgrestTransformBuilder'
22
import { JsonPathToAccessor, JsonPathToType } from './select-query-parser/utils'
33
import { ClientServerOptions, GenericSchema } from './types'
4-
import { HeaderManager } from './utils'
54

65
type FilterOperator =
76
| 'eq'
@@ -616,10 +615,8 @@ export default class PostgrestFilterBuilder<
616615
? this
617616
: InvalidMethodError<'maxAffected method only available on update or delete'>
618617
: InvalidMethodError<'maxAffected method only available on postgrest 13+'> {
619-
const preferHeaderManager = new HeaderManager('Prefer', this.headers['Prefer'])
620-
preferHeaderManager.add('handling=strict')
621-
preferHeaderManager.add(`max-affected=${value}`)
622-
this.headers['Prefer'] = preferHeaderManager.get()
618+
this.headers.append('Prefer', 'handling=strict')
619+
this.headers.append('Prefer', `max-affected=${value}`)
623620
return this as unknown as ClientOptions['postgrestVersion'] extends 13
624621
? Method extends 'PATCH' | 'DELETE'
625622
? this

src/PostgrestQueryBuilder.ts

Lines changed: 21 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import PostgrestBuilder from './PostgrestBuilder'
21
import PostgrestFilterBuilder from './PostgrestFilterBuilder'
32
import { GetResult } from './select-query-parser/result'
43
import { ClientServerOptions, Fetch, GenericSchema, GenericTable, GenericView } from './types'
@@ -11,7 +10,7 @@ export default class PostgrestQueryBuilder<
1110
Relationships = Relation extends { Relationships: infer R } ? R : unknown
1211
> {
1312
url: URL
14-
headers: Record<string, string>
13+
headers: Headers
1514
schema?: string
1615
signal?: AbortSignal
1716
fetch?: Fetch
@@ -23,13 +22,13 @@ export default class PostgrestQueryBuilder<
2322
schema,
2423
fetch,
2524
}: {
26-
headers?: Record<string, string>
25+
headers?: HeadersInit
2726
schema?: string
2827
fetch?: Fetch
2928
}
3029
) {
3130
this.url = url
32-
this.headers = headers
31+
this.headers = new Headers(headers)
3332
this.schema = schema
3433
this.fetch = fetch
3534
}
@@ -99,8 +98,9 @@ export default class PostgrestQueryBuilder<
9998
})
10099
.join('')
101100
this.url.searchParams.set('select', cleanedColumns)
101+
102102
if (count) {
103-
this.headers['Prefer'] = `count=${count}`
103+
this.headers.append('Prefer', `count=${count}`)
104104
}
105105

106106
return new PostgrestFilterBuilder({
@@ -109,8 +109,7 @@ export default class PostgrestQueryBuilder<
109109
headers: this.headers,
110110
schema: this.schema,
111111
fetch: this.fetch,
112-
allowEmpty: false,
113-
} as unknown as PostgrestBuilder<ClientOptions, ResultOne[]>)
112+
})
114113
}
115114

116115
// TODO(v3): Make `defaultToNull` consistent for both single & bulk inserts.
@@ -189,17 +188,12 @@ export default class PostgrestQueryBuilder<
189188
> {
190189
const method = 'POST'
191190

192-
const prefersHeaders = []
193-
if (this.headers['Prefer']) {
194-
prefersHeaders.push(this.headers['Prefer'])
195-
}
196191
if (count) {
197-
prefersHeaders.push(`count=${count}`)
192+
this.headers.append('Prefer', `count=${count}`)
198193
}
199194
if (!defaultToNull) {
200-
prefersHeaders.push('missing=default')
195+
this.headers.append('Prefer', `missing=default`)
201196
}
202-
this.headers['Prefer'] = prefersHeaders.join(',')
203197

204198
if (Array.isArray(values)) {
205199
const columns = values.reduce((acc, x) => acc.concat(Object.keys(x)), [] as string[])
@@ -215,9 +209,8 @@ export default class PostgrestQueryBuilder<
215209
headers: this.headers,
216210
schema: this.schema,
217211
body: values,
218-
fetch: this.fetch,
219-
allowEmpty: false,
220-
} as unknown as PostgrestBuilder<ClientOptions, null>)
212+
fetch: this.fetch ?? fetch,
213+
})
221214
}
222215

223216
// TODO(v3): Make `defaultToNull` consistent for both single & bulk upserts.
@@ -316,19 +309,15 @@ export default class PostgrestQueryBuilder<
316309
> {
317310
const method = 'POST'
318311

319-
const prefersHeaders = [`resolution=${ignoreDuplicates ? 'ignore' : 'merge'}-duplicates`]
312+
this.headers.append('Prefer', `resolution=${ignoreDuplicates ? 'ignore' : 'merge'}-duplicates`)
320313

321314
if (onConflict !== undefined) this.url.searchParams.set('on_conflict', onConflict)
322-
if (this.headers['Prefer']) {
323-
prefersHeaders.push(this.headers['Prefer'])
324-
}
325315
if (count) {
326-
prefersHeaders.push(`count=${count}`)
316+
this.headers.append('Prefer', `count=${count}`)
327317
}
328318
if (!defaultToNull) {
329-
prefersHeaders.push('missing=default')
319+
this.headers.append('Prefer', 'missing=default')
330320
}
331-
this.headers['Prefer'] = prefersHeaders.join(',')
332321

333322
if (Array.isArray(values)) {
334323
const columns = values.reduce((acc, x) => acc.concat(Object.keys(x)), [] as string[])
@@ -344,9 +333,8 @@ export default class PostgrestQueryBuilder<
344333
headers: this.headers,
345334
schema: this.schema,
346335
body: values,
347-
fetch: this.fetch,
348-
allowEmpty: false,
349-
} as unknown as PostgrestBuilder<ClientOptions, null>)
336+
fetch: this.fetch ?? fetch,
337+
})
350338
}
351339

352340
/**
@@ -387,24 +375,18 @@ export default class PostgrestQueryBuilder<
387375
'PATCH'
388376
> {
389377
const method = 'PATCH'
390-
const prefersHeaders = []
391-
if (this.headers['Prefer']) {
392-
prefersHeaders.push(this.headers['Prefer'])
393-
}
394378
if (count) {
395-
prefersHeaders.push(`count=${count}`)
379+
this.headers.append('Prefer', `count=${count}`)
396380
}
397-
this.headers['Prefer'] = prefersHeaders.join(',')
398381

399382
return new PostgrestFilterBuilder({
400383
method,
401384
url: this.url,
402385
headers: this.headers,
403386
schema: this.schema,
404387
body: values,
405-
fetch: this.fetch,
406-
allowEmpty: false,
407-
} as unknown as PostgrestBuilder<ClientOptions, null>)
388+
fetch: this.fetch ?? fetch,
389+
})
408390
}
409391

410392
/**
@@ -440,22 +422,16 @@ export default class PostgrestQueryBuilder<
440422
'DELETE'
441423
> {
442424
const method = 'DELETE'
443-
const prefersHeaders = []
444425
if (count) {
445-
prefersHeaders.push(`count=${count}`)
426+
this.headers.append('Prefer', `count=${count}`)
446427
}
447-
if (this.headers['Prefer']) {
448-
prefersHeaders.unshift(this.headers['Prefer'])
449-
}
450-
this.headers['Prefer'] = prefersHeaders.join(',')
451428

452429
return new PostgrestFilterBuilder({
453430
method,
454431
url: this.url,
455432
headers: this.headers,
456433
schema: this.schema,
457-
fetch: this.fetch,
458-
allowEmpty: false,
459-
} as unknown as PostgrestBuilder<ClientOptions, null>)
434+
fetch: this.fetch ?? fetch,
435+
})
460436
}
461437
}

0 commit comments

Comments
 (0)