From 0caf5145217339025b9b54b644557d9594e9fc92 Mon Sep 17 00:00:00 2001 From: Wojciech Grzebieniowski Date: Sat, 23 Mar 2024 15:24:12 +0100 Subject: [PATCH 1/5] Allow to pass Next.js options to fetch --- src/PostgrestBuilder.ts | 5 +++- src/PostgrestTransformBuilder.ts | 13 ++++++++- src/types.ts | 15 ++++++++++ test/transforms.ts | 48 ++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 2 deletions(-) diff --git a/src/PostgrestBuilder.ts b/src/PostgrestBuilder.ts index 96a8bc55..fc9987ab 100644 --- a/src/PostgrestBuilder.ts +++ b/src/PostgrestBuilder.ts @@ -1,7 +1,7 @@ // @ts-ignore import nodeFetch from '@supabase/node-fetch' -import type { Fetch, PostgrestSingleResponse } from './types' +import type { Fetch, NextFetchRequestConfig, PostgrestSingleResponse } from './types' import PostgrestError from './PostgrestError' export default abstract class PostgrestBuilder @@ -14,6 +14,7 @@ export default abstract class PostgrestBuilder protected body?: unknown protected shouldThrowOnError = false protected signal?: AbortSignal + protected nextOptions?: NextFetchRequestConfig protected fetch: Fetch protected isMaybeSingle: boolean @@ -25,6 +26,7 @@ export default abstract class PostgrestBuilder this.body = builder.body this.shouldThrowOnError = builder.shouldThrowOnError this.signal = builder.signal + this.nextOptions = builder.nextOptions this.isMaybeSingle = builder.isMaybeSingle if (builder.fetch) { @@ -74,6 +76,7 @@ export default abstract class PostgrestBuilder headers: this.headers, body: JSON.stringify(this.body), signal: this.signal, + next: this.nextOptions, }).then(async (res) => { let error = null let data = null diff --git a/src/PostgrestTransformBuilder.ts b/src/PostgrestTransformBuilder.ts index 219ccd79..d2457555 100644 --- a/src/PostgrestTransformBuilder.ts +++ b/src/PostgrestTransformBuilder.ts @@ -1,6 +1,6 @@ import PostgrestBuilder from './PostgrestBuilder' import { GetResult } from './select-query-parser' -import { GenericSchema } from './types' +import { GenericSchema, NextFetchRequestConfig } from './types' export default class PostgrestTransformBuilder< Schema extends GenericSchema, @@ -182,6 +182,17 @@ export default class PostgrestTransformBuilder< return this } + /** + * Set Next.js's tags for the fetch request. + * + * @param tags - An array of tags. A tag represents the cache tag associated with the data. + * Must be less than or equal to 256 characters. This value is case-sensitive. + */ + next(nextOptions: NextFetchRequestConfig): this { + this.nextOptions = nextOptions + return this + } + /** * Return `data` as a single object instead of an array of objects. * diff --git a/src/types.ts b/src/types.ts index 5379b271..0989fb7d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -70,3 +70,18 @@ export type GenericSchema = { // https://twitter.com/mattpocockuk/status/1622730173446557697 export type Prettify = { [K in keyof T]: T[K] } & {} + +export type NextFetchRequestConfig = RequestInit extends { next: infer T } + ? T + : { + revalidate?: number | false + tags?: string[] + } + +declare global { + namespace globalThis { + interface RequestInit { + next?: unknown // Avoid: 'next' is referenced directly or indirectly in its own type annotation.ts(2502) + } + } +} diff --git a/test/transforms.ts b/test/transforms.ts index a7ca4e76..ccf35499 100644 --- a/test/transforms.ts +++ b/test/transforms.ts @@ -473,3 +473,51 @@ test('rollback delete', async () => { } `) }) + +test('Next.js options', async () => { + const fetchSpy = jest.fn(fetch) + + const postgrest = new PostgrestClient('http://localhost:3000', { + fetch: fetchSpy, + }) + + const builder = postgrest + .from('users') + .select() + .eq('username', 'supabot') + .next({ + tags: ['users', 'supabot'], + }) + const res = await builder + expect(res).toMatchInlineSnapshot(` + Object { + "count": null, + "data": Array [ + Object { + "age_range": "[1,2)", + "catchphrase": "'cat' 'fat'", + "data": null, + "status": "ONLINE", + "username": "supabot", + }, + ], + "error": null, + "status": 200, + "statusText": "OK", + } + `) + expect(fetchSpy).toHaveBeenCalledWith( + 'http://localhost:3000/users?select=*&username=eq.supabot', + { + body: undefined, + headers: { + 'X-Client-Info': 'postgrest-js/0.0.0-automated', + }, + method: 'GET', + next: { + tags: ['users', 'supabot'], + }, + signal: undefined, + } + ) +}) From a0145905c39caeef3530a6b916398df2b52ff07d Mon Sep 17 00:00:00 2001 From: Wojciech Grzebieniowski Date: Tue, 2 Apr 2024 09:45:25 +0200 Subject: [PATCH 2/5] Fix tests error: fetch is not defined --- test/transforms.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/transforms.ts b/test/transforms.ts index ccf35499..20e39e81 100644 --- a/test/transforms.ts +++ b/test/transforms.ts @@ -2,6 +2,8 @@ import { PostgrestClient } from '../src/index' import { Database } from './types' import { AbortController } from 'node-abort-controller' +// @ts-ignore +import nodeFetch from '@supabase/node-fetch' const postgrest = new PostgrestClient('http://localhost:3000') @@ -475,7 +477,11 @@ test('rollback delete', async () => { }) test('Next.js options', async () => { - const fetchSpy = jest.fn(fetch) + let fetchImpl = fetch + if (typeof fetchImpl === 'undefined') { + fetchImpl = nodeFetch + } + const fetchSpy = jest.fn(fetchImpl) const postgrest = new PostgrestClient('http://localhost:3000', { fetch: fetchSpy, From 53a9652845cb0edbaaeac035e318a93128b8e908 Mon Sep 17 00:00:00 2001 From: Wojciech Grzebieniowski Date: Tue, 2 Apr 2024 14:38:09 +0200 Subject: [PATCH 3/5] Allow to pass any fetchOptions --- src/PostgrestBuilder.ts | 17 +++++++++-------- src/PostgrestTransformBuilder.ts | 17 ++++++++++------- src/types.ts | 15 +-------------- test/transforms.ts | 8 +++++--- 4 files changed, 25 insertions(+), 32 deletions(-) diff --git a/src/PostgrestBuilder.ts b/src/PostgrestBuilder.ts index fc9987ab..ea9ef45f 100644 --- a/src/PostgrestBuilder.ts +++ b/src/PostgrestBuilder.ts @@ -1,7 +1,7 @@ // @ts-ignore import nodeFetch from '@supabase/node-fetch' -import type { Fetch, NextFetchRequestConfig, PostgrestSingleResponse } from './types' +import type { Fetch, FetchOptions, PostgrestSingleResponse } from './types' import PostgrestError from './PostgrestError' export default abstract class PostgrestBuilder @@ -13,8 +13,7 @@ export default abstract class PostgrestBuilder protected schema?: string protected body?: unknown protected shouldThrowOnError = false - protected signal?: AbortSignal - protected nextOptions?: NextFetchRequestConfig + protected fetchOpts: FetchOptions = {} protected fetch: Fetch protected isMaybeSingle: boolean @@ -25,8 +24,7 @@ export default abstract class PostgrestBuilder this.schema = builder.schema this.body = builder.body this.shouldThrowOnError = builder.shouldThrowOnError - this.signal = builder.signal - this.nextOptions = builder.nextOptions + this.fetchOpts = builder.fetchOpts this.isMaybeSingle = builder.isMaybeSingle if (builder.fetch) { @@ -72,11 +70,14 @@ export default abstract class PostgrestBuilder // https://github.com/supabase/postgrest-js/pull/247 const _fetch = this.fetch let res = _fetch(this.url.toString(), { + ...this.fetchOpts, method: this.method, - headers: this.headers, + headers: { + ...this.fetchOpts.headers, + ...this.headers, + }, body: JSON.stringify(this.body), - signal: this.signal, - next: this.nextOptions, + signal: this.fetchOpts.signal, }).then(async (res) => { let error = null let data = null diff --git a/src/PostgrestTransformBuilder.ts b/src/PostgrestTransformBuilder.ts index d2457555..206a9315 100644 --- a/src/PostgrestTransformBuilder.ts +++ b/src/PostgrestTransformBuilder.ts @@ -1,6 +1,6 @@ import PostgrestBuilder from './PostgrestBuilder' import { GetResult } from './select-query-parser' -import { GenericSchema, NextFetchRequestConfig } from './types' +import type { FetchOptions, GenericSchema } from './types' export default class PostgrestTransformBuilder< Schema extends GenericSchema, @@ -176,20 +176,23 @@ export default class PostgrestTransformBuilder< * Set the AbortSignal for the fetch request. * * @param signal - The AbortSignal to use for the fetch request + * @deprecated Use fetchOptions instead. E.g. `fetchOptions({ signal: new AbortController().signal })` */ abortSignal(signal: AbortSignal): this { - this.signal = signal + this.fetchOpts.signal = signal return this } /** - * Set Next.js's tags for the fetch request. + * Set fetch options for the request. * - * @param tags - An array of tags. A tag represents the cache tag associated with the data. - * Must be less than or equal to 256 characters. This value is case-sensitive. + * @param init - Fetch options. */ - next(nextOptions: NextFetchRequestConfig): this { - this.nextOptions = nextOptions + fetchOptions(init: FetchOptions): this { + this.fetchOpts = { + signal: this.fetchOpts.signal, + ...init, + } return this } diff --git a/src/types.ts b/src/types.ts index 0989fb7d..aead8585 100644 --- a/src/types.ts +++ b/src/types.ts @@ -71,17 +71,4 @@ export type GenericSchema = { // https://twitter.com/mattpocockuk/status/1622730173446557697 export type Prettify = { [K in keyof T]: T[K] } & {} -export type NextFetchRequestConfig = RequestInit extends { next: infer T } - ? T - : { - revalidate?: number | false - tags?: string[] - } - -declare global { - namespace globalThis { - interface RequestInit { - next?: unknown // Avoid: 'next' is referenced directly or indirectly in its own type annotation.ts(2502) - } - } -} +export type FetchOptions = Omit diff --git a/test/transforms.ts b/test/transforms.ts index 1666f825..41d72197 100644 --- a/test/transforms.ts +++ b/test/transforms.ts @@ -497,9 +497,11 @@ test('Next.js options', async () => { .from('users') .select() .eq('username', 'supabot') - .next({ - tags: ['users', 'supabot'], - }) + .fetchOptions({ + next: { + tags: ['users', 'supabot'], + }, + } as any) const res = await builder expect(res).toMatchInlineSnapshot(` Object { From d22e54e554a518c64f2719518d4a2bd8471e288d Mon Sep 17 00:00:00 2001 From: Wojciech Grzebieniowski Date: Tue, 2 Apr 2024 19:16:44 +0200 Subject: [PATCH 4/5] Fix merging headers --- src/PostgrestBuilder.ts | 8 ++------ src/PostgrestTransformBuilder.ts | 26 +++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/PostgrestBuilder.ts b/src/PostgrestBuilder.ts index ea9ef45f..bb6488df 100644 --- a/src/PostgrestBuilder.ts +++ b/src/PostgrestBuilder.ts @@ -13,7 +13,7 @@ export default abstract class PostgrestBuilder protected schema?: string protected body?: unknown protected shouldThrowOnError = false - protected fetchOpts: FetchOptions = {} + protected fetchOpts: Omit = {} protected fetch: Fetch protected isMaybeSingle: boolean @@ -72,12 +72,8 @@ export default abstract class PostgrestBuilder let res = _fetch(this.url.toString(), { ...this.fetchOpts, method: this.method, - headers: { - ...this.fetchOpts.headers, - ...this.headers, - }, + headers: this.headers, body: JSON.stringify(this.body), - signal: this.fetchOpts.signal, }).then(async (res) => { let error = null let data = null diff --git a/src/PostgrestTransformBuilder.ts b/src/PostgrestTransformBuilder.ts index 206a9315..11a32f6d 100644 --- a/src/PostgrestTransformBuilder.ts +++ b/src/PostgrestTransformBuilder.ts @@ -179,7 +179,8 @@ export default class PostgrestTransformBuilder< * @deprecated Use fetchOptions instead. E.g. `fetchOptions({ signal: new AbortController().signal })` */ abortSignal(signal: AbortSignal): this { - this.fetchOpts.signal = signal + this.fetchOptions({ signal }) + return this } @@ -189,10 +190,29 @@ export default class PostgrestTransformBuilder< * @param init - Fetch options. */ fetchOptions(init: FetchOptions): this { + const { headers, ...rest } = init + this.fetchOpts = { - signal: this.fetchOpts.signal, - ...init, + ...this.fetchOpts, + ...rest, } + + if (headers) { + let entries: Iterable + + if (Array.isArray(headers)) { + entries = headers.values() + } else if (headers instanceof Headers) { + entries = headers.entries() + } else { + entries = Object.entries(headers) + } + + for (const [name, val] of entries) { + this.headers[name] = val + } + } + return this } From e7aeb043d96a4844da176fd40f11d445277a7095 Mon Sep 17 00:00:00 2001 From: Wojciech Grzebieniowski Date: Mon, 4 Nov 2024 10:08:24 +0100 Subject: [PATCH 5/5] Update types.ts --- src/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/types.ts b/src/types.ts index 890fc090..effd6628 100644 --- a/src/types.ts +++ b/src/types.ts @@ -92,4 +92,3 @@ type BuiltIns = Primitive | void | Date | RegExp type Primitive = null | undefined | string | number | boolean | symbol | bigint export type FetchOptions = Omit - \ No newline at end of file