Skip to content

Commit d237995

Browse files
committed
[WIP] feat(clickhouse): Use ClickHouse query with parameters via HTTP interface
1 parent 8e815c2 commit d237995

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

packages/cubejs-clickhouse-driver/src/ClickHouseDriver.ts

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,41 @@ export class ClickHouseDriver extends BaseDriver implements DriverInterface {
222222
true;
223223
}
224224

225-
public async query(query: string, values: unknown[]) {
225+
public async query(query: string, values?: unknown[]) {
226226
return this.queryResponse(query, values).then((res: any) => this.normaliseResponse(res));
227227
}
228228

229-
protected queryResponse(query: string, values: unknown[]) {
230-
const formattedQuery = sqlstring.format(query, values);
229+
protected queryResponse(query: string, values?: unknown[]) {
230+
// todo drop this
231+
console.log('queryResponse call', query, values)
232+
233+
// const formattedQuery = sqlstring.format(query, values);
234+
const formattedQuery = query;
235+
236+
// `queryOptions` object will be merged into query params via querystring.stringify
237+
// https://github.com/cube-js/apla-node-clickhouse/blob/5a6577fc97ba6911171753fc65b2cd2f6170f2f7/src/clickhouse.js#L347-L348
238+
// https://github.com/cube-js/apla-node-clickhouse/blob/5a6577fc97ba6911171753fc65b2cd2f6170f2f7/src/clickhouse.js#L265-L266
239+
// https://github.com/cube-js/apla-node-clickhouse/blob/5a6577fc97ba6911171753fc65b2cd2f6170f2f7/src/clickhouse.js#L336-L338
240+
// https://github.com/cube-js/apla-node-clickhouse/blob/5a6577fc97ba6911171753fc65b2cd2f6170f2f7/src/clickhouse.js#L173-L175
241+
242+
// We can use `toSearchParams` or `formatQueryParams` from `@clickhouse/client-common` to prepare params, and extract only interesting ones
243+
// Beware - these functions marked as "For implementations usage only - should not be re-exported", so, probably, ot could be moved or disappear completely
244+
// https://github.com/ClickHouse/clickhouse-js/blob/a15cce93545c792852e34c05ce31954c75d11486/packages/client-common/src/utils/url.ts#L57-L61
245+
246+
// HTTP interface itself is documented, so it should be fine
247+
// https://clickhouse.com/docs/en/interfaces/cli#cli-queries-with-parameters
248+
// https://clickhouse.com/docs/en/interfaces/http#cli-queries-with-parameters
249+
250+
const paramsValues = Object.fromEntries((values ?? []).map((value, idx) => {
251+
const paramName = this.paramName(idx);
252+
const paramKey = `param_${paramName}`;
253+
// TODO prepare value
254+
const preparedValue = value;
255+
return [paramKey, preparedValue];
256+
}));
257+
258+
// todo drop this
259+
console.log('queryResponse prepared', formattedQuery, paramsValues);
231260

232261
return this.withConnection((connection, queryId) => connection.querying(formattedQuery, {
233262
dataObjects: true,
@@ -241,6 +270,9 @@ export class ClickHouseDriver extends BaseDriver implements DriverInterface {
241270
//
242271
//
243272
...(this.readOnlyMode ? {} : { join_use_nulls: 1 }),
273+
274+
// Add parameter values to query string
275+
...paramsValues,
244276
}
245277
}));
246278
}
@@ -309,6 +341,15 @@ export class ClickHouseDriver extends BaseDriver implements DriverInterface {
309341
return [{ schema_name: this.config.queryOptions.database }];
310342
}
311343

344+
protected paramName(paramIndex: number): string {
345+
return `p${paramIndex}`;
346+
}
347+
348+
public param(paramIndex: number): string {
349+
// TODO not always string
350+
return `{${this.paramName(paramIndex)}:String}`;
351+
}
352+
312353
public async stream(
313354
query: string,
314355
values: unknown[],

packages/cubejs-schema-compiler/src/adapter/ClickHouseQuery.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@ export class ClickHouseQuery extends BaseQuery {
268268

269269
public sqlTemplates() {
270270
const templates = super.sqlTemplates();
271+
// TODO not every param is a string
272+
// TODO override timeStampParam
273+
templates.params.param = '{p{{ param_index }}:String}';
271274
templates.functions.DATETRUNC = 'DATE_TRUNC({{ args_concat }})';
272275
// TODO: Introduce additional filter in jinja? or parseDateTimeBestEffort?
273276
// https://github.com/ClickHouse/ClickHouse/issues/19351

0 commit comments

Comments
 (0)