Skip to content

Commit

Permalink
Expose X-ClickHouse-Summary header info (#214)
Browse files Browse the repository at this point in the history
  • Loading branch information
slvrtrn authored Dec 13, 2023
1 parent ff466cb commit 152b89a
Show file tree
Hide file tree
Showing 12 changed files with 186 additions and 59 deletions.
2 changes: 1 addition & 1 deletion .docker/clickhouse/single_node_tls/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM clickhouse/clickhouse-server:23.10-alpine
FROM clickhouse/clickhouse-server:23.11-alpine
COPY .docker/clickhouse/single_node_tls/certificates /etc/clickhouse-server/certs
RUN chown clickhouse:clickhouse -R /etc/clickhouse-server/certs \
&& chmod 600 /etc/clickhouse-server/certs/* \
Expand Down
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
## 0.2.7 (Web only)
## 0.2.7 (Common, Node.js, Web)

### New features

- (Node.js only) `X-ClickHouse-Summary` response header is now parsed when working with `insert`/`exec`/`command` methods.
See the [related test](./packages/client-node/__tests__/integration/node_summary.test.ts) for more details.
NB: it is guaranteed to be correct only for non-streaming scenarios.
Web version does not currently support this due to CORS limitations. ([#210](https://github.com/ClickHouse/clickhouse-js/issues/210))

### Bug fixes

Expand Down
4 changes: 2 additions & 2 deletions docker-compose.cluster.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: '2.3'

services:
clickhouse1:
image: 'clickhouse/clickhouse-server:${CLICKHOUSE_VERSION-23.10-alpine}'
image: 'clickhouse/clickhouse-server:${CLICKHOUSE_VERSION-23.11-alpine}'
ulimits:
nofile:
soft: 262144
Expand All @@ -19,7 +19,7 @@ services:
- './.docker/clickhouse/users.xml:/etc/clickhouse-server/users.xml'

clickhouse2:
image: 'clickhouse/clickhouse-server:${CLICKHOUSE_VERSION-23.10-alpine}'
image: 'clickhouse/clickhouse-server:${CLICKHOUSE_VERSION-23.11-alpine}'
ulimits:
nofile:
soft: 262144
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: '3.8'
services:
clickhouse:
image: 'clickhouse/clickhouse-server:${CLICKHOUSE_VERSION-23.10-alpine}'
image: 'clickhouse/clickhouse-server:${CLICKHOUSE_VERSION-23.11-alpine}'
container_name: 'clickhouse-js-clickhouse-server'
ports:
- '8123:8123'
Expand Down
2 changes: 1 addition & 1 deletion karma.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const TEST_TIMEOUT_MS = 120_000

module.exports = function (config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
// base path that will be used to resolve all patterns (e.g. files, exclude)
basePath: '',
frameworks: ['webpack', 'jasmine'],
// list of files / patterns to load in the browser
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe('insert', () => {
let tableName: string

beforeEach(async () => {
client = await createTestClient()
client = createTestClient()
tableName = `insert_test_${guid()}`
await createSimpleTable(client, tableName)
})
Expand Down
15 changes: 15 additions & 0 deletions packages/client-common/src/clickhouse_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,18 @@ export interface InputJSON<T = unknown> {
}

export type InputJSONObjectEachRow<T = unknown> = Record<string, T>

export interface ClickHouseSummary {
read_rows: string
read_bytes: string
written_rows: string
written_bytes: string
total_rows_to_read: string
result_rows: string
result_bytes: string
elapsed_ns: string
}

export interface WithClickHouseSummary {
summary?: ClickHouseSummary
}
15 changes: 7 additions & 8 deletions packages/client-common/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import type {
Connection,
ConnectionParams,
ConnInsertResult,
ConnQueryResult,
Logger,
WithClickHouseSummary,
ConnExecResult,
} from '@clickhouse/client-common'
import {
type DataFormat,
Expand Down Expand Up @@ -76,7 +77,7 @@ export interface ClickHouseClientConfigOptions<Stream> {
username?: string
/** The user password. Default: ''. */
password?: string
/** The name of the application using the nodejs client.
/** The name of the application using the JS client.
* Default: empty. */
application?: string
/** Database name to use. Default value: `default`. */
Expand Down Expand Up @@ -124,12 +125,10 @@ export interface ExecParams extends BaseQueryParams {
}

export type CommandParams = ExecParams
export interface CommandResult {
query_id: string
}
export type CommandResult = { query_id: string } & WithClickHouseSummary

export type InsertResult = ConnInsertResult
export type ExecResult<Stream> = ConnQueryResult<Stream>
export type ExecResult<Stream> = ConnExecResult<Stream>
export type PingResult = ConnPingResult

export type InsertValues<Stream, T = unknown> =
Expand Down Expand Up @@ -203,9 +202,9 @@ export class ClickHouseClient<Stream = unknown> {
* If you are interested in the response data, consider using {@link ClickHouseClient.exec}
*/
async command(params: CommandParams): Promise<CommandResult> {
const { stream, query_id } = await this.exec(params)
const { stream, query_id, summary } = await this.exec(params)
await this.closeStream(stream)
return { query_id }
return { query_id, summary }
}

/**
Expand Down
6 changes: 4 additions & 2 deletions packages/client-common/src/connection.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { WithClickHouseSummary } from './clickhouse_types'
import type { LogWriter } from './logger'
import type { ClickHouseSettings } from './settings'

Expand Down Expand Up @@ -39,8 +40,9 @@ export interface ConnQueryResult<Stream> extends ConnBaseResult {
query_id: string
}

export type ConnInsertResult = ConnBaseResult
export type ConnExecResult<Stream> = ConnQueryResult<Stream>
export type ConnInsertResult = ConnBaseResult & WithClickHouseSummary
export type ConnExecResult<Stream> = ConnQueryResult<Stream> &
WithClickHouseSummary

export type ConnPingResult =
| {
Expand Down
2 changes: 2 additions & 0 deletions packages/client-common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export {
type LogParams,
} from './logger'
export type {
ClickHouseSummary,
WithClickHouseSummary,
ResponseJSON,
InputJSON,
InputJSONObjectEachRow,
Expand Down
70 changes: 70 additions & 0 deletions packages/client-node/__tests__/integration/node_summary.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import type { ClickHouseClient } from '@clickhouse/client-common'
import { createSimpleTable } from '@test/fixtures/simple_table'
import { jsonValues } from '@test/fixtures/test_data'
import { createTestClient, guid } from '@test/utils'
import type Stream from 'stream'

describe('[Node.js] Summary header parsing', () => {
let client: ClickHouseClient<Stream.Readable>
let tableName: string

beforeAll(async () => {
client = createTestClient()
tableName = `summary_test_${guid()}`
await createSimpleTable(client, tableName)
})
afterAll(async () => {
await client.close()
})

it('should provide summary for insert/exec', async () => {
const { summary: insertSummary } = await client.insert({
table: tableName,
values: jsonValues,
format: 'JSONEachRow',
})
expect(insertSummary).toEqual({
read_rows: '5',
read_bytes: jasmine.any(String),
written_rows: '5',
written_bytes: jasmine.any(String),
total_rows_to_read: '0',
result_rows: '5',
result_bytes: jasmine.any(String),
elapsed_ns: jasmine.any(String),
})

const { summary: execSummary } = await client.exec({
query: `INSERT INTO ${tableName} SELECT * FROM ${tableName}`,
})
expect(execSummary).toEqual({
read_rows: '5',
read_bytes: jasmine.any(String),
written_rows: '5',
written_bytes: jasmine.any(String),
total_rows_to_read: '5',
result_rows: '5',
result_bytes: jasmine.any(String),
elapsed_ns: jasmine.any(String),
})
})

it('should provide summary for command', async () => {
const { summary } = await client.command({
query: `INSERT INTO ${tableName} VALUES (144, 'Hello', [2, 4]), (255, 'World', [3, 5])`,
clickhouse_settings: {
wait_end_of_query: 1,
},
})
expect(summary).toEqual({
read_rows: '2',
read_bytes: jasmine.any(String),
written_rows: '2',
written_bytes: jasmine.any(String),
total_rows_to_read: '0',
result_rows: '2',
result_bytes: jasmine.any(String),
elapsed_ns: jasmine.any(String),
})
})
})
Loading

0 comments on commit 152b89a

Please sign in to comment.