add run options to ui client (#15)

This commit is contained in:
Jeff Raymakers
2025-06-25 12:09:40 -07:00
committed by GitHub
parent 2a8db10c6a
commit 8ec47ccec9
3 changed files with 61 additions and 19 deletions

View File

@@ -1,11 +1,9 @@
import { DuckDBUIHttpRequestQueue } from '../../http/classes/DuckDBUIHttpRequestQueue.js'; import { DuckDBUIHttpRequestQueue } from '../../http/classes/DuckDBUIHttpRequestQueue.js';
import { import { makeDuckDBUIHttpRequestHeaders } from '../../http/functions/makeDuckDBUIHttpRequestHeaders.js';
DuckDBUIHttpRequestHeaderOptions,
makeDuckDBUIHttpRequestHeaders,
} from '../../http/functions/makeDuckDBUIHttpRequestHeaders.js';
import { sendDuckDBUIHttpRequest } from '../../http/functions/sendDuckDBUIHttpRequest.js'; import { sendDuckDBUIHttpRequest } from '../../http/functions/sendDuckDBUIHttpRequest.js';
import { randomString } from '../../util/functions/randomString.js'; import { randomString } from '../../util/functions/randomString.js';
import { materializedRunResultFromQueueResult } from '../functions/materializedRunResultFromQueueResult.js'; import { materializedRunResultFromQueueResult } from '../functions/materializedRunResultFromQueueResult.js';
import { DuckDBUIRunOptions } from '../types/DuckDBUIRunOptions.js';
import { MaterializedRunResult } from '../types/MaterializedRunResult.js'; import { MaterializedRunResult } from '../types/MaterializedRunResult.js';
export class DuckDBUIClientConnection { export class DuckDBUIClientConnection {
@@ -16,21 +14,21 @@ export class DuckDBUIClientConnection {
public async run( public async run(
sql: string, sql: string,
args?: unknown[], options?: DuckDBUIRunOptions,
): Promise<MaterializedRunResult> { ): Promise<MaterializedRunResult> {
const queueResult = await this.requestQueue.enqueueAndWait( const queueResult = await this.requestQueue.enqueueAndWait(
'/ddb/run', '/ddb/run',
sql, sql,
this.makeHeaders({ parameters: args }), this.makeHeaders(options),
); );
return materializedRunResultFromQueueResult(queueResult); return materializedRunResultFromQueueResult(queueResult);
} }
public enqueue(sql: string, args?: unknown[]): string { public enqueue(sql: string, options?: DuckDBUIRunOptions): string {
return this.requestQueue.enqueue( return this.requestQueue.enqueue(
'/ddb/run', '/ddb/run',
sql, sql,
this.makeHeaders({ parameters: args }), this.makeHeaders(options),
); );
} }
@@ -52,18 +50,16 @@ export class DuckDBUIClientConnection {
return true; return true;
} }
public async runQueued(id: string): Promise<MaterializedRunResult> { public async enqueuedResult(id: string): Promise<MaterializedRunResult> {
const queueResult = await this.requestQueue.enqueuedResult(id); const queueResult = await this.requestQueue.enqueuedResult(id);
return materializedRunResultFromQueueResult(queueResult); return materializedRunResultFromQueueResult(queueResult);
} }
public get queuedCount(): number { public get enqueuedCount(): number {
return this.requestQueue.length; return this.requestQueue.length;
} }
private makeHeaders( private makeHeaders(options: DuckDBUIRunOptions = {}): Headers {
options: Omit<DuckDBUIHttpRequestHeaderOptions, 'connectionName'> = {},
): Headers {
return makeDuckDBUIHttpRequestHeaders({ return makeDuckDBUIHttpRequestHeaders({
...options, ...options,
connectionName: this.connectionName, connectionName: this.connectionName,

View File

@@ -0,0 +1,12 @@
export interface DuckDBUIRunOptions {
description?: string;
databaseName?: string;
schemaName?: string;
errorsAsJson?: boolean;
parameters?: unknown[];
resultChunkLimit?: number;
resultDatabaseName?: string;
resultSchemaName?: string;
resultTableName?: string;
resultTableChunkLimit?: number;
}

View File

@@ -1,19 +1,25 @@
import { DuckDBUIRunOptions } from '../../client/types/DuckDBUIRunOptions.js';
import { toBase64 } from '../../util/functions/toBase64.js'; import { toBase64 } from '../../util/functions/toBase64.js';
export interface DuckDBUIHttpRequestHeaderOptions { export interface DuckDBUIHttpRequestHeaderOptions extends DuckDBUIRunOptions {
description?: string;
connectionName?: string; connectionName?: string;
databaseName?: string;
parameters?: unknown[];
} }
export function makeDuckDBUIHttpRequestHeaders({ export function makeDuckDBUIHttpRequestHeaders({
description, description,
connectionName, connectionName,
databaseName, databaseName,
schemaName,
errorsAsJson,
parameters, parameters,
resultChunkLimit,
resultDatabaseName,
resultSchemaName,
resultTableName,
resultTableChunkLimit,
}: DuckDBUIHttpRequestHeaderOptions): Headers { }: DuckDBUIHttpRequestHeaderOptions): Headers {
const headers = new Headers(); const headers = new Headers();
// We base64 encode some values because they can contain characters invalid in an HTTP header.
if (description) { if (description) {
headers.append('X-DuckDB-UI-Request-Description', description); headers.append('X-DuckDB-UI-Request-Description', description);
} }
@@ -21,13 +27,14 @@ export function makeDuckDBUIHttpRequestHeaders({
headers.append('X-DuckDB-UI-Connection-Name', connectionName); headers.append('X-DuckDB-UI-Connection-Name', connectionName);
} }
if (databaseName) { if (databaseName) {
// base64 encode the value because it can contain characters invalid in an HTTP header
headers.append('X-DuckDB-UI-Database-Name', toBase64(databaseName)); headers.append('X-DuckDB-UI-Database-Name', toBase64(databaseName));
} }
if (schemaName) {
headers.append('X-DuckDB-UI-Schema-Name', toBase64(schemaName));
}
if (parameters) { if (parameters) {
headers.append('X-DuckDB-UI-Parameter-Count', String(parameters.length)); headers.append('X-DuckDB-UI-Parameter-Count', String(parameters.length));
for (let i = 0; i < parameters.length; i++) { for (let i = 0; i < parameters.length; i++) {
// base64 encode the value because it can contain characters invalid in an HTTP header
// TODO: support non-string parameters? // TODO: support non-string parameters?
headers.append( headers.append(
`X-DuckDB-UI-Parameter-Value-${i}`, `X-DuckDB-UI-Parameter-Value-${i}`,
@@ -35,5 +42,32 @@ export function makeDuckDBUIHttpRequestHeaders({
); );
} }
} }
if (resultChunkLimit !== undefined) {
headers.append('X-DuckDB-UI-Result-Chunk-Limit', String(resultChunkLimit));
}
if (resultDatabaseName) {
headers.append(
'X-DuckDB-UI-Result-Database-Name',
toBase64(resultDatabaseName),
);
}
if (resultSchemaName) {
headers.append(
'X-DuckDB-UI-Result-Schema-Name',
toBase64(resultSchemaName),
);
}
if (resultTableName) {
headers.append('X-DuckDB-UI-Result-Table-Name', toBase64(resultTableName));
}
if (resultTableChunkLimit !== undefined) {
headers.append(
'X-DuckDB-UI-Result-Table-Chunk-Limit',
String(resultTableChunkLimit),
);
}
if (errorsAsJson) {
headers.append('X-DuckDB-UI-Errors-As-JSON', 'true');
}
return headers; return headers;
} }