@clickhouse/client 1.18.5 → 1.19.0-head.ee91a12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +2 -2
- package/skills/clickhouse-js-node-coding/SKILL.md +12 -19
- package/skills/clickhouse-js-node-coding/reference/async-insert.md +10 -6
- package/skills/clickhouse-js-node-coding/reference/client-configuration.md +5 -41
- package/skills/clickhouse-js-node-coding/reference/custom-json.md +59 -15
- package/skills/clickhouse-js-node-coding/reference/data-types.md +58 -6
- package/skills/clickhouse-js-node-coding/reference/insert-columns.md +1 -7
- package/skills/clickhouse-js-node-coding/reference/insert-formats.md +10 -13
- package/skills/clickhouse-js-node-coding/reference/insert-values.md +10 -10
- package/skills/clickhouse-js-node-coding/reference/ping.md +25 -4
- package/skills/clickhouse-js-node-coding/reference/query-parameters.md +7 -7
- package/skills/clickhouse-js-node-coding/reference/select-formats.md +3 -5
- package/skills/clickhouse-js-node-coding/reference/sessions.md +40 -14
- package/skills/clickhouse-js-node-coding/evals/evals.json +0 -103
- package/skills/clickhouse-js-node-troubleshooting/evals/evals.json +0 -126
package/dist/index.d.ts
CHANGED
|
@@ -4,4 +4,4 @@ export { type NodeClickHouseClientConfigOptions as ClickHouseClientConfigOptions
|
|
|
4
4
|
export { ResultSet, type StreamReadable } from './result_set';
|
|
5
5
|
export { drainStream } from './connection/stream';
|
|
6
6
|
/** Re-export @clickhouse/client-common types */
|
|
7
|
-
export { type BaseClickHouseClientConfigOptions, type BaseQueryParams, type QueryParams, type ExecParams, type InsertParams, type InsertValues, type CommandParams, type CommandResult, type ExecResult, type InsertResult, type DataFormat, type RawDataFormat, type JSONDataFormat, type StreamableDataFormat, type StreamableJSONDataFormat, type SingleDocumentJSONFormat, type Logger, type LogParams, type ErrorLogParams, type WarnLogParams, type ClickHouseSettings, type MergeTreeSettings, type Row, type ResponseJSON, type InputJSON, type InputJSONObjectEachRow, type BaseResultSet, type PingResult, ClickHouseError, parseError, ClickHouseLogLevel, SettingsMap, SupportedJSONFormats, SupportedRawFormats, StreamableFormats, StreamableJSONFormats, SingleDocumentJSONFormats, RecordsJSONFormats, type SimpleColumnType, type ParsedColumnSimple, type ParsedColumnEnum, type ParsedColumnFixedString, type ParsedColumnNullable, type ParsedColumnDecimal, type ParsedColumnDateTime, type ParsedColumnDateTime64, type ParsedColumnArray, type ParsedColumnTuple, type ParsedColumnMap, type ParsedColumnType, parseColumnType, SimpleColumnTypes, type ProgressRow, isProgressRow, isRow, isException, type RowOrProgress, type ClickHouseAuth, type ClickHouseJWTAuth, type ClickHouseCredentialsAuth, TupleParam, } from '@clickhouse/client-common';
|
|
7
|
+
export { type BaseClickHouseClientConfigOptions, type BaseQueryParams, type QueryParams, type ExecParams, type InsertParams, type InsertValues, type CommandParams, type CommandResult, type ExecResult, type InsertResult, type DataFormat, type RawDataFormat, type JSONDataFormat, type StreamableDataFormat, type StreamableJSONDataFormat, type SingleDocumentJSONFormat, type Logger, type LogParams, type ErrorLogParams, type WarnLogParams, type ClickHouseSettings, type MergeTreeSettings, type Row, type ResponseJSON, type InputJSON, type InputJSONObjectEachRow, type BaseResultSet, type PingResult, type ResponseHeaders, ClickHouseError, parseError, ClickHouseLogLevel, SettingsMap, SupportedJSONFormats, SupportedRawFormats, StreamableFormats, StreamableJSONFormats, SingleDocumentJSONFormats, RecordsJSONFormats, type SimpleColumnType, type ParsedColumnSimple, type ParsedColumnEnum, type ParsedColumnFixedString, type ParsedColumnNullable, type ParsedColumnDecimal, type ParsedColumnDateTime, type ParsedColumnDateTime64, type ParsedColumnArray, type ParsedColumnTuple, type ParsedColumnMap, type ParsedColumnType, parseColumnType, SimpleColumnTypes, type ProgressRow, isProgressRow, isRow, isException, type RowOrProgress, type ClickHouseAuth, type ClickHouseJWTAuth, type ClickHouseCredentialsAuth, TupleParam, } from '@clickhouse/client-common';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mCAGiB;AAFf,0GAAA,oBAAoB,OAAoB;AAG1C,mCAAuC;AAA9B,sGAAA,YAAY,OAAA;AAErB,2CAA6D;AAApD,uGAAA,SAAS,OAAA;AAClB,8CAAiD;AAAxC,qGAAA,WAAW,OAAA;AAEpB,gDAAgD;AAChD,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mCAGiB;AAFf,0GAAA,oBAAoB,OAAoB;AAG1C,mCAAuC;AAA9B,sGAAA,YAAY,OAAA;AAErB,2CAA6D;AAApD,uGAAA,SAAS,OAAA;AAClB,8CAAiD;AAAxC,qGAAA,WAAW,OAAA;AAEpB,gDAAgD;AAChD,2DA+DkC;AAjChC,gHAAA,eAAe,OAAA;AACf,2GAAA,UAAU,OAAA;AACV,mHAAA,kBAAkB,OAAA;AAClB,4GAAA,WAAW,OAAA;AACX,qHAAA,oBAAoB,OAAA;AACpB,oHAAA,mBAAmB,OAAA;AACnB,kHAAA,iBAAiB,OAAA;AACjB,sHAAA,qBAAqB,OAAA;AACrB,0HAAA,yBAAyB,OAAA;AACzB,mHAAA,kBAAkB,OAAA;AAalB,gHAAA,eAAe,OAAA;AACf,kHAAA,iBAAiB,OAAA;AAEjB,8GAAA,aAAa,OAAA;AACb,sGAAA,KAAK,OAAA;AACL,4GAAA,WAAW,OAAA;AAKX,2GAAA,UAAU,OAAA"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: "1.
|
|
1
|
+
declare const _default: "1.19.0-head.ee91a12.1";
|
|
2
2
|
export default _default;
|
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":";;AAAA,kBAAe,
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":";;AAAA,kBAAe,uBAAuB,CAAA"}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@clickhouse/client",
|
|
3
3
|
"description": "Official JS client for ClickHouse DB - Node.js implementation",
|
|
4
4
|
"homepage": "https://clickhouse.com",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.19.0-head.ee91a12.1",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"clickhouse",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"build": "rm -rf dist; tsc"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@clickhouse/client-common": "1.
|
|
47
|
+
"@clickhouse/client-common": "1.19.0-head.ee91a12.1"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"simdjson": "^0.9.2"
|
|
@@ -5,14 +5,8 @@ description: >
|
|
|
5
5
|
(`@clickhouse/client`). Use this skill whenever a user is *building* against
|
|
6
6
|
the Node.js client — configuring the client, pinging, inserting rows in JSON
|
|
7
7
|
or raw formats, selecting and parsing results, binding query parameters,
|
|
8
|
-
managing sessions and temporary tables, working with data types
|
|
9
|
-
|
|
10
|
-
customizing JSON parsing. Trigger on phrases like "how do I insert…", "how
|
|
11
|
-
do I select…", "what format should I use…", "how do I parameterize…", "how
|
|
12
|
-
do I configure the client…". Do NOT use for browser/Web client code, for
|
|
13
|
-
performance/streaming/Parquet questions (see `examples/node/performance/`),
|
|
14
|
-
or for diagnosing errors and unexpected behavior (see
|
|
15
|
-
clickhouse-js-node-troubleshooting).
|
|
8
|
+
managing sessions and temporary tables, working with data types or
|
|
9
|
+
customizing JSON parsing. Do NOT use for browser/Web client code.
|
|
16
10
|
---
|
|
17
11
|
|
|
18
12
|
# ClickHouse Node.js Client — Coding
|
|
@@ -37,9 +31,9 @@ Reference: https://clickhouse.com/docs/integrations/javascript
|
|
|
37
31
|
each relevant item; those checklists capture details users usually need but
|
|
38
32
|
are easy to omit in short answers.
|
|
39
33
|
2. **Always import from `@clickhouse/client`** (never `@clickhouse/client-web`)
|
|
40
|
-
and create a
|
|
34
|
+
and create a client with `createClient({ url })` or rely on
|
|
41
35
|
supported defaults when appropriate. Close it with `await client.close()`
|
|
42
|
-
during graceful shutdown.
|
|
36
|
+
preferably when it's no longer needed or during graceful shutdown for global resources.
|
|
43
37
|
3. **Prefer `JSONEachRow` for typical row inserts/selects** unless the user
|
|
44
38
|
has already chosen another format or is streaming raw bytes (CSV / TSV /
|
|
45
39
|
Parquet — see `examples/node/performance/`).
|
|
@@ -49,6 +43,12 @@ Reference: https://clickhouse.com/docs/integrations/javascript
|
|
|
49
43
|
Always mention this when the user configures settings at the client level.
|
|
50
44
|
4. **Always use `query_params` for user-supplied values** — never template-
|
|
51
45
|
literal-interpolate them into SQL. See `reference/query-parameters.md`.
|
|
46
|
+
**When answering a parameter-binding question, your response must
|
|
47
|
+
explicitly name template-literal interpolation as a "SQL injection
|
|
48
|
+
risk"** — even when the user only asked about syntax and did not raise
|
|
49
|
+
security. The literal phrase "SQL injection" needs to appear; this is
|
|
50
|
+
the most common mistake from PostgreSQL/MySQL users and the security
|
|
51
|
+
framing is part of the correct answer, not an optional aside.
|
|
52
52
|
5. **Pick the right method for the job:**
|
|
53
53
|
- `client.insert()` — write rows.
|
|
54
54
|
- `client.query()` + `resultSet.json()` / `.text()` / `.stream()` — read
|
|
@@ -67,10 +67,6 @@ Reference: https://clickhouse.com/docs/integrations/javascript
|
|
|
67
67
|
- `Time` / `Time64` data types: ClickHouse server `>= 25.6`.
|
|
68
68
|
- `Dynamic` / `Variant` / new `JSON` types: ClickHouse server `>= 24.1` /
|
|
69
69
|
`24.5` / `24.8` (no longer experimental since `25.3`).
|
|
70
|
-
7. **Show a runnable snippet**, not pseudo-code. The examples in
|
|
71
|
-
[`examples/node/coding/`](https://github.com/ClickHouse/clickhouse-js/tree/main/examples/node/coding)
|
|
72
|
-
are all self-contained and runnable against the repo's `docker-compose up`
|
|
73
|
-
setup — pattern your snippet after them.
|
|
74
70
|
|
|
75
71
|
---
|
|
76
72
|
|
|
@@ -97,16 +93,13 @@ Identify the user's task and read the matching reference file.
|
|
|
97
93
|
## Conventions used in answers
|
|
98
94
|
|
|
99
95
|
- Always show `import { createClient } from '@clickhouse/client'` (Node, never
|
|
100
|
-
Web).
|
|
101
|
-
(e.g., `import * as crypto from 'node:crypto'`).
|
|
96
|
+
Web).
|
|
102
97
|
- Always `await client.close()` at the end of self-contained snippets; in
|
|
103
98
|
long-running services, close on graceful shutdown.
|
|
104
|
-
- Prefer top-level `await` in snippets to match the style of
|
|
105
|
-
`examples/node/coding/*.ts`.
|
|
106
99
|
- For inserts, prefer `format: 'JSONEachRow'` and `values: [...]` unless the
|
|
107
100
|
user's scenario requires otherwise.
|
|
108
101
|
- For selects, prefer `await (await client.query({...})).json<RowType>()` for
|
|
109
|
-
small / medium result sets; for
|
|
102
|
+
small / medium result sets; for bigger results suggest streaming.
|
|
110
103
|
- When showing parameter binding, use ClickHouse's native `{name: Type}`
|
|
111
104
|
syntax — never `$1`, `?`, or `:name`.
|
|
112
105
|
- For DDL inside a cluster or behind a load balancer, set
|
|
@@ -3,9 +3,6 @@
|
|
|
3
3
|
> **Applies to:** all client versions; the relevant settings are server-side.
|
|
4
4
|
> See https://clickhouse.com/docs/en/optimize/asynchronous-inserts.
|
|
5
5
|
|
|
6
|
-
Backing example:
|
|
7
|
-
[`examples/node/coding/async_insert.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/async_insert.ts).
|
|
8
|
-
|
|
9
6
|
> **When to use async inserts:** when many small inserts arrive concurrently
|
|
10
7
|
> (e.g., one per HTTP request) and you don't want to maintain a client-side
|
|
11
8
|
> batching layer. ClickHouse will batch them server-side. This is also the
|
|
@@ -13,12 +10,11 @@ Backing example:
|
|
|
13
10
|
|
|
14
11
|
> **When _not_ to use async inserts:** when you already build large batches
|
|
15
12
|
> client-side (e.g., from a stream). Plain inserts are simpler and lower
|
|
16
|
-
> latency.
|
|
17
|
-
> [`examples/node/performance/`](https://github.com/ClickHouse/clickhouse-js/tree/main/examples/node/performance).
|
|
13
|
+
> latency.
|
|
18
14
|
|
|
19
15
|
## Setup
|
|
20
16
|
|
|
21
|
-
Enable on the client
|
|
17
|
+
Enable on the client level or per-request via `clickhouse_settings`:
|
|
22
18
|
|
|
23
19
|
```ts
|
|
24
20
|
import { createClient, ClickHouseError } from '@clickhouse/client'
|
|
@@ -89,6 +85,9 @@ await client.command({
|
|
|
89
85
|
})
|
|
90
86
|
```
|
|
91
87
|
|
|
88
|
+
Even better is to create a specialized client for inserts with the appropriate async
|
|
89
|
+
settings and a separate client for DDL and other queries.
|
|
90
|
+
|
|
92
91
|
## Common pitfalls
|
|
93
92
|
|
|
94
93
|
- **Setting `async_insert` per call but expecting client-side batching.**
|
|
@@ -101,3 +100,8 @@ await client.command({
|
|
|
101
100
|
failures will not surface to the client.
|
|
102
101
|
- **Not handling `ClickHouseError`.** It exposes `err.code`, which maps to
|
|
103
102
|
rows in the `system.errors` table — use it to decide whether to retry.
|
|
103
|
+
|
|
104
|
+
## See also
|
|
105
|
+
|
|
106
|
+
- For raw throughput tuning of large async-insert workloads,
|
|
107
|
+
see [`examples/node/performance/`](https://github.com/ClickHouse/clickhouse-js/tree/main/examples/node/performance).
|
|
@@ -6,11 +6,6 @@
|
|
|
6
6
|
> - `clickhouse_setting_*` / `ch_*` URL parameters: client `>= 1.0.0`.
|
|
7
7
|
> - `keep_alive.idle_socket_ttl` (Node-only): client `>= 1.0.0`.
|
|
8
8
|
|
|
9
|
-
Backing examples:
|
|
10
|
-
[`examples/node/coding/url_configuration.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/url_configuration.ts),
|
|
11
|
-
[`examples/node/coding/clickhouse_settings.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/clickhouse_settings.ts),
|
|
12
|
-
[`examples/node/coding/default_format_setting.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/default_format_setting.ts).
|
|
13
|
-
|
|
14
9
|
## Answer checklist
|
|
15
10
|
|
|
16
11
|
When answering configuration questions, include the relevant points:
|
|
@@ -53,22 +48,7 @@ await client.close()
|
|
|
53
48
|
http[s]://[username:password@]hostname:port[/database][?param1=value1¶m2=value2]
|
|
54
49
|
```
|
|
55
50
|
|
|
56
|
-
## Configuration via URL
|
|
57
|
-
|
|
58
|
-
A fixed allowlist of config fields can be set as URL query parameters
|
|
59
|
-
(plus any key prefixed with `clickhouse_setting_` / `ch_` / `http_header_`).
|
|
60
|
-
**Supported URL parameters override the corresponding values in the rest of
|
|
61
|
-
the configuration object** — when they do, the client logs a warning.
|
|
62
|
-
Unknown URL parameters cause `createClient` to throw
|
|
63
|
-
`Unknown URL parameters: ...`
|
|
64
|
-
(see [`packages/client-common/src/config.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/packages/client-common/src/config.ts) for the shared allowlist, and [`packages/client-node/src/config.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/packages/client-node/src/config.ts) for Node-specific URL parameters).
|
|
65
|
-
|
|
66
|
-
Supported non-prefixed keys parsed by `client-common`: `application`,
|
|
67
|
-
`session_id`, `pathname`, `access_token`, `request_timeout`,
|
|
68
|
-
`max_open_connections`, `compression_request`, `compression_response`,
|
|
69
|
-
`log_level`, `keep_alive_enabled`. Additionally, Node supports
|
|
70
|
-
`keep_alive_idle_socket_ttl` via the Node-specific config implementation.
|
|
71
|
-
Anything else must be passed via the config object on `createClient`.
|
|
51
|
+
## Configuration via URL
|
|
72
52
|
|
|
73
53
|
Prefer explicit object fields in application code. Use the URL form when the
|
|
74
54
|
application receives one connection string from an environment variable, secret
|
|
@@ -77,7 +57,7 @@ source code — show it as a shell export and read it in Node:
|
|
|
77
57
|
|
|
78
58
|
```bash
|
|
79
59
|
# In your shell environment / deployment config (e.g. .env, Kubernetes secret):
|
|
80
|
-
export CLICKHOUSE_URL='https://bob:secret@my.host:8124/analytics
|
|
60
|
+
export CLICKHOUSE_URL='https://bob:secret@my.host:8124/analytics'
|
|
81
61
|
```
|
|
82
62
|
|
|
83
63
|
```ts
|
|
@@ -85,21 +65,6 @@ export CLICKHOUSE_URL='https://bob:secret@my.host:8124/analytics?application=my_
|
|
|
85
65
|
const client = createClient({ url: process.env.CLICKHOUSE_URL })
|
|
86
66
|
```
|
|
87
67
|
|
|
88
|
-
The same connection can also be expressed as an explicit config object (useful when you want to document each field individually):
|
|
89
|
-
|
|
90
|
-
```ts
|
|
91
|
-
import { createClient } from '@clickhouse/client'
|
|
92
|
-
|
|
93
|
-
createClient({
|
|
94
|
-
url: 'https://my.host:8124',
|
|
95
|
-
username: 'bob',
|
|
96
|
-
password: 'secret',
|
|
97
|
-
database: 'analytics',
|
|
98
|
-
application: 'my_analytics_app',
|
|
99
|
-
clickhouse_settings: { async_insert: 1, wait_for_async_insert: 0 },
|
|
100
|
-
})
|
|
101
|
-
```
|
|
102
|
-
|
|
103
68
|
## Per-client vs per-request `clickhouse_settings` ⭐
|
|
104
69
|
|
|
105
70
|
> **Always mention this when discussing `clickhouse_settings`:** settings set
|
|
@@ -112,13 +77,12 @@ for **that call only**.
|
|
|
112
77
|
```ts
|
|
113
78
|
const client = createClient({
|
|
114
79
|
clickhouse_settings: {
|
|
115
|
-
|
|
80
|
+
output_format_json_quote_64bit_integers: 0, // applied to every request
|
|
116
81
|
},
|
|
117
82
|
})
|
|
118
83
|
|
|
119
84
|
const rows = await client.query({
|
|
120
|
-
query: 'SELECT number FROM system.numbers LIMIT 2',
|
|
121
|
-
format: 'JSONEachRow',
|
|
85
|
+
query: 'SELECT number FROM system.numbers LIMIT 2 FORMAT JSONEachRow',
|
|
122
86
|
clickhouse_settings: {
|
|
123
87
|
output_format_json_quote_64bit_integers: 1, // overrides client default for this call
|
|
124
88
|
},
|
|
@@ -155,5 +119,5 @@ only needed for raw `exec()`.
|
|
|
155
119
|
for the DB. (Symptom: "wrong database selected.") See the
|
|
156
120
|
troubleshooting skill for diagnosis.
|
|
157
121
|
- **Don't create a client per request.** `createClient` opens a connection
|
|
158
|
-
pool; share one client across
|
|
122
|
+
pool; share one client across requests and `close()` on shutdown.
|
|
159
123
|
- **`max_open_connections` must be `>= 1`** when set explicitly.
|
|
@@ -3,9 +3,6 @@
|
|
|
3
3
|
> **Requires:** client `>= 1.14.0` (configurable `json.parse` and
|
|
4
4
|
> `json.stringify`). Earlier versions cannot swap the JSON implementation.
|
|
5
5
|
|
|
6
|
-
Backing example:
|
|
7
|
-
[`examples/node/coding/custom_json_handling.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/custom_json_handling.ts).
|
|
8
|
-
|
|
9
6
|
## Answer checklist
|
|
10
7
|
|
|
11
8
|
When the user wants `UInt64`/`Int64` values back as `BigInt`:
|
|
@@ -66,7 +63,7 @@ const valueSerializer = (value: unknown): unknown => {
|
|
|
66
63
|
|
|
67
64
|
const client = createClient({
|
|
68
65
|
json: {
|
|
69
|
-
parse: JSON.parse,
|
|
66
|
+
parse: JSON.parse, // use default parsing
|
|
70
67
|
stringify: (obj: unknown) => JSON.stringify(valueSerializer(obj)),
|
|
71
68
|
},
|
|
72
69
|
})
|
|
@@ -85,17 +82,12 @@ await client.insert({
|
|
|
85
82
|
format: 'JSONEachRow',
|
|
86
83
|
values: [
|
|
87
84
|
{
|
|
88
|
-
id: BigInt(250000000000000200), // serialized as a string
|
|
85
|
+
id: BigInt('250000000000000200'), // serialized as a string
|
|
89
86
|
dt: new Date(), // serialized as ms since epoch
|
|
90
87
|
},
|
|
91
88
|
],
|
|
92
89
|
})
|
|
93
90
|
|
|
94
|
-
const rows = await client.query({
|
|
95
|
-
query: 'SELECT * FROM inserts_custom_json_handling',
|
|
96
|
-
format: 'JSONEachRow',
|
|
97
|
-
})
|
|
98
|
-
console.info(await rows.json())
|
|
99
91
|
await client.close()
|
|
100
92
|
```
|
|
101
93
|
|
|
@@ -126,16 +118,65 @@ const client = createClient({
|
|
|
126
118
|
})
|
|
127
119
|
```
|
|
128
120
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
`json-bigint`
|
|
121
|
+
`output_format_json_quote_64bit_integers: 0` is the default since
|
|
122
|
+
ClickHouse `25.8`; setting it explicitly is useful for older servers and
|
|
123
|
+
makes the example self-contained. With it off, the server emits unquoted
|
|
124
|
+
64-bit integers that `json-bigint` parses straight to `BigInt`. The
|
|
125
|
+
`json` option applies to **both** outgoing JSON bodies and incoming
|
|
126
|
+
JSON-format responses.
|
|
127
|
+
|
|
128
|
+
## Recipe: Zero-dep BigInt parsing (no `npm install`)
|
|
129
|
+
|
|
130
|
+
If adding a dependency is awkward (locked lockfile, restricted environment,
|
|
131
|
+
or you just don't want to pull in `json-bigint`), you can plug in a
|
|
132
|
+
hand-rolled reviver. This uses the `context.source` argument that
|
|
133
|
+
`JSON.parse` revivers gained in Node `>= 20.16` / `>= 21.7`, so the raw
|
|
134
|
+
numeric literal is available before it's coerced to a JS `number`:
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
import { createClient } from '@clickhouse/client'
|
|
138
|
+
|
|
139
|
+
const parseBigInt = (text: string) =>
|
|
140
|
+
JSON.parse(text, function (key, value, context) {
|
|
141
|
+
if (key.endsWith('__bigint')) {
|
|
142
|
+
return BigInt(context.source)
|
|
143
|
+
}
|
|
144
|
+
return value
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
const client = createClient({
|
|
148
|
+
json: {
|
|
149
|
+
parse: parseBigInt,
|
|
150
|
+
stringify: JSON.stringify, // use default stringify
|
|
151
|
+
},
|
|
152
|
+
clickhouse_settings: { output_format_json_quote_64bit_integers: 0 },
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
const rs = await client.query({
|
|
156
|
+
query: 'SELECT toUInt64(250000000000000200) AS id__bigint',
|
|
157
|
+
})
|
|
158
|
+
const { data } = await rs.json()
|
|
159
|
+
console.log(data[0].id__bigint) // 250000000000000200
|
|
160
|
+
|
|
161
|
+
await client.close()
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Trade-offs versus `json-bigint`:
|
|
165
|
+
|
|
166
|
+
- ✓ No new dependency to install.
|
|
167
|
+
- ✓ Only promotes known to be 64-bit integers to `BigInt`.
|
|
168
|
+
- ✗ Requires Node `>= 20.16` / `>= 21.7` for the reviver `context.source`.
|
|
169
|
+
On older Node, prefer `json-bigint` or upgrade Node.
|
|
170
|
+
- ✗ Outgoing `stringify` still uses default `JSON.stringify`, which throws
|
|
171
|
+
on `BigInt`. Pair with the `valueSerializer` pattern above if your
|
|
172
|
+
inserts contain `BigInt` values.
|
|
133
173
|
|
|
134
174
|
## Common pitfalls
|
|
135
175
|
|
|
136
176
|
- **Setting `json.parse` only.** That only affects reading JSON responses;
|
|
137
177
|
outgoing JSON bodies use `json.stringify`. If you want consistent custom
|
|
138
|
-
handling in both directions, generally provide a matching `stringify` too
|
|
178
|
+
handling in both directions, generally provide a matching `stringify` too
|
|
179
|
+
or a throwing serializer that prevents mismatches.
|
|
139
180
|
- **Forgetting `bigint` handling in `stringify`.** Default `JSON.stringify`
|
|
140
181
|
throws on `BigInt`; if your data ever contains one, the insert will fail
|
|
141
182
|
with `TypeError: Do not know how to serialize a BigInt`.
|
|
@@ -147,3 +188,6 @@ default since CH 25.8) so the server emits unquoted 64-bit integers that
|
|
|
147
188
|
are silently rounded. Do **not** try to fix precision loss by calling
|
|
148
189
|
`Number()`, `parseInt()`, or `parseFloat()` on the value. The correct fix
|
|
149
190
|
is a `BigInt`-aware parser (shown above), not a lossy cast.
|
|
191
|
+
- **Mixing BigInt and number for the same column.** If some values are `BigInt` and
|
|
192
|
+
others are `number`, your app code needs to handle both types. Otherwise
|
|
193
|
+
JavaScript will throw a `TypeError: Cannot mix BigInt and other types`.
|
|
@@ -10,10 +10,6 @@
|
|
|
10
10
|
> - `Time` / `Time64`: ClickHouse `>= 25.6` and require
|
|
11
11
|
> `enable_time_time64_type: 1`.
|
|
12
12
|
|
|
13
|
-
Backing examples:
|
|
14
|
-
[`examples/node/coding/dynamic_variant_json.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/dynamic_variant_json.ts),
|
|
15
|
-
[`examples/node/coding/time_time64.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/time_time64.ts).
|
|
16
|
-
|
|
17
13
|
## Answer checklist
|
|
18
14
|
|
|
19
15
|
When answering about storing and reading JSON objects:
|
|
@@ -21,6 +17,29 @@ When answering about storing and reading JSON objects:
|
|
|
21
17
|
- Use the new `JSON` column type, introduced in ClickHouse `>= 24.8`.
|
|
22
18
|
- Say `JSON` is no longer experimental since ClickHouse `25.3`; on older
|
|
23
19
|
supported versions, enable `allow_experimental_json_type`.
|
|
20
|
+
- **State the version policy in your explanation AND inline in the code.**
|
|
21
|
+
When you set `allow_experimental_json_type` (or any `allow_experimental_*_type`)
|
|
22
|
+
in code, you must do BOTH of the following:
|
|
23
|
+
1. Put an inline comment directly above the setting that names the version
|
|
24
|
+
where the type was introduced and the version where it became
|
|
25
|
+
non-experimental. The comment is the durable version provenance — it
|
|
26
|
+
lives in the user's source file long after the chat reply is gone.
|
|
27
|
+
2. Repeat the version policy in your prose reply.
|
|
28
|
+
|
|
29
|
+
For the `JSON` column type the inline comment must look like:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
clickhouse_settings: {
|
|
33
|
+
// JSON type introduced in ClickHouse 24.8, non-experimental since 25.3.
|
|
34
|
+
// This setting is required only on 24.8–25.2; harmless on >= 25.3.
|
|
35
|
+
allow_experimental_json_type: 1,
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Without the inline comment, a reader on a newer server has no idea the
|
|
40
|
+
setting is a no-op and a reader on an older server has no idea why it's
|
|
41
|
+
required.
|
|
42
|
+
|
|
24
43
|
- Insert real JS objects with `format: 'JSONEachRow'`; do not
|
|
25
44
|
`JSON.stringify()` the column value.
|
|
26
45
|
- Read with a JSON output format such as `JSONEachRow` and `resultSet.json()`;
|
|
@@ -32,8 +51,10 @@ When answering about storing and reading JSON objects:
|
|
|
32
51
|
import { createClient } from '@clickhouse/client'
|
|
33
52
|
|
|
34
53
|
const client = createClient({
|
|
35
|
-
// Required only on ClickHouse < 25.3 — harmless to leave on
|
|
36
54
|
clickhouse_settings: {
|
|
55
|
+
// Variant introduced in 24.1, Dynamic in 24.5, JSON in 24.8.
|
|
56
|
+
// All three are non-experimental since 25.3; these settings are
|
|
57
|
+
// required only on 24.1–25.2 and are harmless on >= 25.3.
|
|
37
58
|
allow_experimental_variant_type: 1,
|
|
38
59
|
allow_experimental_dynamic_type: 1,
|
|
39
60
|
allow_experimental_json_type: 1,
|
|
@@ -77,6 +98,33 @@ const rs = await client.query({
|
|
|
77
98
|
console.log(await rs.json())
|
|
78
99
|
```
|
|
79
100
|
|
|
101
|
+
Outputs:
|
|
102
|
+
|
|
103
|
+
```js
|
|
104
|
+
;[
|
|
105
|
+
{
|
|
106
|
+
id: '1',
|
|
107
|
+
var: '42',
|
|
108
|
+
dynamic: 'foo',
|
|
109
|
+
json: { foo: 'x' },
|
|
110
|
+
'variantType(var)': 'Int64',
|
|
111
|
+
'dynamicType(dynamic)': 'String',
|
|
112
|
+
'dynamicType(json.foo)': 'String',
|
|
113
|
+
'dynamicType(json.bar)': 'None',
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: '2',
|
|
117
|
+
var: 'str',
|
|
118
|
+
dynamic: '144',
|
|
119
|
+
json: { bar: '10' },
|
|
120
|
+
'variantType(var)': 'String',
|
|
121
|
+
'dynamicType(dynamic)': 'Int64',
|
|
122
|
+
'dynamicType(json.foo)': 'None',
|
|
123
|
+
'dynamicType(json.bar)': 'Int64',
|
|
124
|
+
},
|
|
125
|
+
]
|
|
126
|
+
```
|
|
127
|
+
|
|
80
128
|
### Notes
|
|
81
129
|
|
|
82
130
|
- The `JSON` column type accepts a real JS object on insert and returns one
|
|
@@ -154,7 +202,8 @@ await client.insert({
|
|
|
154
202
|
- Pass values as **strings** in the `HH:MM:SS[.fraction]` format. Negatives
|
|
155
203
|
are supported; the magnitude can exceed 24 hours.
|
|
156
204
|
- For `Time64(p)` with `p > 3`, do not use JS `Date` — it tops out at
|
|
157
|
-
millisecond precision and will silently truncate.
|
|
205
|
+
millisecond precision and will silently truncate. Store nanosecond values
|
|
206
|
+
separately and provide on stringify as needed.
|
|
158
207
|
|
|
159
208
|
## Common pitfalls
|
|
160
209
|
|
|
@@ -167,3 +216,6 @@ await client.insert({
|
|
|
167
216
|
- **Reading a `Variant`/`Dynamic` value of type `Int64` and being surprised
|
|
168
217
|
it's a string.** That's the standard 64-bit-integers-in-JSON behavior;
|
|
169
218
|
see the troubleshooting skill if you need to change it.
|
|
219
|
+
- **Avoid parsing Variant/Dynamic/JSON columns that mix strings and 64-bit**
|
|
220
|
+
without checking their returned types first. Otherwise a number stored in
|
|
221
|
+
a string will come back as a number or vice versa.
|
|
@@ -3,12 +3,6 @@
|
|
|
3
3
|
> **Applies to:** all versions. The `columns` option (both forms) and the
|
|
4
4
|
> `database` config field are universally supported.
|
|
5
5
|
|
|
6
|
-
Backing examples:
|
|
7
|
-
[`examples/node/coding/insert_specific_columns.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/insert_specific_columns.ts),
|
|
8
|
-
[`examples/node/coding/insert_exclude_columns.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/insert_exclude_columns.ts),
|
|
9
|
-
[`examples/node/coding/insert_ephemeral_columns.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/insert_ephemeral_columns.ts),
|
|
10
|
-
[`examples/node/coding/insert_into_different_db.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/insert_into_different_db.ts).
|
|
11
|
-
|
|
12
6
|
## Answer checklist
|
|
13
7
|
|
|
14
8
|
When explaining partial-column inserts:
|
|
@@ -29,9 +23,9 @@ get their declared default.
|
|
|
29
23
|
```ts
|
|
30
24
|
await client.insert({
|
|
31
25
|
table: 'events',
|
|
26
|
+
columns: ['message'], // the rest of the events table columns get their DEFAULTs
|
|
32
27
|
format: 'JSONEachRow',
|
|
33
28
|
values: [{ message: 'foo' }],
|
|
34
|
-
columns: ['message'], // `id` will get its default (0 for UInt32)
|
|
35
29
|
})
|
|
36
30
|
```
|
|
37
31
|
|
|
@@ -4,14 +4,8 @@
|
|
|
4
4
|
> ClickHouse feature; the JSON _formats_ listed here are universally supported
|
|
5
5
|
> by the client.
|
|
6
6
|
|
|
7
|
-
Backing examples:
|
|
8
|
-
[`examples/node/coding/array_json_each_row.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/array_json_each_row.ts),
|
|
9
|
-
[`examples/node/coding/insert_data_formats_overview.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/insert_data_formats_overview.ts).
|
|
10
|
-
|
|
11
7
|
> **Raw / binary formats (CSV, TSV, CustomSeparated, Parquet) require a Node
|
|
12
|
-
> stream as input.**
|
|
13
|
-
> [`examples/node/performance/`](https://github.com/ClickHouse/clickhouse-js/tree/main/examples/node/performance)
|
|
14
|
-
> — defer if the user wants to insert from a file or `Readable`.
|
|
8
|
+
> stream as input.** Suggest streaming when the user wants to insert from a file or `Readable`.
|
|
15
9
|
|
|
16
10
|
## Answer checklist
|
|
17
11
|
|
|
@@ -125,12 +119,12 @@ await client.insert({
|
|
|
125
119
|
|
|
126
120
|
## Quick chooser
|
|
127
121
|
|
|
128
|
-
| Use case | Format
|
|
129
|
-
| -------------------------------------------- |
|
|
130
|
-
| Insert plain JS objects | `JSONEachRow` _(default)_
|
|
131
|
-
| Insert tuples / column-positional rows | `JSONCompactEachRow`
|
|
132
|
-
| Insert with explicit column ordering / types | `JSONCompactEachRow*WithNames…`
|
|
133
|
-
| Insert a single document with metadata | `JSON`, `JSONCompact`
|
|
122
|
+
| Use case | Format |
|
|
123
|
+
| -------------------------------------------- | ------------------------------------------------------- |
|
|
124
|
+
| Insert plain JS objects | `JSONEachRow` _(default)_ |
|
|
125
|
+
| Insert tuples / column-positional rows | `JSONCompactEachRow` |
|
|
126
|
+
| Insert with explicit column ordering / types | `JSONCompactEachRow*WithNames…` |
|
|
127
|
+
| Insert a single document with metadata | `JSON`, `JSONCompact` |
|
|
134
128
|
| Insert from a CSV / TSV / Parquet file | Raw format + Node stream → `examples/node/performance/` |
|
|
135
129
|
|
|
136
130
|
## Common pitfalls
|
|
@@ -143,3 +137,6 @@ await client.insert({
|
|
|
143
137
|
`JSONColumnsWithMetadata`).
|
|
144
138
|
- For type guidance (`Decimal` strings, `Date` objects, `BigInt`), see
|
|
145
139
|
`insert-values.md` and `custom-json.md`.
|
|
140
|
+
- **Use runtime type checkers like `zod` or `io-ts` if your app ingests untrusted JSON.**
|
|
141
|
+
It's easier to debug mismatches between your data and the format's expected shape with a validation library used at the place of ingestion than with ClickHouse errors.
|
|
142
|
+
This is especially true in the middle of a large insert batch or streaming operation.
|
|
@@ -3,12 +3,6 @@
|
|
|
3
3
|
> **Applies to:** all versions. `wait_end_of_query: 1` is a server-side
|
|
4
4
|
> setting available on every supported ClickHouse version.
|
|
5
5
|
|
|
6
|
-
Backing examples:
|
|
7
|
-
[`examples/node/coding/insert_from_select.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/insert_from_select.ts),
|
|
8
|
-
[`examples/node/coding/insert_values_and_functions.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/insert_values_and_functions.ts),
|
|
9
|
-
[`examples/node/coding/insert_js_dates.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/insert_js_dates.ts),
|
|
10
|
-
[`examples/node/coding/insert_decimals.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/insert_decimals.ts).
|
|
11
|
-
|
|
12
6
|
## `INSERT … SELECT` (no values payload)
|
|
13
7
|
|
|
14
8
|
When the data already lives in ClickHouse, use `client.command()` with a raw
|
|
@@ -18,7 +12,7 @@ When the data already lives in ClickHouse, use `client.command()` with a raw
|
|
|
18
12
|
await client.command({
|
|
19
13
|
query: `
|
|
20
14
|
INSERT INTO target
|
|
21
|
-
SELECT
|
|
15
|
+
SELECT * FROM source
|
|
22
16
|
`,
|
|
23
17
|
})
|
|
24
18
|
```
|
|
@@ -71,7 +65,7 @@ await client.insert({
|
|
|
71
65
|
format: 'JSONEachRow',
|
|
72
66
|
values: [{ id: '42', dt: new Date() }],
|
|
73
67
|
clickhouse_settings: {
|
|
74
|
-
date_time_input_format: 'best_effort',
|
|
68
|
+
date_time_input_format: 'best_effort', // default on the Cloud
|
|
75
69
|
},
|
|
76
70
|
})
|
|
77
71
|
```
|
|
@@ -81,6 +75,13 @@ await client.insert({
|
|
|
81
75
|
|
|
82
76
|
## Inserting `Decimal*` values
|
|
83
77
|
|
|
78
|
+
**IMPORTANT:** Make sure that the application code you're working on or the user
|
|
79
|
+
prompt clearly indicates that floats are not used anywhere for decimal values.
|
|
80
|
+
The most common scenario is using floats for money amounts in the app while the
|
|
81
|
+
database uses `Decimal` for them. In that case, the app code should be changed
|
|
82
|
+
to use a proper decimal library and serialization strategy (custom serializer
|
|
83
|
+
or a class using `toJSON()`) to `string` instead of JS `number`.
|
|
84
|
+
|
|
84
85
|
Decimals must be passed as **strings** in JSON formats to avoid precision
|
|
85
86
|
loss in JavaScript:
|
|
86
87
|
|
|
@@ -130,8 +131,6 @@ const rs = await client.query({
|
|
|
130
131
|
|
|
131
132
|
## Common pitfalls
|
|
132
133
|
|
|
133
|
-
- **Passing decimals as JS `number`s.** Anything beyond `Number.MAX_SAFE_INTEGER`
|
|
134
|
-
silently loses precision before it ever reaches the server.
|
|
135
134
|
- **Using `client.insert()` for `INSERT … SELECT`.** There's nothing to
|
|
136
135
|
upload — use `client.command()` with the full SQL.
|
|
137
136
|
- **Forgetting `date_time_input_format: 'best_effort'`** when inserting
|
|
@@ -139,3 +138,4 @@ const rs = await client.query({
|
|
|
139
138
|
ISO-8601 with the `T`/`Z` separators.
|
|
140
139
|
- **Hand-building `VALUES` with user input.** Always parameterize user data;
|
|
141
140
|
see `reference/query-parameters.md`.
|
|
141
|
+
- **Using floats in the app and expect `Decimal` columns to store them safely.** Use a proper decimal library and pass them as strings to avoid precision loss.
|
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
# Ping the Server
|
|
2
2
|
|
|
3
|
-
> **Applies to:** all versions. `ping()` returns a discriminated
|
|
3
|
+
> **Applies to:** all versions. `ping()` returns a discriminated union
|
|
4
4
|
> `PingResult = { success: true } | { success: false, error: Error }` —
|
|
5
5
|
> it does **not** throw on connection failures.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
## Answer checklist
|
|
8
|
+
|
|
9
|
+
When answering "how do I health-check / readiness-probe ClickHouse?":
|
|
10
|
+
|
|
11
|
+
- Use `await client.ping()` (or `ping({ select: true })`) and branch on
|
|
12
|
+
`result.success` directly — **do not** wrap in `try/catch` as the only
|
|
13
|
+
check, and do not substitute `query('SELECT 1')`.
|
|
14
|
+
- For a readiness probe / "can it serve traffic", recommend
|
|
15
|
+
`client.ping({ select: true })` so credentials and the query layer are
|
|
16
|
+
validated, not just the socket.
|
|
17
|
+
- **Always contrast the two forms explicitly in your answer**, even when
|
|
18
|
+
you're recommending one: plain `client.ping()` hits `/ping` (TCP/HTTP
|
|
19
|
+
reachability only — does not validate credentials or query processing);
|
|
20
|
+
`client.ping({ select: true })` issues a lightweight `SELECT 1` (validates
|
|
21
|
+
auth and query path). Name both and say which to use for liveness vs
|
|
22
|
+
readiness.
|
|
23
|
+
- Recommend lowering `request_timeout` on the client used for probes so
|
|
24
|
+
they fail fast instead of hanging on the default timeout — pick a value
|
|
25
|
+
comparable to the probe interval (e.g., `1500`–`2000` ms for a
|
|
26
|
+
2-second-interval probe).
|
|
10
27
|
|
|
11
28
|
## Successful ping
|
|
12
29
|
|
|
@@ -118,3 +135,7 @@ const r = await client.ping({ select: true })
|
|
|
118
135
|
- **Plain `ping()` does not check credentials.** If auth is part of what you
|
|
119
136
|
want to verify, use `ping({ select: true })`.
|
|
120
137
|
- For ping that times out specifically, see the troubleshooting skill.
|
|
138
|
+
- **Only ping the ClickHouse server in your app's liveness probe** if the app
|
|
139
|
+
has to be restarted to recover from a ClickHouse outage. If the app can recover
|
|
140
|
+
the connection to ClickHouse without a restart, put the ping in a readiness
|
|
141
|
+
probe instead so the app doesn't get killed unnecessarily.
|
|
@@ -6,17 +6,16 @@
|
|
|
6
6
|
> `Array`/`Tuple`/`Map` parameters fixed in `>= 1.13.0`. `BigInt` query
|
|
7
7
|
> parameters `>= 1.15.0`.
|
|
8
8
|
|
|
9
|
-
Backing examples:
|
|
10
|
-
[`examples/node/coding/query_with_parameter_binding.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/query_with_parameter_binding.ts),
|
|
11
|
-
[`examples/node/coding/query_with_parameter_binding_special_chars.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/query_with_parameter_binding_special_chars.ts).
|
|
12
|
-
|
|
13
9
|
## Answer checklist
|
|
14
10
|
|
|
15
11
|
When the user passes user-controlled values into SQL:
|
|
16
12
|
|
|
17
13
|
- Use ClickHouse `{name: Type}` placeholders and a `query_params` object.
|
|
18
|
-
-
|
|
19
|
-
|
|
14
|
+
- **Your response must explicitly name template-literal / string
|
|
15
|
+
interpolation of user input as a SQL injection risk** — even when the
|
|
16
|
+
user only asked "how do I bind values" and did not mention security.
|
|
17
|
+
This is non-negotiable: the security framing is part of the right
|
|
18
|
+
answer, not an optional aside.
|
|
20
19
|
- Do not suggest PostgreSQL/MySQL-style `$1`, `?`, or `:name` placeholders.
|
|
21
20
|
- Pick the placeholder type to match the ClickHouse column type (`String`,
|
|
22
21
|
`Date`, `DateTime`, `Nullable(T)`, etc.).
|
|
@@ -42,8 +41,9 @@ Interpolating user input into the SQL string bypasses server-side escaping
|
|
|
42
41
|
and opens the door to SQL injection:
|
|
43
42
|
|
|
44
43
|
```ts
|
|
45
|
-
// ❌ Dangerous — never do this with user-controlled values
|
|
46
44
|
const userId = req.params.id
|
|
45
|
+
|
|
46
|
+
// ❌ Dangerous — never do this with user-controlled values
|
|
47
47
|
await client.query({ query: `SELECT * FROM users WHERE id = ${userId}` })
|
|
48
48
|
|
|
49
49
|
// ✓ Safe — parameterized
|
|
@@ -4,11 +4,6 @@
|
|
|
4
4
|
> `>= 1.7.0`; see the in-repo performance examples under
|
|
5
5
|
> `examples/node/performance/`.
|
|
6
6
|
|
|
7
|
-
Backing examples:
|
|
8
|
-
[`examples/node/coding/select_json_each_row.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/select_json_each_row.ts),
|
|
9
|
-
[`examples/node/coding/select_data_formats_overview.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/select_data_formats_overview.ts),
|
|
10
|
-
[`examples/node/coding/select_json_with_metadata.ts`](https://github.com/ClickHouse/clickhouse-js/blob/main/examples/node/coding/select_json_with_metadata.ts).
|
|
11
|
-
|
|
12
7
|
## Default choice: `JSONEachRow` → `.json<T>()`
|
|
13
8
|
|
|
14
9
|
Right answer for ~90% of selects when the result fits in memory.
|
|
@@ -27,6 +22,9 @@ const rows = await client.query({
|
|
|
27
22
|
})
|
|
28
23
|
const result = await rows.json<Row>() // Row[]
|
|
29
24
|
result.forEach((r) => console.log(r))
|
|
25
|
+
// { number: '0' }
|
|
26
|
+
// { number: '1' }
|
|
27
|
+
// ...
|
|
30
28
|
await client.close()
|
|
31
29
|
```
|
|
32
30
|
|
|
@@ -3,9 +3,30 @@
|
|
|
3
3
|
> **Applies to:** all versions. `session_id` is a server-level concept; the
|
|
4
4
|
> client just forwards it on every request that names it.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
## Answer checklist
|
|
7
|
+
|
|
8
|
+
When answering "temp table disappears between calls" / "how do I share a
|
|
9
|
+
session" / anything involving `session_id`:
|
|
10
|
+
|
|
11
|
+
- State plainly that **temporary tables and session-scoped state are tied
|
|
12
|
+
to a `session_id`** — without a stable `session_id` across calls, every
|
|
13
|
+
request gets a fresh server-side session and the temp table is gone.
|
|
14
|
+
- Set `session_id` via `crypto.randomUUID()` either on `createClient` or
|
|
15
|
+
per-call.
|
|
16
|
+
- Warn that **`session_id` on a global / module-static client is an
|
|
17
|
+
anti-pattern** in any concurrent app (Express, server actions, workers,
|
|
18
|
+
etc.) — concurrent requests will share the same session and trip
|
|
19
|
+
`"Session is locked by a concurrent client"`. Recommend a short-lived
|
|
20
|
+
per-workflow client or per-call `session_id` instead.
|
|
21
|
+
- If `session_id` is set on the client, also set `max_open_connections: 1`
|
|
22
|
+
to serialize calls and avoid the concurrent-session error.
|
|
23
|
+
- For ClickHouse Cloud or any load-balanced deployment: **explicitly
|
|
24
|
+
recommend replica-aware routing or a single-node hostname** as the
|
|
25
|
+
primary remedy when sessions are needed. Sessions are pinned to one
|
|
26
|
+
node; behind an LB, consecutive requests may land on different nodes
|
|
27
|
+
and the temp table will appear to vanish. "Just collapse the workflow
|
|
28
|
+
into one handler" or "use a non-temporary table" are valid fallbacks
|
|
29
|
+
but secondary — name the routing fix first.
|
|
9
30
|
|
|
10
31
|
## When you need a session
|
|
11
32
|
|
|
@@ -40,8 +61,8 @@ the entire process.
|
|
|
40
61
|
## Per-client `session_id`
|
|
41
62
|
|
|
42
63
|
Appropriate when **one client handles exactly one sequential workflow** (a
|
|
43
|
-
script, a background job, a single user's session that you've already
|
|
44
|
-
serialized).
|
|
64
|
+
script, a background job, a single user's session that you've already manually
|
|
65
|
+
serialized in the code).
|
|
45
66
|
|
|
46
67
|
```ts
|
|
47
68
|
import { createClient } from '@clickhouse/client'
|
|
@@ -49,7 +70,7 @@ import * as crypto from 'node:crypto'
|
|
|
49
70
|
|
|
50
71
|
const client = createClient({
|
|
51
72
|
session_id: crypto.randomUUID(),
|
|
52
|
-
max_open_connections: 1, //
|
|
73
|
+
max_open_connections: 1, // safeguard against concurrent-session errors
|
|
53
74
|
})
|
|
54
75
|
|
|
55
76
|
await client.command({
|
|
@@ -81,7 +102,7 @@ import * as crypto from 'node:crypto'
|
|
|
81
102
|
|
|
82
103
|
const client = createClient({
|
|
83
104
|
session_id: crypto.randomUUID(),
|
|
84
|
-
max_open_connections: 1, //
|
|
105
|
+
max_open_connections: 1, // safe-guard against concurrent-session errors
|
|
85
106
|
})
|
|
86
107
|
|
|
87
108
|
await client.command({
|
|
@@ -125,13 +146,18 @@ front of ClickHouse routes consecutive requests to different nodes, the
|
|
|
125
146
|
temporary table / `SET` won't be visible — you'll get
|
|
126
147
|
`UNKNOWN_TABLE` / surprising results.
|
|
127
148
|
|
|
128
|
-
Mitigations:
|
|
129
|
-
|
|
130
|
-
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
149
|
+
Mitigations (in order of preference):
|
|
150
|
+
|
|
151
|
+
- **For ClickHouse Cloud, use [replica-aware
|
|
152
|
+
routing](https://clickhouse.com/docs/manage/replica-aware-routing)** so
|
|
153
|
+
consecutive requests in the same session land on the same node. This is
|
|
154
|
+
the right primary fix when you need sessions in a Cloud deployment.
|
|
155
|
+
- Talk to a single node directly (e.g., a node-pinned hostname) when
|
|
156
|
+
routing isn't an option.
|
|
157
|
+
- As a fallback only: avoid sessions for cross-node workflows and persist
|
|
158
|
+
intermediate state in a regular (non-temporary) table instead. This
|
|
159
|
+
trades the session requirement away rather than fixing it — use it only
|
|
160
|
+
if replica-aware routing / single-node connections aren't available.
|
|
135
161
|
|
|
136
162
|
## Common pitfalls
|
|
137
163
|
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"skill_name": "clickhouse-js-node-coding",
|
|
3
|
-
"evals": [
|
|
4
|
-
{
|
|
5
|
-
"id": 0,
|
|
6
|
-
"prompt": "I'm setting up clickhouse client in a Node service. I want to point it at https://my.host:8124, use database 'analytics', user 'bob' / password 'secret', set application name 'my_app', and turn on async_insert without waiting for ack. What's the cleanest way to express that?",
|
|
7
|
-
"expected_output": "A createClient call (Node, not Web) that sets url, username/password (or embeds them in the URL), database, application, and clickhouse_settings: { async_insert: 1, wait_for_async_insert: 0 }. Optionally mentions the equivalent URL-parameter form (ch_async_insert=1&ch_wait_for_async_insert=0) and that URL params override the config object.",
|
|
8
|
-
"files": [],
|
|
9
|
-
"expectations": [
|
|
10
|
-
"Uses createClient from @clickhouse/client (Node, not Web).",
|
|
11
|
-
"Either passes a single URL string with auth + ?ch_async_insert=1&ch_wait_for_async_insert=0, or a config object with database, username, password, application, clickhouse_settings.",
|
|
12
|
-
"Mentions or implies that URL parameters override the config object if both are provided.",
|
|
13
|
-
"Does not suggest using URL parameters in code and instead suggests that the URL should be read from environment variables or a config file.",
|
|
14
|
-
"Does not construct the URL with parameters directly in code neither using string concatenation nor query objects.",
|
|
15
|
-
"Suggests using `await client.close()` during graceful shutdown.",
|
|
16
|
-
"Suggests that settings in `clickhouse_settings` can be overridden per-query by passing them inside the individual `insert()` or `query()` call for finer control."
|
|
17
|
-
]
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
"id": 1,
|
|
21
|
-
"prompt": "How do I do a health check against ClickHouse from Node? I want to return 200/503 from an Express endpoint based on whether ClickHouse is reachable.",
|
|
22
|
-
"expected_output": "Use await client.ping(), branch on { success } (no try/catch needed) — return 200 on success and 503 on failure, optionally surfacing the error.",
|
|
23
|
-
"files": [],
|
|
24
|
-
"expectations": [
|
|
25
|
-
"Uses await client.ping() and reads { success, error } directly — does NOT wrap it in try/catch as the only check.",
|
|
26
|
-
"Maps success === true to 200 and success === false to 503.",
|
|
27
|
-
"Suggests lowering request_timeout to make the probe fail fast.",
|
|
28
|
-
"Explains the difference between `client.ping()` (checks connectivity only and ignores credentials by default) and `client.ping({ select: true })` (lightweight query that also checks auth and query processing) and when to use each."
|
|
29
|
-
]
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
"id": 2,
|
|
33
|
-
"prompt": "I have an array of about 10k plain JS objects I want to insert into a MergeTree table. What's the right format and call?",
|
|
34
|
-
"expected_output": "client.insert with format: 'JSONEachRow' and values: <array>. No streaming / Parquet needed for this size.",
|
|
35
|
-
"files": [],
|
|
36
|
-
"expectations": [
|
|
37
|
-
"Uses client.insert({ table, values, format: 'JSONEachRow' }).",
|
|
38
|
-
"Notes that the array can be passed directly to values — no need to stringify or stream for a few thousand rows.",
|
|
39
|
-
"Does NOT recommend a streaming/Parquet flow for this size.",
|
|
40
|
-
"Mentions `JSONCompact*` formats as an alternative for bigger payloads"
|
|
41
|
-
]
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
"id": 3,
|
|
45
|
-
"prompt": "My table has columns (id, name, created_at, internal_hash) but the rows I have only contain id and name. How do I insert just those two columns?",
|
|
46
|
-
"expected_output": "Use the columns option on client.insert: either columns: ['id', 'name'] (allowlist) or columns: { except: ['created_at', 'internal_hash'] } (excludelist). Omitted columns get their declared defaults.",
|
|
47
|
-
"files": [],
|
|
48
|
-
"expectations": [
|
|
49
|
-
"Uses client.insert with the columns: ['id', 'name'] option.",
|
|
50
|
-
"Mentions the alternative columns: { except: [...] } form.",
|
|
51
|
-
"Notes that omitted columns will receive their server-side defaults."
|
|
52
|
-
]
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
"id": 4,
|
|
56
|
-
"prompt": "I want to call: SELECT * FROM users WHERE country = '<user input>' AND signup_date > '<user input>'. How should I pass those values from JS?",
|
|
57
|
-
"expected_output": "Use parameterized queries with the ClickHouse {name: Type} syntax and query_params: { country: ..., signup_date: ... }. Explicitly warn against template-literal interpolation (SQL injection).",
|
|
58
|
-
"files": [],
|
|
59
|
-
"expectations": [
|
|
60
|
-
"Uses {name: Type} parameter syntax (e.g., {country: String}, {signup_date: Date}) and query_params.",
|
|
61
|
-
"Explicitly warns against template-literal interpolation as a SQL injection risk.",
|
|
62
|
-
"Does NOT suggest $1/?/:name placeholders."
|
|
63
|
-
]
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
"id": 5,
|
|
67
|
-
"prompt": "I'm doing CREATE TEMPORARY TABLE and then SELECT from it in a follow-up call. They keep disappearing between calls. What am I missing?",
|
|
68
|
-
"expected_output": "Temporary tables are scoped to a session — set a stable session_id (e.g., crypto.randomUUID()) on the client (or per-call) so consecutive requests share server-side state. Also flag the load-balancer/Cloud caveat (replica-aware routing).",
|
|
69
|
-
"files": [],
|
|
70
|
-
"expectations": [
|
|
71
|
-
"Explains that temporary tables are scoped to a session and require a stable session_id across calls.",
|
|
72
|
-
"Shows setting session_id either on createClient or via per-call session_id.",
|
|
73
|
-
"Mentions the load-balancer / ClickHouse Cloud caveat (sessions are pinned to a node; recommend replica-aware routing or a single-node connection).",
|
|
74
|
-
"Explicitly explains that parallel calls with the same session_id will result in an error as ClickHouse does not allow concurrent queries within the same session_id.",
|
|
75
|
-
"Explicitly advises against using session_id in client configuration for a global / module static client",
|
|
76
|
-
"When session_id is used as a client option it should suggest configuring the maximum number of connections to 1 to minimize concurrency issues at the client level."
|
|
77
|
-
]
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
"id": 6,
|
|
81
|
-
"prompt": "I'm running 25.x ClickHouse. I want to store a JSON object per row and read it back as a real JS object, not a JSON string. How do I do that with the Node client?",
|
|
82
|
-
"expected_output": "Use the new JSON column type (>= 24.8, no longer experimental since 25.3). CREATE TABLE with a JSON column, insert with format: 'JSONEachRow' passing JS objects, select with JSONEachRow — values come back as parsed JS objects with no manual JSON.parse.",
|
|
83
|
-
"files": [],
|
|
84
|
-
"expectations": [
|
|
85
|
-
"Uses the JSON column type and format: 'JSONEachRow' for both insert and select.",
|
|
86
|
-
"Inserts a real JS object as the column value (no JSON.stringify) and shows it returns as a parsed object.",
|
|
87
|
-
"Mentions the relevant ClickHouse server version (>= 24.8 introduced; non-experimental since 25.3) and, if needed on older servers, allow_experimental_json_type."
|
|
88
|
-
]
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
"id": 7,
|
|
92
|
-
"prompt": "Our IDs are UInt64 and we don't want them coming back as strings or losing precision.",
|
|
93
|
-
"expected_output": "Yes — pass a custom { parse, stringify } via the json config option (>= 1.14.0). Show wiring up json-bigint (or similar) so 64-bit integers are parsed as BigInt. Mention output_format_json_quote_64bit_integers: 0 so the server emits unquoted ints. Note that switching to native Number would lose precision and is the wrong fix.",
|
|
94
|
-
"files": [],
|
|
95
|
-
"expectations": [
|
|
96
|
-
"Shows passing custom { parse, stringify } via the json config option on createClient.",
|
|
97
|
-
"Notes the >= 1.14.0 client requirement for the json option.",
|
|
98
|
-
"Mentions output_format_json_quote_64bit_integers: 0 (default since 25.8) so 64-bit integers come back unquoted and parseable as BigInt.",
|
|
99
|
-
"Warns that switching to native Number would lose precision and is the wrong fix."
|
|
100
|
-
]
|
|
101
|
-
}
|
|
102
|
-
]
|
|
103
|
-
}
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"skill_name": "clickhouse-js-node-troubleshooting",
|
|
3
|
-
"evals": [
|
|
4
|
-
{
|
|
5
|
-
"id": 0,
|
|
6
|
-
"prompt": "I'm using @clickhouse/client in a Node.js API server and I get `socket hang up` errors, but only after the server has been idle for a while — if I hammer it with requests it's fine. Any idea what's going on? I'm on version 0.3.2.",
|
|
7
|
-
"expected_output": "Explanation that this is a Keep-Alive idle socket timeout mismatch. The server's keep-alive timeout is shorter than the client's idle_socket_ttl. Should recommend checking the server's keep-alive timeout with curl and setting idle_socket_ttl to ~500ms below it.",
|
|
8
|
-
"files": [],
|
|
9
|
-
"expectations": [
|
|
10
|
-
"Identifies the likely cause as a Keep-Alive idle timeout mismatch rather than a generic network problem.",
|
|
11
|
-
"Recommends checking the server or proxy Keep-Alive timeout, including the curl-based header check or equivalent.",
|
|
12
|
-
"Explains that idle_socket_ttl should be set slightly below the server timeout, around 500ms lower."
|
|
13
|
-
]
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
"id": 1,
|
|
17
|
-
"prompt": "I keep getting ECONNRESET on literally every second request in my Node.js app. Here's my code:\n\n```js\nconst resultSet = await client.query({ query: 'SELECT count() FROM events' })\nconst stream = resultSet.stream()\n// then I do some stuff and run another query\nconst result2 = await client.query({ query: 'SELECT 1' })\n```\n\nThe first query always works, second always fails. What am I doing wrong?",
|
|
18
|
-
"expected_output": "Diagnosis of dangling stream — the stream from the first query is never fully iterated or closed, corrupting the Keep-Alive socket. Fix: either fully consume via for-await or call resultSet.close().",
|
|
19
|
-
"files": [],
|
|
20
|
-
"expectations": [
|
|
21
|
-
"Diagnoses the problem as an unconsumed or dangling ResultSet stream causing the next request to fail.",
|
|
22
|
-
"Explains that the first query response must be fully consumed or explicitly closed before reusing the client connection.",
|
|
23
|
-
"Provides at least one concrete fix using full stream consumption, resultSet.json/text, or resultSet.close()."
|
|
24
|
-
]
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
"id": 2,
|
|
28
|
-
"prompt": "My UInt64 column values are coming back as strings in JavaScript — like `\"9007199254740993\"` instead of a number. I'm using JSONEachRow format. Is there a way to get them as actual numbers?",
|
|
29
|
-
"expected_output": "Explanation that ClickHouse serializes 64-bit integers as strings in JSON formats to prevent overflow. Option 1: use output_format_json_quote_64bit_integers: 0 (with precision-loss warning). Option 2: use BigInt or a BigInt-safe JSON parser. Should mention the precision risk.",
|
|
30
|
-
"files": [],
|
|
31
|
-
"expectations": [
|
|
32
|
-
"Explains that 64-bit integers are returned as strings in JSON formats to avoid JavaScript precision issues.",
|
|
33
|
-
"Mentions output_format_json_quote_64bit_integers: 0 as a way to receive numeric JSON output.",
|
|
34
|
-
"Warns that converting these values to Number can lose precision and suggests a safer BigInt-oriented alternative."
|
|
35
|
-
]
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"id": 3,
|
|
39
|
-
"prompt": "We have ClickHouse sitting behind an nginx reverse proxy. The proxy URL is http://myproxy.internal:8123/clickhouse. I'm on @clickhouse/client 1.3.0 and creating the client like this:\n\n```js\nconst client = createClient({ url: 'http://myproxy.internal:8123/clickhouse' })\n```\n\nBut it seems to be selecting the wrong database — it's trying to use 'clickhouse' as the database name instead of going through the proxy path. What am I missing?",
|
|
40
|
-
"expected_output": "Explanation of the proxy/pathname confusion: the path in the URL is being interpreted as the database name. Fix: use the `pathname` option separately — createClient({ url: 'http://myproxy.internal:8123', pathname: '/clickhouse' }). Should note this requires >= 1.0.0.",
|
|
41
|
-
"files": [],
|
|
42
|
-
"expectations": [
|
|
43
|
-
"Explains that putting the path segment in url makes the client interpret it as the database name or otherwise mishandle the proxy path.",
|
|
44
|
-
"Shows the fix using a base url plus a separate pathname option.",
|
|
45
|
-
"Acknowledges the version dependency by either noting pathname requires >= 1.0.0 or asking for the client version before assuming that fix is available."
|
|
46
|
-
]
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
"id": 4,
|
|
50
|
-
"prompt": "I'm getting this error when connecting to our self-hosted ClickHouse over HTTPS:\n\n```\nError: unable to verify the first certificate\n at TLSSocket.onConnectEnd (_tls_wrap.js:1495:19)\n```\n\nWe use an internal certificate authority. I'm using @clickhouse/client 1.3.0 with Node.js 18. How do I fix this?",
|
|
51
|
-
"expected_output": "Diagnosis: private/internal CA not trusted by Node.js. Fix: pass the CA certificate via the tls.ca_cert option using fs.readFileSync. Should show the createClient({ url: 'https://...', tls: { ca_cert: fs.readFileSync('certs/CA.pem') } }) example.",
|
|
52
|
-
"files": [],
|
|
53
|
-
"expectations": [
|
|
54
|
-
"Diagnoses the error as Node.js not trusting the internal or private certificate authority.",
|
|
55
|
-
"Shows how to pass the CA certificate via tls.ca_cert with fs.readFileSync or an equivalent code example.",
|
|
56
|
-
"Avoids recommending insecure production advice such as disabling certificate verification without clearly marking it as development-only."
|
|
57
|
-
]
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
"id": 5,
|
|
61
|
-
"prompt": "My parameterized queries aren't working. I'm doing:\n\n```js\nawait client.query({\n query: 'SELECT * FROM users WHERE id = $1 AND status = $2',\n query_params: { 1: 42, 2: 'active' }\n})\n```\n\nThe values just don't get substituted. Coming from PostgreSQL and this was how params work there.",
|
|
62
|
-
"expected_output": "Explanation that ClickHouse JS client uses ClickHouse's native {name: type} syntax, not $1/$2 placeholders. Show the correct syntax: { query: 'SELECT * FROM users WHERE id = {id: UInt32} AND status = {status: String}', query_params: { id: 42, status: 'active' } }. Warn against template literal interpolation (SQL injection risk).",
|
|
63
|
-
"files": [],
|
|
64
|
-
"expectations": [
|
|
65
|
-
"Explains that the ClickHouse JS client does not use PostgreSQL-style $1 or $2 placeholders.",
|
|
66
|
-
"Provides a corrected example using ClickHouse's native {name: type} parameter syntax with query_params keys matching the names.",
|
|
67
|
-
"Warns against interpolating user values directly into the SQL string because of SQL injection risk."
|
|
68
|
-
]
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
"id": 6,
|
|
72
|
-
"prompt": "I enabled response compression in @clickhouse/client for my readonly user, but I'm getting an error from ClickHouse that says something like 'Cannot modify setting enable_http_compression for user with readonly=1'. My client setup:\n\n```js\nconst client = createClient({\n username: 'readonly_user',\n password: 'secret',\n compression: { response: true }\n})\n```",
|
|
73
|
-
"expected_output": "Explanation that readonly=1 users cannot change the enable_http_compression setting, which response compression requires. Fix: remove compression.response: true (or set to false). Note that request compression is unaffected. Mention that in >= 1.0.0, response compression is disabled by default.",
|
|
74
|
-
"files": [],
|
|
75
|
-
"expectations": [
|
|
76
|
-
"Explains that response compression toggles enable_http_compression, which a readonly=1 user cannot modify.",
|
|
77
|
-
"Recommends removing or disabling compression.response for this user.",
|
|
78
|
-
"Notes that request compression is a separate setting and is not blocked by the readonly restriction."
|
|
79
|
-
]
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
"id": 7,
|
|
83
|
-
"prompt": "I'm on @clickhouse/client 1.3.0 and trying to set up structured logging to pipe into our observability stack (we use pino). I want to forward all client log messages at INFO level and above to pino. How do I wire that up?",
|
|
84
|
-
"expected_output": "Should show how to implement the Logger interface with a class (MyLogger implements Logger) that forwards to pino, then pass it via createClient({ log: { LoggerClass: MyLogger, level: ClickHouseLogLevel.INFO } }). Should show the debug/info/warn/error/trace method signatures.",
|
|
85
|
-
"files": [],
|
|
86
|
-
"expectations": [
|
|
87
|
-
"Shows a custom Logger implementation or equivalent logger wiring that forwards client logs to pino.",
|
|
88
|
-
"Configures createClient with log.LoggerClass and ClickHouseLogLevel.INFO or an equivalent INFO-level setup.",
|
|
89
|
-
"Acknowledges the version dependency by either noting this logging API requires >= 0.2.0 or asking for the client version before assuming availability."
|
|
90
|
-
]
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
"id": 8,
|
|
94
|
-
"prompt": "I'm using `@clickhouse/client-web` inside a Next.js Edge route and trying to debug random request failures and TLS weirdness. Can you walk me through the Node.js client socket and certificate options I should tune?",
|
|
95
|
-
"expected_output": "Should explicitly reject applying the Node.js troubleshooting flow because this is an Edge/browser-style runtime using `@clickhouse/client-web`, not `@clickhouse/client`. Must redirect the user to the web client / runtime-appropriate guidance instead of suggesting Node-only socket, keep-alive, or tls options.",
|
|
96
|
-
"files": [],
|
|
97
|
-
"expectations": [
|
|
98
|
-
"Explicitly states that this skill's Node.js guidance does not apply to @clickhouse/client-web in a Next.js Edge runtime.",
|
|
99
|
-
"Avoids recommending Node-only configuration such as keep_alive, socket TTL tuning, custom HTTP agents, or tls.ca_cert for this case.",
|
|
100
|
-
"Redirects the user toward runtime-appropriate web or edge guidance instead of continuing with Node client troubleshooting."
|
|
101
|
-
]
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
"id": 9,
|
|
105
|
-
"prompt": "I'm on @clickhouse/client 1.6.0 talking to a self-hosted ClickHouse cluster over HTTP. I turned on `compression: { response: true }` but the responses still don't look compressed. This is not a readonly user, and there is no settings error from ClickHouse. What should I check?",
|
|
106
|
-
"expected_output": "Should explain that in >= 1.0.0 response compression is disabled by default unless enabled, but since it is already enabled here the next checks are whether the server has HTTP compression enabled and whether the user is confusing request compression with response compression. Should mention that only GZIP is supported and that request compression does not affect response bodies.",
|
|
107
|
-
"files": [],
|
|
108
|
-
"expectations": [
|
|
109
|
-
"Recognizes that this is not the readonly-user failure mode because there is no settings error and the user already enabled response compression.",
|
|
110
|
-
"Recommends checking whether the ClickHouse server has HTTP compression enabled.",
|
|
111
|
-
"Clarifies that request compression and response compression are separate, and that only GZIP is supported."
|
|
112
|
-
]
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
"id": 10,
|
|
116
|
-
"prompt": "We run a long `INSERT INTO dst SELECT * FROM src` through @clickhouse/client in a Node.js worker. It can sit there for a couple minutes with no rows coming back, and then our AWS load balancer drops the connection around the 120 second mark. Smaller queries are fine. We're on client 1.4.0. How should we handle this?",
|
|
117
|
-
"expected_output": "Should diagnose this as a long-running query idle-timeout problem rather than a dangling stream issue. Must recommend increasing request_timeout and enabling periodic progress headers with send_progress_in_http_headers and http_headers_progress_interval_ms set below the load balancer idle timeout. Should also mention the Node.js response-header limit tradeoff for very long queries and optionally suggest the fire-and-forget mutation pattern.",
|
|
118
|
-
"files": [],
|
|
119
|
-
"expectations": [
|
|
120
|
-
"Diagnoses the issue as a long-running idle timeout at the load balancer rather than a dangling stream or ordinary per-request ECONNRESET problem.",
|
|
121
|
-
"Recommends increasing request_timeout and enabling send_progress_in_http_headers with http_headers_progress_interval_ms below the load balancer timeout.",
|
|
122
|
-
"Mentions the Node.js received-header limit tradeoff for very long-running progress-header use or offers the fire-and-forget mutation pattern as an alternative."
|
|
123
|
-
]
|
|
124
|
-
}
|
|
125
|
-
]
|
|
126
|
-
}
|