diff --git a/packages/client-web/__tests__/integration/web_connection.test.ts b/packages/client-web/__tests__/integration/web_connection.test.ts new file mode 100644 index 00000000..b71121bb --- /dev/null +++ b/packages/client-web/__tests__/integration/web_connection.test.ts @@ -0,0 +1,38 @@ +import { createClient } from '../../src' +import type { WebClickHouseClient } from '../../src/client' + +describe('[Web] Connection', () => { + describe('KeepAlive setting', () => { + let fetchSpy: jasmine.Spy + beforeEach(() => { + fetchSpy = spyOn(window, 'fetch').and.returnValue( + Promise.resolve(new Response()) + ) + }) + + it('should be enabled by default', async () => { + const client = createClient() + const fetchParams = await pingAndGetRequestInit(client) + expect(fetchParams.keepalive).toBeTruthy() + }) + + it('should be possible to disable it', async () => { + const client = createClient({ keep_alive: { enabled: false } }) + const fetchParams = await pingAndGetRequestInit(client) + expect(fetchParams!.keepalive).toBeFalsy() + }) + + it('should be enabled with an explicit setting', async () => { + const client = createClient({ keep_alive: { enabled: true } }) + const fetchParams = await pingAndGetRequestInit(client) + expect(fetchParams.keepalive).toBeTruthy() + }) + + async function pingAndGetRequestInit(client: WebClickHouseClient) { + await client.ping() + expect(fetchSpy).toHaveBeenCalledTimes(1) + const [, fetchParams] = fetchSpy.calls.mostRecent().args + return fetchParams! + } + }) +}) diff --git a/packages/client-web/src/client.ts b/packages/client-web/src/client.ts index 49c5bb49..4f0f02ca 100644 --- a/packages/client-web/src/client.ts +++ b/packages/client-web/src/client.ts @@ -15,6 +15,14 @@ import { WebConnection } from './connection' import { ResultSet } from './result_set' import { WebValuesEncoder } from './utils' +export type WebClickHouseClientConfigOptions = + BaseClickHouseClientConfigOptions & { + keep_alive?: { + /** Enable or disable HTTP Keep-Alive mechanism. Default: true */ + enabled: boolean + } + } + export type WebClickHouseClient = Omit< ClickHouseClient, 'insert' | 'query' @@ -30,11 +38,15 @@ export type WebClickHouseClient = Omit< } export function createClient( - config?: BaseClickHouseClientConfigOptions + config?: WebClickHouseClientConfigOptions ): WebClickHouseClient { + const keep_alive = { + enabled: config?.keep_alive?.enabled ?? true, + } return new ClickHouseClient({ impl: { - make_connection: (params: ConnectionParams) => new WebConnection(params), + make_connection: (params: ConnectionParams) => + new WebConnection({ ...params, keep_alive }), make_result_set: ( stream: ReadableStream, format: DataFormat, diff --git a/packages/client-web/src/connection/web_connection.ts b/packages/client-web/src/connection/web_connection.ts index 847ec65b..710736a7 100644 --- a/packages/client-web/src/connection/web_connection.ts +++ b/packages/client-web/src/connection/web_connection.ts @@ -24,9 +24,15 @@ type WebInsertParams = Omit< values: string } +export type WebConnectionParams = ConnectionParams & { + keep_alive: { + enabled: boolean + } +} + export class WebConnection implements Connection { private readonly defaultHeaders: Record - constructor(private readonly params: ConnectionParams) { + constructor(private readonly params: WebConnectionParams) { this.defaultHeaders = { Authorization: `Basic ${btoa(`${params.username}:${params.password}`)}`, } @@ -175,7 +181,7 @@ export class WebConnection implements Connection { const response = await fetch(url, { body: values, headers, - keepalive: false, + keepalive: this.params.keep_alive.enabled, method: method ?? 'POST', signal: abortController.signal, })