diff --git a/src/PostgrestClient.ts b/src/PostgrestClient.ts index 13afc923..c63eb930 100644 --- a/src/PostgrestClient.ts +++ b/src/PostgrestClient.ts @@ -1,6 +1,13 @@ import PostgrestQueryBuilder from './PostgrestQueryBuilder' import PostgrestFilterBuilder from './PostgrestFilterBuilder' -import { Fetch, GenericSchema, ClientServerOptions } from './types' +import { + Fetch, + GenericSchema, + ClientServerOptions, + PostgrestQueryBuilderOptions, + PostgrestQueryBuilderOptionsWithSchema, +} from './types' +import { mergeHeaders } from './utils' /** * PostgREST client. @@ -50,15 +57,7 @@ export default class PostgrestClient< */ constructor( url: string, - { - headers = {}, - schema, - fetch, - }: { - headers?: HeadersInit - schema?: SchemaName - fetch?: Fetch - } = {} + { headers = {}, schema, fetch }: PostgrestQueryBuilderOptionsWithSchema = {} ) { this.url = url this.headers = new Headers(headers) @@ -68,21 +67,29 @@ export default class PostgrestClient< from< TableName extends string & keyof Schema['Tables'], Table extends Schema['Tables'][TableName] - >(relation: TableName): PostgrestQueryBuilder + >( + relation: TableName, + options?: PostgrestQueryBuilderOptions + ): PostgrestQueryBuilder from( - relation: ViewName + relation: ViewName, + options?: PostgrestQueryBuilderOptions ): PostgrestQueryBuilder /** * Perform a query on a table or a view. * * @param relation - The table or view name to query */ - from(relation: string): PostgrestQueryBuilder { + from( + relation: string, + options?: PostgrestQueryBuilderOptions + ): PostgrestQueryBuilder { const url = new URL(`${this.url}/${relation}`) + return new PostgrestQueryBuilder(url, { - headers: new Headers(this.headers), + headers: mergeHeaders(this.headers, options?.headers), schema: this.schemaName, - fetch: this.fetch, + fetch: options?.fetch ?? this.fetch, }) } diff --git a/src/PostgrestQueryBuilder.ts b/src/PostgrestQueryBuilder.ts index 1a866b1a..bb3e71ed 100644 --- a/src/PostgrestQueryBuilder.ts +++ b/src/PostgrestQueryBuilder.ts @@ -1,6 +1,13 @@ import PostgrestFilterBuilder from './PostgrestFilterBuilder' import { GetResult } from './select-query-parser/result' -import { ClientServerOptions, Fetch, GenericSchema, GenericTable, GenericView } from './types' +import { + ClientServerOptions, + Fetch, + GenericSchema, + GenericTable, + GenericView, + PostgrestQueryBuilderOptionsWithSchema, +} from './types' export default class PostgrestQueryBuilder< ClientOptions extends ClientServerOptions, @@ -17,15 +24,7 @@ export default class PostgrestQueryBuilder< constructor( url: URL, - { - headers = {}, - schema, - fetch, - }: { - headers?: HeadersInit - schema?: string - fetch?: Fetch - } + { headers = {}, schema, fetch }: PostgrestQueryBuilderOptionsWithSchema ) { this.url = url this.headers = new Headers(headers) diff --git a/src/index.ts b/src/index.ts index 8c435dda..85aa686b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -29,6 +29,8 @@ export type { PostgrestSingleResponse, PostgrestMaybeSingleResponse, ClientServerOptions as PostgrestClientOptions, + PostgrestQueryBuilderOptions, + PostgrestQueryBuilderOptionsWithSchema, } from './types' // https://github.com/supabase/postgrest-js/issues/551 // To be replaced with a helper type that only uses public types diff --git a/src/types.ts b/src/types.ts index d0b89036..89a888ab 100644 --- a/src/types.ts +++ b/src/types.ts @@ -31,6 +31,16 @@ export type PostgrestSingleResponse = PostgrestResponseSuccess | Postgrest export type PostgrestMaybeSingleResponse = PostgrestSingleResponse export type PostgrestResponse = PostgrestSingleResponse +export type PostgrestQueryBuilderOptions = { + headers?: HeadersInit + fetch?: Fetch +} + +export type PostgrestQueryBuilderOptionsWithSchema = + PostgrestQueryBuilderOptions & { + schema?: TSchema + } + export type GenericRelationship = { foreignKeyName: string columns: string[] diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 00000000..20696a20 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,23 @@ +/** + * Non-destructively merges an optional {@link HeadersInit} into a {@link Headers} object, where {@link right} takes precedence over {@link left} if it exists. + * @param {Headers} left Base {@link Headers} object + * @param {HeadersInit?} right Optional {@link HeadersInit} to merge into {@link left} + * @returns The resulting merged {@link HeadersInit} object. + */ + +export function mergeHeaders(left: Headers, right?: HeadersInit): HeadersInit { + if (!right) return left + + const merged = new Headers(left) + const rightEntries = + right instanceof Headers + ? right.entries() + : Array.isArray(right) + ? right + : Object.entries(right) + for (const [key, value] of rightEntries) { + merged.set(key, value) + } + + return merged +}