@clickhouse/client 1.20.0 → 1.21.0

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.
Files changed (72) hide show
  1. package/README.md +11 -11
  2. package/dist/client.d.ts +6 -6
  3. package/dist/client.js.map +1 -1
  4. package/dist/config.d.ts +6 -6
  5. package/dist/config.js +6 -5
  6. package/dist/config.js.map +1 -1
  7. package/dist/connection/compression.d.ts +4 -4
  8. package/dist/connection/compression.js +3 -3
  9. package/dist/connection/compression.js.map +1 -1
  10. package/dist/connection/create_connection.d.ts +6 -6
  11. package/dist/connection/create_connection.js +3 -3
  12. package/dist/connection/create_connection.js.map +1 -1
  13. package/dist/connection/index.d.ts +4 -4
  14. package/dist/connection/index.js.map +1 -1
  15. package/dist/connection/node_base_connection.d.ts +11 -11
  16. package/dist/connection/node_base_connection.js +75 -42
  17. package/dist/connection/node_base_connection.js.map +1 -1
  18. package/dist/connection/node_custom_agent_connection.d.ts +4 -4
  19. package/dist/connection/node_custom_agent_connection.js +2 -2
  20. package/dist/connection/node_custom_agent_connection.js.map +1 -1
  21. package/dist/connection/node_http_connection.d.ts +4 -4
  22. package/dist/connection/node_http_connection.js.map +1 -1
  23. package/dist/connection/node_https_connection.d.ts +5 -5
  24. package/dist/connection/node_https_connection.js +11 -11
  25. package/dist/connection/node_https_connection.js.map +1 -1
  26. package/dist/connection/socket_pool.d.ts +9 -9
  27. package/dist/connection/socket_pool.js +33 -32
  28. package/dist/connection/socket_pool.js.map +1 -1
  29. package/dist/connection/stream.d.ts +2 -2
  30. package/dist/connection/stream.js +18 -18
  31. package/dist/connection/stream.js.map +1 -1
  32. package/dist/index.d.ts +41 -8
  33. package/dist/index.js +4 -1
  34. package/dist/index.js.map +1 -1
  35. package/dist/result_set.d.ts +31 -20
  36. package/dist/result_set.js +83 -13
  37. package/dist/result_set.js.map +1 -1
  38. package/dist/utils/encoder.d.ts +2 -2
  39. package/dist/utils/encoder.js +3 -3
  40. package/dist/utils/encoder.js.map +1 -1
  41. package/dist/utils/index.d.ts +4 -4
  42. package/dist/utils/index.js.map +1 -1
  43. package/dist/utils/process.js.map +1 -1
  44. package/dist/utils/runtime.js.map +1 -1
  45. package/dist/utils/stream.d.ts +1 -1
  46. package/dist/utils/stream.js +8 -8
  47. package/dist/utils/stream.js.map +1 -1
  48. package/dist/utils/user_agent.js.map +1 -1
  49. package/dist/version.d.ts +1 -1
  50. package/dist/version.js +1 -1
  51. package/dist/version.js.map +1 -1
  52. package/package.json +2 -2
  53. package/skills/clickhouse-js-node-coding/reference/async-insert.md +12 -12
  54. package/skills/clickhouse-js-node-coding/reference/client-configuration.md +16 -16
  55. package/skills/clickhouse-js-node-coding/reference/custom-json.md +31 -31
  56. package/skills/clickhouse-js-node-coding/reference/data-types.md +65 -65
  57. package/skills/clickhouse-js-node-coding/reference/insert-columns.md +23 -23
  58. package/skills/clickhouse-js-node-coding/reference/insert-formats.md +30 -30
  59. package/skills/clickhouse-js-node-coding/reference/insert-values.md +35 -35
  60. package/skills/clickhouse-js-node-coding/reference/ping.md +24 -24
  61. package/skills/clickhouse-js-node-coding/reference/query-parameters.md +27 -27
  62. package/skills/clickhouse-js-node-coding/reference/select-formats.md +21 -21
  63. package/skills/clickhouse-js-node-coding/reference/sessions.md +27 -27
  64. package/skills/clickhouse-js-node-troubleshooting/reference/compression.md +2 -2
  65. package/skills/clickhouse-js-node-troubleshooting/reference/data-types.md +24 -24
  66. package/skills/clickhouse-js-node-troubleshooting/reference/logging.md +5 -5
  67. package/skills/clickhouse-js-node-troubleshooting/reference/proxy-pathname.md +7 -7
  68. package/skills/clickhouse-js-node-troubleshooting/reference/query-format-clause.md +6 -6
  69. package/skills/clickhouse-js-node-troubleshooting/reference/query-params.md +30 -30
  70. package/skills/clickhouse-js-node-troubleshooting/reference/readonly-users.md +4 -4
  71. package/skills/clickhouse-js-node-troubleshooting/reference/socket-hangup.md +20 -20
  72. package/skills/clickhouse-js-node-troubleshooting/reference/tls.md +24 -24
@@ -9,12 +9,12 @@
9
9
  **Fix:** Use the `pathname` option separately:
10
10
 
11
11
  ```js
12
- import { createClient } from '@clickhouse/client'
12
+ import { createClient } from "@clickhouse/client";
13
13
 
14
14
  const client = createClient({
15
- url: 'http://proxy:8123',
16
- pathname: '/clickhouse_server', // leading slash optional; multiple segments supported
17
- })
15
+ url: "http://proxy:8123",
16
+ pathname: "/clickhouse_server", // leading slash optional; multiple segments supported
17
+ });
18
18
  ```
19
19
 
20
20
  For proxies that require custom auth headers:
@@ -22,11 +22,11 @@ For proxies that require custom auth headers:
22
22
  > **Requires:** `>= 1.0.0` (`http_headers` config option; replaces the deprecated `additional_headers` from `>= 0.2.9`). Per-request `http_headers` overrides are available since `>= 1.11.0`.
23
23
 
24
24
  ```js
25
- import { createClient } from '@clickhouse/client'
25
+ import { createClient } from "@clickhouse/client";
26
26
 
27
27
  const client = createClient({
28
28
  http_headers: {
29
- 'My-Auth-Header': 'secret',
29
+ "My-Auth-Header": "secret",
30
30
  },
31
- })
31
+ });
32
32
  ```
@@ -6,7 +6,7 @@
6
6
 
7
7
  ```js
8
8
  // What you write:
9
- await client.query({ query: 'SELECT 1', format: 'JSONEachRow' })
9
+ await client.query({ query: "SELECT 1", format: "JSONEachRow" });
10
10
 
11
11
  // What the client actually sends:
12
12
  // SELECT 1
@@ -19,10 +19,10 @@ If the `query` string already contains a `FORMAT` clause, the client still appen
19
19
 
20
20
  ```js
21
21
  // ❌ Wrong — ends up as `... FORMAT CSV FORMAT JSON` → syntax error
22
- await client.query({ query: 'SELECT 1 FORMAT CSV' })
22
+ await client.query({ query: "SELECT 1 FORMAT CSV" });
23
23
 
24
24
  // ✓ Correct — let the client append FORMAT via the option
25
- await client.query({ query: 'SELECT 1', format: 'CSV' })
25
+ await client.query({ query: "SELECT 1", format: "CSV" });
26
26
  ```
27
27
 
28
28
  If you genuinely need to write the full SQL yourself (including the `FORMAT` clause), or you're running a statement where the appended `FORMAT` suffix is not supported, use `client.exec()` instead of `client.query()`. Use `client.insert()` for data insertion and `client.command()` for DDLs.
@@ -33,15 +33,15 @@ Some statements are not parsed by the server with a trailing `FORMAT` clause, so
33
33
 
34
34
  ```js
35
35
  // ❌ Fails — query() appends `FORMAT JSON`, which the short SHOW POLICIES syntax rejects
36
- await client.query({ query: 'SHOW POLICIES', format: 'JSON' })
37
- await client.query({ query: 'SHOW ROW POLICIES', format: 'JSON' })
36
+ await client.query({ query: "SHOW POLICIES", format: "JSON" });
37
+ await client.query({ query: "SHOW ROW POLICIES", format: "JSON" });
38
38
  ```
39
39
 
40
40
  **Fix:** use the full syntax `SHOW POLICIES ON *` (or `SHOW POLICIES ON db.table`), which the parser accepts together with the appended `FORMAT`:
41
41
 
42
42
  ```js
43
43
  // ✓ Works — full syntax accepts the appended FORMAT clause
44
- await client.query({ query: 'SHOW POLICIES ON *', format: 'JSON' })
44
+ await client.query({ query: "SHOW POLICIES ON *", format: "JSON" });
45
45
  ```
46
46
 
47
47
  Alternatively, run the short statement through `client.exec()`, where you control the full SQL and no `FORMAT` suffix is appended.
@@ -6,10 +6,10 @@ Use the `{name: type}` syntax in the query string and pass values via `query_par
6
6
 
7
7
  ```js
8
8
  await client.query({
9
- query: 'SELECT plus({val1: Int32}, {val2: Int32})',
10
- format: 'CSV',
9
+ query: "SELECT plus({val1: Int32}, {val2: Int32})",
10
+ format: "CSV",
11
11
  query_params: { val1: 10, val2: 20 },
12
- })
12
+ });
13
13
  ```
14
14
 
15
15
  ## Never use template literals for user values
@@ -18,14 +18,14 @@ When `$1`/`?` don't work, a common instinct is to interpolate values directly wi
18
18
 
19
19
  ```js
20
20
  // ❌ Dangerous — never do this with user-controlled values
21
- const userId = req.params.id
22
- await client.query({ query: `SELECT * FROM users WHERE id = ${userId}` })
21
+ const userId = req.params.id;
22
+ await client.query({ query: `SELECT * FROM users WHERE id = ${userId}` });
23
23
 
24
24
  // ✓ Safe — parameterized
25
25
  await client.query({
26
- query: 'SELECT * FROM users WHERE id = {id: UInt32}',
26
+ query: "SELECT * FROM users WHERE id = {id: UInt32}",
27
27
  query_params: { id: userId },
28
- })
28
+ });
29
29
  ```
30
30
 
31
31
  Always bring this up when answering query-params questions, especially when the user is coming from another database (PostgreSQL, MySQL, etc.) — they're the most likely to reach for template literals as a fallback.
@@ -37,27 +37,27 @@ The ClickHouse JS client uses ClickHouse's native `{name: type}` syntax — not
37
37
  ```js
38
38
  // ❌ Wrong — these don't work
39
39
  await client.query({
40
- query: 'SELECT * FROM t WHERE id = $1',
41
- query: 'SELECT * FROM t WHERE id = ?',
42
- query: 'SELECT * FROM t WHERE id = :id',
40
+ query: "SELECT * FROM t WHERE id = $1",
41
+ query: "SELECT * FROM t WHERE id = ?",
42
+ query: "SELECT * FROM t WHERE id = :id",
43
43
  query_params: { id: 42 },
44
- })
44
+ });
45
45
 
46
46
  // ✓ Correct
47
47
  await client.query({
48
- query: 'SELECT * FROM t WHERE id = {id: UInt32}',
48
+ query: "SELECT * FROM t WHERE id = {id: UInt32}",
49
49
  query_params: { id: 42 },
50
- })
50
+ });
51
51
  ```
52
52
 
53
53
  ## Array parameters
54
54
 
55
55
  ```js
56
56
  await client.query({
57
- query: 'SELECT * FROM t WHERE id IN {ids: Array(UInt32)}',
58
- format: 'JSONEachRow',
57
+ query: "SELECT * FROM t WHERE id IN {ids: Array(UInt32)}",
58
+ format: "JSONEachRow",
59
59
  query_params: { ids: [1, 2, 3] },
60
- })
60
+ });
61
61
  ```
62
62
 
63
63
  ## Tuple parameters (`>= 1.9.0`)
@@ -65,17 +65,17 @@ await client.query({
65
65
  Use the `TupleParam` wrapper to pass a tuple:
66
66
 
67
67
  ```js
68
- import { TupleParam, createClient } from '@clickhouse/client'
68
+ import { TupleParam, createClient } from "@clickhouse/client";
69
69
 
70
70
  const client = createClient({
71
- url: 'http://localhost:8123',
72
- })
71
+ url: "http://localhost:8123",
72
+ });
73
73
 
74
74
  await client.query({
75
- query: 'SELECT {t: Tuple(UInt32, String)}',
76
- format: 'JSONEachRow',
77
- query_params: { t: new TupleParam([42, 'hello']) },
78
- })
75
+ query: "SELECT {t: Tuple(UInt32, String)}",
76
+ format: "JSONEachRow",
77
+ query_params: { t: new TupleParam([42, "hello"]) },
78
+ });
79
79
  ```
80
80
 
81
81
  ## Map parameters (`>= 1.9.0`)
@@ -84,10 +84,10 @@ Pass a JS `Map` directly:
84
84
 
85
85
  ```js
86
86
  await client.query({
87
- query: 'SELECT {m: Map(String, UInt32)}',
88
- format: 'JSONEachRow',
89
- query_params: { m: new Map([['key', 1]]) },
90
- })
87
+ query: "SELECT {m: Map(String, UInt32)}",
88
+ format: "JSONEachRow",
89
+ query_params: { m: new Map([["key", 1]]) },
90
+ });
91
91
  ```
92
92
 
93
93
  ## NULL parameters
@@ -96,8 +96,8 @@ Pass `null` directly — binding fixed in `0.0.16`:
96
96
 
97
97
  ```js
98
98
  await client.query({
99
- query: 'SELECT {val: Nullable(String)}',
100
- format: 'JSONEachRow',
99
+ query: "SELECT {val: Nullable(String)}",
100
+ format: "JSONEachRow",
101
101
  query_params: { val: null },
102
- })
102
+ });
103
103
  ```
@@ -9,17 +9,17 @@
9
9
  **Fix:** Remove response compression for read-only users:
10
10
 
11
11
  ```js
12
- import { createClient } from '@clickhouse/client'
12
+ import { createClient } from "@clickhouse/client";
13
13
 
14
14
  // Don't do this with a readonly=1 user:
15
15
  // compression: { response: true }
16
16
 
17
17
  const client = createClient({
18
- username: 'my_readonly_user',
19
- password: '...',
18
+ username: "my_readonly_user",
19
+ password: "...",
20
20
  // compression omitted, or explicitly set to false
21
21
  compression: {
22
22
  response: false,
23
23
  },
24
- })
24
+ });
25
25
  ```
@@ -16,11 +16,11 @@
16
16
  > **Requires:** `>= 0.2.0` (logging support with `log.level` config option). In `>= 1.18.1`, the default log level changed from `OFF` to `WARN`, so this step may already be active. In `>= 1.18.2`, the client auto-emits a WARN log with Keep-Alive troubleshooting hints when an `ECONNRESET` is detected. In `>= 1.12.0`, a warning is logged when a socket is closed without fully consuming the stream.
17
17
 
18
18
  ```js
19
- import { createClient, ClickHouseLogLevel } from '@clickhouse/client'
19
+ import { createClient, ClickHouseLogLevel } from "@clickhouse/client";
20
20
 
21
21
  const client = createClient({
22
22
  log: { level: ClickHouseLogLevel.WARN },
23
- })
23
+ });
24
24
  ```
25
25
 
26
26
  Look for log lines about unconsumed or dangling streams — these are a common hidden cause. A **dangling stream** is a query response stream that was never fully consumed or explicitly closed with `ResultSet.close()`. Because the Node.js client reuses sockets (Keep-Alive), leaving a stream open corrupts the socket and causes the _next_ request to fail with `ECONNRESET`. Errors on **every request** strongly suggest dangling streams rather than a Keep-Alive timeout mismatch.
@@ -29,33 +29,33 @@ Look for log lines about unconsumed or dangling streams — these are a common h
29
29
 
30
30
  ```js
31
31
  // ❌ Wrong — result stream never consumed; socket is left open
32
- const resultSet = await client.query({ query: 'SELECT ...' })
32
+ const resultSet = await client.query({ query: "SELECT ..." });
33
33
  // result is abandoned without calling .json(), .text(), .stream(), or .close()
34
34
 
35
35
  // ❌ Wrong — stream created but not fully piped/iterated
36
36
  const resultSet = await client.query({
37
- query: 'SELECT ...',
38
- format: 'JSONEachRow',
39
- })
40
- const stream = resultSet.stream()
37
+ query: "SELECT ...",
38
+ format: "JSONEachRow",
39
+ });
40
+ const stream = resultSet.stream();
41
41
  // stream is never iterated and resultSet is never closed
42
42
 
43
43
  // ✓ Correct — consume via .json()
44
- const resultSet = await client.query({ query: 'SELECT ...' })
45
- const data = await resultSet.json()
44
+ const resultSet = await client.query({ query: "SELECT ..." });
45
+ const data = await resultSet.json();
46
46
 
47
47
  // ✓ Correct — consume via async iteration
48
48
  const resultSet = await client.query({
49
- query: 'SELECT ...',
50
- format: 'JSONEachRow',
51
- })
49
+ query: "SELECT ...",
50
+ format: "JSONEachRow",
51
+ });
52
52
  for await (const rows of resultSet.stream()) {
53
53
  // process rows
54
54
  }
55
55
 
56
56
  // ✓ Correct — explicitly close; this destroys the underlying socket immediately
57
- const resultSet = await client.query({ query: 'SELECT ...' })
58
- resultSet.close()
57
+ const resultSet = await client.query({ query: "SELECT ..." });
58
+ resultSet.close();
59
59
  ```
60
60
 
61
61
  ## Step 2 — Check your ESLint setup
@@ -86,7 +86,7 @@ const client = createClient({
86
86
  keep_alive: {
87
87
  idle_socket_ttl: 9000, // stay ~500ms below the server's timeout
88
88
  },
89
- })
89
+ });
90
90
  ```
91
91
 
92
92
  > ⚠️ If you still get errors after increasing, **lower** the value, not raise it.
@@ -104,9 +104,9 @@ const client = createClient({
104
104
  request_timeout: 400_000, // e.g. 400s for long queries
105
105
  clickhouse_settings: {
106
106
  send_progress_in_http_headers: 1,
107
- http_headers_progress_interval_ms: '110000', // string — UInt64 type; set ~10s below LB idle timeout
107
+ http_headers_progress_interval_ms: "110000", // string — UInt64 type; set ~10s below LB idle timeout
108
108
  },
109
- })
109
+ });
110
110
  ```
111
111
 
112
112
  ### ⚠️ Critical: 16 KB Node.js Header Size Limit
@@ -140,9 +140,9 @@ const client = createClient({
140
140
  max_response_headers_size: 65536, // 64 KB; lifts the per-request header cap
141
141
  clickhouse_settings: {
142
142
  send_progress_in_http_headers: 1,
143
- http_headers_progress_interval_ms: '110000',
143
+ http_headers_progress_interval_ms: "110000",
144
144
  },
145
- })
145
+ });
146
146
  ```
147
147
 
148
148
  ```bash
@@ -200,5 +200,5 @@ Adds overhead (new TCP connection per request) but eliminates all Keep-Alive iss
200
200
  ```js
201
201
  const client = createClient({
202
202
  keep_alive: { enabled: false },
203
- })
203
+ });
204
204
  ```
@@ -5,34 +5,34 @@
5
5
  ## Basic TLS (CA certificate only)
6
6
 
7
7
  ```js
8
- import fs from 'fs'
9
- import { createClient } from '@clickhouse/client'
8
+ import fs from "fs";
9
+ import { createClient } from "@clickhouse/client";
10
10
 
11
11
  const client = createClient({
12
- url: 'https://<hostname>:<port>',
13
- username: '<user>',
14
- password: '<pass>',
12
+ url: "https://<hostname>:<port>",
13
+ username: "<user>",
14
+ password: "<pass>",
15
15
  tls: {
16
- ca_cert: fs.readFileSync('certs/CA.pem'),
16
+ ca_cert: fs.readFileSync("certs/CA.pem"),
17
17
  },
18
- })
18
+ });
19
19
  ```
20
20
 
21
21
  ## Mutual TLS (client certificate + key)
22
22
 
23
23
  ```js
24
- import fs from 'fs'
25
- import { createClient } from '@clickhouse/client'
24
+ import fs from "fs";
25
+ import { createClient } from "@clickhouse/client";
26
26
 
27
27
  const client = createClient({
28
- url: 'https://<hostname>:<port>',
29
- username: '<user>',
28
+ url: "https://<hostname>:<port>",
29
+ username: "<user>",
30
30
  tls: {
31
- ca_cert: fs.readFileSync('certs/CA.pem'),
32
- cert: fs.readFileSync('certs/client.crt'),
33
- key: fs.readFileSync('certs/client.key'),
31
+ ca_cert: fs.readFileSync("certs/CA.pem"),
32
+ cert: fs.readFileSync("certs/client.crt"),
33
+ key: fs.readFileSync("certs/client.key"),
34
34
  },
35
- })
35
+ });
36
36
  ```
37
37
 
38
38
  > **Tip (`>= 1.2.0`):** If you need a custom HTTP(S) agent, use the `http_agent` option. Only set `set_basic_auth_header: false` if you must avoid sending the basic-auth `Authorization` header (for example, due to a header conflict); in that case, provide alternative auth headers such as `X-ClickHouse-User` / `X-ClickHouse-Key` via `http_headers`.
@@ -59,29 +59,29 @@ The server uses a self-signed cert (the certificate is its own CA). Options in o
59
59
 
60
60
  ```js
61
61
  tls: {
62
- ca_cert: fs.readFileSync('certs/server.crt')
62
+ ca_cert: fs.readFileSync("certs/server.crt");
63
63
  }
64
64
  ```
65
65
 
66
66
  2. For development only — disable verification via a custom agent (`>= 1.2.0`):
67
67
 
68
68
  ```js
69
- import https from 'https'
70
- import { createClient } from '@clickhouse/client'
69
+ import https from "https";
70
+ import { createClient } from "@clickhouse/client";
71
71
 
72
72
  const client = createClient({
73
- url: 'https://<hostname>:<port>',
74
- username: '<user>',
75
- password: '<pass>',
73
+ url: "https://<hostname>:<port>",
74
+ username: "<user>",
75
+ password: "<pass>",
76
76
  http_agent: new https.Agent({ rejectUnauthorized: false }),
77
77
  // Optional: only disable the basic-auth Authorization header if you need to
78
78
  // provide alternative auth headers instead.
79
79
  set_basic_auth_header: false,
80
80
  http_headers: {
81
- 'X-ClickHouse-User': '<user>',
82
- 'X-ClickHouse-Key': '<pass>',
81
+ "X-ClickHouse-User": "<user>",
82
+ "X-ClickHouse-Key": "<pass>",
83
83
  },
84
- })
84
+ });
85
85
  ```
86
86
 
87
87
  > ⚠️ Never use `rejectUnauthorized: false` in production — it disables all certificate verification.