@clickhouse/client 1.20.0 → 1.21.0-head.68dd619.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/README.md +11 -11
- package/dist/client.d.ts +6 -6
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +6 -6
- package/dist/config.js +6 -5
- package/dist/config.js.map +1 -1
- package/dist/connection/compression.d.ts +4 -4
- package/dist/connection/compression.js +3 -3
- package/dist/connection/compression.js.map +1 -1
- package/dist/connection/create_connection.d.ts +6 -6
- package/dist/connection/create_connection.js +3 -3
- package/dist/connection/create_connection.js.map +1 -1
- package/dist/connection/index.d.ts +4 -4
- package/dist/connection/index.js.map +1 -1
- package/dist/connection/node_base_connection.d.ts +11 -11
- package/dist/connection/node_base_connection.js +75 -42
- package/dist/connection/node_base_connection.js.map +1 -1
- package/dist/connection/node_custom_agent_connection.d.ts +4 -4
- package/dist/connection/node_custom_agent_connection.js +2 -2
- package/dist/connection/node_custom_agent_connection.js.map +1 -1
- package/dist/connection/node_http_connection.d.ts +4 -4
- package/dist/connection/node_http_connection.js.map +1 -1
- package/dist/connection/node_https_connection.d.ts +5 -5
- package/dist/connection/node_https_connection.js +11 -11
- package/dist/connection/node_https_connection.js.map +1 -1
- package/dist/connection/socket_pool.d.ts +9 -9
- package/dist/connection/socket_pool.js +33 -32
- package/dist/connection/socket_pool.js.map +1 -1
- package/dist/connection/stream.d.ts +2 -2
- package/dist/connection/stream.js +18 -18
- package/dist/connection/stream.js.map +1 -1
- package/dist/index.d.ts +41 -8
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/result_set.d.ts +31 -20
- package/dist/result_set.js +83 -13
- package/dist/result_set.js.map +1 -1
- package/dist/utils/encoder.d.ts +2 -2
- package/dist/utils/encoder.js +3 -3
- package/dist/utils/encoder.js.map +1 -1
- package/dist/utils/index.d.ts +4 -4
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/process.js.map +1 -1
- package/dist/utils/runtime.js.map +1 -1
- package/dist/utils/stream.d.ts +1 -1
- package/dist/utils/stream.js +8 -8
- package/dist/utils/stream.js.map +1 -1
- package/dist/utils/user_agent.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/reference/async-insert.md +12 -12
- package/skills/clickhouse-js-node-coding/reference/client-configuration.md +16 -16
- package/skills/clickhouse-js-node-coding/reference/custom-json.md +31 -31
- package/skills/clickhouse-js-node-coding/reference/data-types.md +65 -65
- package/skills/clickhouse-js-node-coding/reference/insert-columns.md +23 -23
- package/skills/clickhouse-js-node-coding/reference/insert-formats.md +30 -30
- package/skills/clickhouse-js-node-coding/reference/insert-values.md +35 -35
- package/skills/clickhouse-js-node-coding/reference/ping.md +24 -24
- package/skills/clickhouse-js-node-coding/reference/query-parameters.md +27 -27
- package/skills/clickhouse-js-node-coding/reference/select-formats.md +21 -21
- package/skills/clickhouse-js-node-coding/reference/sessions.md +27 -27
- package/skills/clickhouse-js-node-troubleshooting/reference/compression.md +2 -2
- package/skills/clickhouse-js-node-troubleshooting/reference/data-types.md +24 -24
- package/skills/clickhouse-js-node-troubleshooting/reference/logging.md +5 -5
- package/skills/clickhouse-js-node-troubleshooting/reference/proxy-pathname.md +7 -7
- package/skills/clickhouse-js-node-troubleshooting/reference/query-format-clause.md +6 -6
- package/skills/clickhouse-js-node-troubleshooting/reference/query-params.md +30 -30
- package/skills/clickhouse-js-node-troubleshooting/reference/readonly-users.md +4 -4
- package/skills/clickhouse-js-node-troubleshooting/reference/socket-hangup.md +20 -20
- package/skills/clickhouse-js-node-troubleshooting/reference/tls.md +24 -24
|
@@ -14,7 +14,7 @@ await client.command({
|
|
|
14
14
|
INSERT INTO target
|
|
15
15
|
SELECT * FROM source
|
|
16
16
|
`,
|
|
17
|
-
})
|
|
17
|
+
});
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
Use `command()` (not `insert()`) — there is no row payload to send.
|
|
@@ -38,13 +38,13 @@ await client.command({
|
|
|
38
38
|
)
|
|
39
39
|
`,
|
|
40
40
|
query_params: {
|
|
41
|
-
id:
|
|
42
|
-
timestamp:
|
|
43
|
-
email:
|
|
44
|
-
name:
|
|
41
|
+
id: "00112233445566778899aabbccddeeff",
|
|
42
|
+
timestamp: "2026-05-06 12:34:56",
|
|
43
|
+
email: "alice@example.com",
|
|
44
|
+
name: "Alice",
|
|
45
45
|
},
|
|
46
46
|
clickhouse_settings: { wait_end_of_query: 1 },
|
|
47
|
-
})
|
|
47
|
+
});
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
Do not build `VALUES` rows with string interpolation or manual escaping. If
|
|
@@ -61,13 +61,13 @@ session-wide.
|
|
|
61
61
|
|
|
62
62
|
```ts
|
|
63
63
|
await client.insert({
|
|
64
|
-
table:
|
|
65
|
-
format:
|
|
66
|
-
values: [{ id:
|
|
64
|
+
table: "events",
|
|
65
|
+
format: "JSONEachRow",
|
|
66
|
+
values: [{ id: "42", dt: new Date() }],
|
|
67
67
|
clickhouse_settings: {
|
|
68
|
-
date_time_input_format:
|
|
68
|
+
date_time_input_format: "best_effort", // default on the Cloud
|
|
69
69
|
},
|
|
70
|
-
})
|
|
70
|
+
});
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
> JS `Date` objects do **not** work for the `Date` type (date-only) — pass
|
|
@@ -97,22 +97,22 @@ await client.command({
|
|
|
97
97
|
)
|
|
98
98
|
ENGINE MergeTree ORDER BY id
|
|
99
99
|
`,
|
|
100
|
-
})
|
|
100
|
+
});
|
|
101
101
|
|
|
102
102
|
await client.insert({
|
|
103
|
-
table:
|
|
104
|
-
format:
|
|
103
|
+
table: "prices",
|
|
104
|
+
format: "JSONEachRow",
|
|
105
105
|
values: [
|
|
106
106
|
{
|
|
107
107
|
id: 1,
|
|
108
|
-
dec32:
|
|
109
|
-
dec64:
|
|
110
|
-
dec128:
|
|
108
|
+
dec32: "1234567.89",
|
|
109
|
+
dec64: "123456789123456.789",
|
|
110
|
+
dec128: "1234567891234567891234567891.1234567891",
|
|
111
111
|
dec256:
|
|
112
|
-
|
|
112
|
+
"12345678912345678912345678911234567891234567891234567891.12345678911234567891",
|
|
113
113
|
},
|
|
114
114
|
],
|
|
115
|
-
})
|
|
115
|
+
});
|
|
116
116
|
```
|
|
117
117
|
|
|
118
118
|
When reading them back, cast to string in the SELECT to avoid the same
|
|
@@ -125,8 +125,8 @@ const rs = await client.query({
|
|
|
125
125
|
toString(dec128) AS decimal128
|
|
126
126
|
FROM prices
|
|
127
127
|
`,
|
|
128
|
-
format:
|
|
129
|
-
})
|
|
128
|
+
format: "JSONEachRow",
|
|
129
|
+
});
|
|
130
130
|
```
|
|
131
131
|
|
|
132
132
|
## Inserting a `UUID` into a `UInt128` column
|
|
@@ -142,11 +142,11 @@ clause**. With the row-oriented JSON formats the client uses (e.g.
|
|
|
142
142
|
always pass `UInt128` as a string:
|
|
143
143
|
|
|
144
144
|
```ts
|
|
145
|
-
import * as crypto from
|
|
145
|
+
import * as crypto from "node:crypto";
|
|
146
146
|
|
|
147
147
|
function uuidToUInt128(uuid: string): string {
|
|
148
148
|
// 8-4-4-4-12 hex digits → 32 hex digits → BigInt → decimal string
|
|
149
|
-
return BigInt(
|
|
149
|
+
return BigInt("0x" + uuid.replace(/-/g, "")).toString();
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
await client.command({
|
|
@@ -154,14 +154,14 @@ await client.command({
|
|
|
154
154
|
CREATE OR REPLACE TABLE events (id UInt128, description String)
|
|
155
155
|
ENGINE MergeTree ORDER BY id
|
|
156
156
|
`,
|
|
157
|
-
})
|
|
157
|
+
});
|
|
158
158
|
|
|
159
|
-
const uuid = crypto.randomUUID()
|
|
159
|
+
const uuid = crypto.randomUUID();
|
|
160
160
|
await client.insert({
|
|
161
|
-
table:
|
|
162
|
-
format:
|
|
163
|
-
values: [{ id: uuidToUInt128(uuid), description:
|
|
164
|
-
})
|
|
161
|
+
table: "events",
|
|
162
|
+
format: "JSONEachRow",
|
|
163
|
+
values: [{ id: uuidToUInt128(uuid), description: "converted on the client" }],
|
|
164
|
+
});
|
|
165
165
|
```
|
|
166
166
|
|
|
167
167
|
`UInt128` values are also too wide for a JS `number` when reading back — cast
|
|
@@ -181,15 +181,15 @@ await client.command({
|
|
|
181
181
|
)
|
|
182
182
|
ENGINE MergeTree ORDER BY id
|
|
183
183
|
`,
|
|
184
|
-
})
|
|
184
|
+
});
|
|
185
185
|
|
|
186
186
|
await client.insert({
|
|
187
|
-
table:
|
|
188
|
-
format:
|
|
189
|
-
values: [{ id_uuid: uuid, description:
|
|
187
|
+
table: "events",
|
|
188
|
+
format: "JSONEachRow",
|
|
189
|
+
values: [{ id_uuid: uuid, description: "populated via EPHEMERAL column" }],
|
|
190
190
|
// The ephemeral column must be listed so the DEFAULT on `id` is evaluated.
|
|
191
|
-
columns: [
|
|
192
|
-
})
|
|
191
|
+
columns: ["id_uuid", "description"],
|
|
192
|
+
});
|
|
193
193
|
```
|
|
194
194
|
|
|
195
195
|
See `reference/insert-columns.md` for more on `EPHEMERAL` columns and why they
|
|
@@ -28,20 +28,20 @@ When answering "how do I health-check / readiness-probe ClickHouse?":
|
|
|
28
28
|
## Successful ping
|
|
29
29
|
|
|
30
30
|
```ts
|
|
31
|
-
import { createClient } from
|
|
31
|
+
import { createClient } from "@clickhouse/client";
|
|
32
32
|
|
|
33
33
|
const client = createClient({
|
|
34
34
|
url: process.env.CLICKHOUSE_URL,
|
|
35
35
|
password: process.env.CLICKHOUSE_PASSWORD,
|
|
36
|
-
})
|
|
36
|
+
});
|
|
37
37
|
|
|
38
|
-
const pingResult = await client.ping()
|
|
38
|
+
const pingResult = await client.ping();
|
|
39
39
|
if (pingResult.success) {
|
|
40
|
-
console.info(
|
|
40
|
+
console.info("ClickHouse is reachable");
|
|
41
41
|
} else {
|
|
42
|
-
console.error(
|
|
42
|
+
console.error("Ping failed:", pingResult.error);
|
|
43
43
|
}
|
|
44
|
-
await client.close()
|
|
44
|
+
await client.close();
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
Use `ping()` to:
|
|
@@ -57,44 +57,44 @@ Use `ping()` to:
|
|
|
57
57
|
`{ success: false, error: Error }`, so you can branch without `try/catch`:
|
|
58
58
|
|
|
59
59
|
```ts
|
|
60
|
-
import type { PingResult } from
|
|
61
|
-
import { createClient } from
|
|
60
|
+
import type { PingResult } from "@clickhouse/client";
|
|
61
|
+
import { createClient } from "@clickhouse/client";
|
|
62
62
|
|
|
63
63
|
const client = createClient({
|
|
64
|
-
url:
|
|
64
|
+
url: "http://localhost:8100", // non-existing host
|
|
65
65
|
request_timeout: 50, // keep failure fast
|
|
66
|
-
})
|
|
66
|
+
});
|
|
67
67
|
|
|
68
|
-
const pingResult = await client.ping()
|
|
68
|
+
const pingResult = await client.ping();
|
|
69
69
|
if (hasConnectionRefusedError(pingResult)) {
|
|
70
|
-
console.info(
|
|
70
|
+
console.info("Connection refused, as expected");
|
|
71
71
|
} else {
|
|
72
|
-
console.error(
|
|
72
|
+
console.error("Ping expected ECONNREFUSED, got:", pingResult);
|
|
73
73
|
}
|
|
74
|
-
await client.close()
|
|
74
|
+
await client.close();
|
|
75
75
|
|
|
76
76
|
function hasConnectionRefusedError(
|
|
77
77
|
pingResult: PingResult,
|
|
78
|
-
): pingResult is PingResult & { error: { code:
|
|
78
|
+
): pingResult is PingResult & { error: { code: "ECONNREFUSED" } } {
|
|
79
79
|
return (
|
|
80
80
|
!pingResult.success &&
|
|
81
|
-
|
|
82
|
-
pingResult.error.code ===
|
|
83
|
-
)
|
|
81
|
+
"code" in pingResult.error &&
|
|
82
|
+
pingResult.error.code === "ECONNREFUSED"
|
|
83
|
+
);
|
|
84
84
|
}
|
|
85
85
|
```
|
|
86
86
|
|
|
87
87
|
## Mapping to an HTTP health endpoint
|
|
88
88
|
|
|
89
89
|
```ts
|
|
90
|
-
app.get(
|
|
91
|
-
const r = await client.ping()
|
|
90
|
+
app.get("/healthz", async (_req, res) => {
|
|
91
|
+
const r = await client.ping();
|
|
92
92
|
if (r.success) {
|
|
93
|
-
res.status(200).json({ ok: true })
|
|
93
|
+
res.status(200).json({ ok: true });
|
|
94
94
|
} else {
|
|
95
|
-
res.status(503).json({ ok: false, error: String(r.error) })
|
|
95
|
+
res.status(503).json({ ok: false, error: String(r.error) });
|
|
96
96
|
}
|
|
97
|
-
})
|
|
97
|
+
});
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
## `ping()` vs `ping({ select: true })`
|
|
@@ -107,7 +107,7 @@ pipeline) will still return `{ success: true }` from a plain `ping()`.
|
|
|
107
107
|
Pass `{ select: true }` to run a lightweight `SELECT 1` instead:
|
|
108
108
|
|
|
109
109
|
```ts
|
|
110
|
-
const r = await client.ping({ select: true })
|
|
110
|
+
const r = await client.ping({ select: true });
|
|
111
111
|
// success only if the server is reachable AND auth is correct AND it can run queries
|
|
112
112
|
```
|
|
113
113
|
|
|
@@ -26,10 +26,10 @@ ClickHouse uses `{name: Type}` placeholders — **not** `$1`, `?`, or `:name`.
|
|
|
26
26
|
|
|
27
27
|
```ts
|
|
28
28
|
await client.query({
|
|
29
|
-
query:
|
|
30
|
-
format:
|
|
29
|
+
query: "SELECT plus({a: Int32}, {b: Int32})",
|
|
30
|
+
format: "JSONEachRow",
|
|
31
31
|
query_params: { a: 10, b: 20 },
|
|
32
|
-
})
|
|
32
|
+
});
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
The `Type` must be a valid ClickHouse type (`Int32`, `String`, `Date`,
|
|
@@ -41,16 +41,16 @@ Interpolating user input into the SQL string bypasses server-side escaping
|
|
|
41
41
|
and opens the door to SQL injection:
|
|
42
42
|
|
|
43
43
|
```ts
|
|
44
|
-
const userId = req.params.id
|
|
44
|
+
const userId = req.params.id;
|
|
45
45
|
|
|
46
46
|
// ❌ Dangerous — never do this with user-controlled values
|
|
47
|
-
await client.query({ query: `SELECT * FROM users WHERE id = ${userId}` })
|
|
47
|
+
await client.query({ query: `SELECT * FROM users WHERE id = ${userId}` });
|
|
48
48
|
|
|
49
49
|
// ✓ Safe — parameterized
|
|
50
50
|
await client.query({
|
|
51
|
-
query:
|
|
51
|
+
query: "SELECT * FROM users WHERE id = {id: UInt32}",
|
|
52
52
|
query_params: { id: userId },
|
|
53
|
-
})
|
|
53
|
+
});
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
This is the most common mistake for users coming from PostgreSQL/MySQL. Call
|
|
@@ -59,7 +59,7 @@ it out explicitly when the user shows template-literal interpolation.
|
|
|
59
59
|
## Common types
|
|
60
60
|
|
|
61
61
|
```ts
|
|
62
|
-
import { TupleParam } from
|
|
62
|
+
import { TupleParam } from "@clickhouse/client";
|
|
63
63
|
|
|
64
64
|
await client.query({
|
|
65
65
|
query: `
|
|
@@ -79,27 +79,27 @@ await client.query({
|
|
|
79
79
|
{var_ipv4: IPv4} AS var_ipv4,
|
|
80
80
|
{var_null: Nullable(String)} AS var_null
|
|
81
81
|
`,
|
|
82
|
-
format:
|
|
82
|
+
format: "JSONEachRow",
|
|
83
83
|
query_params: {
|
|
84
84
|
var_int: 10,
|
|
85
|
-
var_float:
|
|
86
|
-
var_str:
|
|
85
|
+
var_float: "10.557",
|
|
86
|
+
var_str: "hello",
|
|
87
87
|
var_array: [42, 144],
|
|
88
|
-
var_tuple: new TupleParam([42,
|
|
88
|
+
var_tuple: new TupleParam([42, "foo"]), // >= 1.9.0
|
|
89
89
|
var_map: new Map([
|
|
90
|
-
[42, [
|
|
91
|
-
[144, [
|
|
90
|
+
[42, ["a", "b"]],
|
|
91
|
+
[144, ["c", "d"]],
|
|
92
92
|
]), // >= 1.9.0
|
|
93
|
-
var_date:
|
|
94
|
-
var_datetime:
|
|
95
|
-
var_datetime64_3:
|
|
96
|
-
var_datetime64_9:
|
|
97
|
-
var_decimal:
|
|
98
|
-
var_uuid:
|
|
99
|
-
var_ipv4:
|
|
93
|
+
var_date: "2022-01-01",
|
|
94
|
+
var_datetime: "2022-01-01 12:34:56", // or a Date
|
|
95
|
+
var_datetime64_3: "2022-01-01 12:34:56.789", // or a Date
|
|
96
|
+
var_datetime64_9: "2022-01-01 12:34:56.123456789", // string for ns precision
|
|
97
|
+
var_decimal: "123.45", // string to avoid precision loss
|
|
98
|
+
var_uuid: "01234567-89ab-cdef-0123-456789abcdef",
|
|
99
|
+
var_ipv4: "192.168.0.1",
|
|
100
100
|
var_null: null, // fixed in 0.0.16
|
|
101
101
|
},
|
|
102
|
-
})
|
|
102
|
+
});
|
|
103
103
|
```
|
|
104
104
|
|
|
105
105
|
### Type-by-type tips
|
|
@@ -131,14 +131,14 @@ await client.query({
|
|
|
131
131
|
'foo_\\'_bar' = {single_quote: String} AS has_single_quote,
|
|
132
132
|
'foo_\\_bar' = {backslash: String} AS has_backslash
|
|
133
133
|
`,
|
|
134
|
-
format:
|
|
134
|
+
format: "JSONEachRow",
|
|
135
135
|
query_params: {
|
|
136
|
-
tab:
|
|
137
|
-
newline:
|
|
136
|
+
tab: "foo_\t_bar",
|
|
137
|
+
newline: "foo_\n_bar",
|
|
138
138
|
single_quote: "foo_'_bar",
|
|
139
|
-
backslash:
|
|
139
|
+
backslash: "foo_\\_bar",
|
|
140
140
|
},
|
|
141
|
-
})
|
|
141
|
+
});
|
|
142
142
|
```
|
|
143
143
|
|
|
144
144
|
## Common pitfalls
|
|
@@ -9,23 +9,23 @@
|
|
|
9
9
|
Right answer for ~90% of selects when the result fits in memory.
|
|
10
10
|
|
|
11
11
|
```ts
|
|
12
|
-
import { createClient } from
|
|
12
|
+
import { createClient } from "@clickhouse/client";
|
|
13
13
|
|
|
14
14
|
interface Row {
|
|
15
|
-
number: string
|
|
15
|
+
number: string;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const client = createClient()
|
|
18
|
+
const client = createClient();
|
|
19
19
|
const rows = await client.query({
|
|
20
|
-
query:
|
|
21
|
-
format:
|
|
22
|
-
})
|
|
23
|
-
const result = await rows.json<Row>() // Row[]
|
|
24
|
-
result.forEach((r) => console.log(r))
|
|
20
|
+
query: "SELECT number FROM system.numbers LIMIT 5",
|
|
21
|
+
format: "JSONEachRow",
|
|
22
|
+
});
|
|
23
|
+
const result = await rows.json<Row>(); // Row[]
|
|
24
|
+
result.forEach((r) => console.log(r));
|
|
25
25
|
// { number: '0' }
|
|
26
26
|
// { number: '1' }
|
|
27
27
|
// ...
|
|
28
|
-
await client.close()
|
|
28
|
+
await client.close();
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
`UInt64`/`Int64` and other 64-bit integers are returned as **strings**
|
|
@@ -41,16 +41,16 @@ Use `JSON` (or `JSONCompact`) when you need ClickHouse's response envelope
|
|
|
41
41
|
`ResponseJSON<T>`:
|
|
42
42
|
|
|
43
43
|
```ts
|
|
44
|
-
import { createClient, type ResponseJSON } from
|
|
44
|
+
import { createClient, type ResponseJSON } from "@clickhouse/client";
|
|
45
45
|
|
|
46
|
-
const client = createClient()
|
|
46
|
+
const client = createClient();
|
|
47
47
|
const rows = await client.query({
|
|
48
|
-
query:
|
|
49
|
-
format:
|
|
50
|
-
})
|
|
51
|
-
const result = await rows.json<ResponseJSON<{ number: string }>>()
|
|
52
|
-
console.info(result.meta, result.data, result.rows, result.statistics)
|
|
53
|
-
await client.close()
|
|
48
|
+
query: "SELECT number FROM system.numbers LIMIT 2",
|
|
49
|
+
format: "JSON",
|
|
50
|
+
});
|
|
51
|
+
const result = await rows.json<ResponseJSON<{ number: string }>>();
|
|
52
|
+
console.info(result.meta, result.data, result.rows, result.statistics);
|
|
53
|
+
await client.close();
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
> `JSON`, `JSONCompact`, `JSONStrings`, `JSONCompactStrings`,
|
|
@@ -64,10 +64,10 @@ Use `.text()` (not `.json()`) for raw textual formats:
|
|
|
64
64
|
|
|
65
65
|
```ts
|
|
66
66
|
const rs = await client.query({
|
|
67
|
-
query:
|
|
68
|
-
format:
|
|
69
|
-
})
|
|
70
|
-
console.log(await rs.text())
|
|
67
|
+
query: "SELECT number, number * 2 AS doubled FROM system.numbers LIMIT 3",
|
|
68
|
+
format: "CSVWithNames",
|
|
69
|
+
});
|
|
70
|
+
console.log(await rs.text());
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
Streaming raw text/Parquet line-by-line belongs in
|
|
@@ -65,30 +65,30 @@ script, a background job, a single user's session that you've already manually
|
|
|
65
65
|
serialized in the code).
|
|
66
66
|
|
|
67
67
|
```ts
|
|
68
|
-
import { createClient } from
|
|
69
|
-
import * as crypto from
|
|
68
|
+
import { createClient } from "@clickhouse/client";
|
|
69
|
+
import * as crypto from "node:crypto";
|
|
70
70
|
|
|
71
71
|
const client = createClient({
|
|
72
72
|
session_id: crypto.randomUUID(),
|
|
73
73
|
max_open_connections: 1, // safeguard against concurrent-session errors
|
|
74
|
-
})
|
|
74
|
+
});
|
|
75
75
|
|
|
76
76
|
await client.command({
|
|
77
|
-
query:
|
|
78
|
-
})
|
|
77
|
+
query: "CREATE TEMPORARY TABLE temporary_example (i Int32)",
|
|
78
|
+
});
|
|
79
79
|
|
|
80
80
|
await client.insert({
|
|
81
|
-
table:
|
|
81
|
+
table: "temporary_example",
|
|
82
82
|
values: [{ i: 42 }, { i: 144 }],
|
|
83
|
-
format:
|
|
84
|
-
})
|
|
83
|
+
format: "JSONEachRow",
|
|
84
|
+
});
|
|
85
85
|
|
|
86
86
|
const rs = await client.query({
|
|
87
|
-
query:
|
|
88
|
-
format:
|
|
89
|
-
})
|
|
90
|
-
console.info(await rs.json())
|
|
91
|
-
await client.close()
|
|
87
|
+
query: "SELECT * FROM temporary_example",
|
|
88
|
+
format: "JSONEachRow",
|
|
89
|
+
});
|
|
90
|
+
console.info(await rs.json());
|
|
91
|
+
await client.close();
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
## Session-level `SET` commands
|
|
@@ -97,37 +97,37 @@ await client.close()
|
|
|
97
97
|
client, every subsequent call inherits the change.
|
|
98
98
|
|
|
99
99
|
```ts
|
|
100
|
-
import { createClient } from
|
|
101
|
-
import * as crypto from
|
|
100
|
+
import { createClient } from "@clickhouse/client";
|
|
101
|
+
import * as crypto from "node:crypto";
|
|
102
102
|
|
|
103
103
|
const client = createClient({
|
|
104
104
|
session_id: crypto.randomUUID(),
|
|
105
105
|
max_open_connections: 1, // safe-guard against concurrent-session errors
|
|
106
|
-
})
|
|
106
|
+
});
|
|
107
107
|
|
|
108
108
|
await client.command({
|
|
109
|
-
query:
|
|
109
|
+
query: "SET output_format_json_quote_64bit_integers = 0",
|
|
110
110
|
clickhouse_settings: { wait_end_of_query: 1 }, // ack before next call
|
|
111
|
-
})
|
|
111
|
+
});
|
|
112
112
|
|
|
113
113
|
const rs1 = await client.query({
|
|
114
|
-
query:
|
|
115
|
-
format:
|
|
116
|
-
})
|
|
114
|
+
query: "SELECT toInt64(42)",
|
|
115
|
+
format: "JSONEachRow",
|
|
116
|
+
});
|
|
117
117
|
// → 64-bit integers come back as numbers in this query
|
|
118
118
|
|
|
119
119
|
await client.command({
|
|
120
|
-
query:
|
|
120
|
+
query: "SET output_format_json_quote_64bit_integers = 1",
|
|
121
121
|
clickhouse_settings: { wait_end_of_query: 1 },
|
|
122
|
-
})
|
|
122
|
+
});
|
|
123
123
|
|
|
124
124
|
const rs2 = await client.query({
|
|
125
|
-
query:
|
|
126
|
-
format:
|
|
127
|
-
})
|
|
125
|
+
query: "SELECT toInt64(144)",
|
|
126
|
+
format: "JSONEachRow",
|
|
127
|
+
});
|
|
128
128
|
// → 64-bit integers come back as strings again
|
|
129
129
|
|
|
130
|
-
await client.close()
|
|
130
|
+
await client.close();
|
|
131
131
|
```
|
|
132
132
|
|
|
133
133
|
> **`wait_end_of_query: 1` matters here.** Without it, a `SET` on one
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
Both request and response compression are supported. Only **GZIP** is supported (via zlib).
|
|
6
6
|
|
|
7
7
|
```js
|
|
8
|
-
import { createClient } from
|
|
8
|
+
import { createClient } from "@clickhouse/client";
|
|
9
9
|
const client = createClient({
|
|
10
10
|
compression: {
|
|
11
11
|
response: true,
|
|
12
12
|
request: true,
|
|
13
13
|
},
|
|
14
|
-
})
|
|
14
|
+
});
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
## Compression enabled but getting an error?
|
|
@@ -10,10 +10,10 @@ To receive them as numbers (use with caution — precision loss possible):
|
|
|
10
10
|
|
|
11
11
|
```js
|
|
12
12
|
const resultSet = await client.query({
|
|
13
|
-
query:
|
|
14
|
-
format:
|
|
13
|
+
query: "SELECT toUInt64(9007199254740993)",
|
|
14
|
+
format: "JSONEachRow",
|
|
15
15
|
clickhouse_settings: { output_format_json_quote_64bit_integers: 0 },
|
|
16
|
-
})
|
|
16
|
+
});
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
> **Tip (`>= 1.15.0`):** BigInt values are now supported in query parameters, so you can safely pass large integers as bind params without string workarounds.
|
|
@@ -30,18 +30,18 @@ const resultSet = await client.query({
|
|
|
30
30
|
SELECT toString(my_decimal) AS my_decimal
|
|
31
31
|
FROM my_table
|
|
32
32
|
`,
|
|
33
|
-
format:
|
|
34
|
-
})
|
|
33
|
+
format: "JSONEachRow",
|
|
34
|
+
});
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
When inserting, always use the string representation to avoid precision loss:
|
|
38
38
|
|
|
39
39
|
```js
|
|
40
40
|
await client.insert({
|
|
41
|
-
table:
|
|
42
|
-
values: [{ dec64:
|
|
43
|
-
format:
|
|
44
|
-
})
|
|
41
|
+
table: "my_table",
|
|
42
|
+
values: [{ dec64: "123456789123456.789" }],
|
|
43
|
+
format: "JSONEachRow",
|
|
44
|
+
});
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
## Inserting a UUID into a `UInt128` column fails (`CANNOT_PARSE_INPUT_ASSERTION_FAILED`)
|
|
@@ -55,19 +55,19 @@ Fix it with one of two patterns:
|
|
|
55
55
|
**Pattern 1 — convert the UUID on the client and send it as a decimal string** (recommended). A JS `number` cannot hold 128 bits without precision loss, so always pass `UInt128` as a string:
|
|
56
56
|
|
|
57
57
|
```js
|
|
58
|
-
import * as crypto from
|
|
58
|
+
import * as crypto from "node:crypto";
|
|
59
59
|
|
|
60
60
|
function uuidToUInt128(uuid) {
|
|
61
61
|
// 8-4-4-4-12 hex digits → 32 hex digits → BigInt → decimal string
|
|
62
|
-
return BigInt(
|
|
62
|
+
return BigInt("0x" + uuid.replace(/-/g, "")).toString();
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
const uuid = crypto.randomUUID()
|
|
65
|
+
const uuid = crypto.randomUUID();
|
|
66
66
|
await client.insert({
|
|
67
|
-
table:
|
|
68
|
-
format:
|
|
69
|
-
values: [{ id: uuidToUInt128(uuid), description:
|
|
70
|
-
})
|
|
67
|
+
table: "events",
|
|
68
|
+
format: "JSONEachRow",
|
|
69
|
+
values: [{ id: uuidToUInt128(uuid), description: "converted on the client" }],
|
|
70
|
+
});
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
Read `UInt128` back with `toString(id)` in the `SELECT` to avoid the same precision loss.
|
|
@@ -77,11 +77,11 @@ Read `UInt128` back with `toString(id)` in the `SELECT` to avoid the same precis
|
|
|
77
77
|
```js
|
|
78
78
|
// CREATE TABLE events (id UInt128 DEFAULT id_uuid, id_uuid UUID EPHEMERAL, description String) ...
|
|
79
79
|
await client.insert({
|
|
80
|
-
table:
|
|
81
|
-
format:
|
|
82
|
-
values: [{ id_uuid: uuid, description:
|
|
83
|
-
columns: [
|
|
84
|
-
})
|
|
80
|
+
table: "events",
|
|
81
|
+
format: "JSONEachRow",
|
|
82
|
+
values: [{ id_uuid: uuid, description: "populated via EPHEMERAL column" }],
|
|
83
|
+
columns: ["id_uuid", "description"],
|
|
84
|
+
});
|
|
85
85
|
```
|
|
86
86
|
|
|
87
87
|
## Format Selection Quick Reference
|
|
@@ -106,8 +106,8 @@ await client.insert({
|
|
|
106
106
|
- `DateTime` / `DateTime64` columns accept strings **or** JS `Date` objects. To use `Date` objects, set:
|
|
107
107
|
|
|
108
108
|
```js
|
|
109
|
-
import { createClient } from
|
|
109
|
+
import { createClient } from "@clickhouse/client";
|
|
110
110
|
const client = createClient({
|
|
111
|
-
clickhouse_settings: { date_time_input_format:
|
|
112
|
-
})
|
|
111
|
+
clickhouse_settings: { date_time_input_format: "best_effort" },
|
|
112
|
+
});
|
|
113
113
|
```
|
|
@@ -5,20 +5,20 @@
|
|
|
5
5
|
The default log level is **OFF** (for `< 1.18.1`) or **WARN** (for `>= 1.18.1`). Enable it explicitly:
|
|
6
6
|
|
|
7
7
|
```js
|
|
8
|
-
import { ClickHouseLogLevel, createClient } from
|
|
8
|
+
import { ClickHouseLogLevel, createClient } from "@clickhouse/client";
|
|
9
9
|
|
|
10
10
|
const client = createClient({
|
|
11
11
|
log: {
|
|
12
12
|
level: ClickHouseLogLevel.DEBUG, // TRACE | DEBUG | INFO | WARN | ERROR
|
|
13
13
|
},
|
|
14
|
-
})
|
|
14
|
+
});
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
To use a custom logger (e.g., to pipe to your observability stack), implement the `Logger` interface:
|
|
18
18
|
|
|
19
19
|
```ts
|
|
20
|
-
import { ClickHouseLogLevel, createClient } from
|
|
21
|
-
import type { Logger } from
|
|
20
|
+
import { ClickHouseLogLevel, createClient } from "@clickhouse/client";
|
|
21
|
+
import type { Logger } from "@clickhouse/client";
|
|
22
22
|
|
|
23
23
|
class MyLogger implements Logger {
|
|
24
24
|
debug({ module, message, args }) {
|
|
@@ -40,5 +40,5 @@ class MyLogger implements Logger {
|
|
|
40
40
|
|
|
41
41
|
const client = createClient({
|
|
42
42
|
log: { LoggerClass: MyLogger, level: ClickHouseLogLevel.INFO },
|
|
43
|
-
})
|
|
43
|
+
});
|
|
44
44
|
```
|