Releases: ClickHouse/clickhouse-js
1.3.0 (Common, Node.js, Web)
New features
-
It is now possible to get the entire response headers object from the
query
/insert
/command
/exec
methods. Withquery
, you can access theResultSet.response_headers
property; other methods (insert
/command
/exec
) return it as parts of their response objects as well.
For example:const rs = await client.query({ query: 'SELECT * FROM system.numbers LIMIT 1', format: 'JSONEachRow', }) console.log(rs.response_headers['content-type'])
This will print:
application/x-ndjson; charset=UTF-8
. It can be used in a similar way with the other methods.
Improvements
-
Re-exported several constants from the
@clickhouse/client-common
package for convenience:SupportedJSONFormats
SupportedRawFormats
StreamableFormats
StreamableJSONFormats
SingleDocumentJSONFormats
RecordsJSONFormats
1.2.0 (Node.js only)
New features
-
(Experimental) Added an option to provide a custom HTTP Agent in the client configuration via the
http_agent
option (#283, related: #278). The following conditions apply if a custom HTTP Agent is provided:- The
max_open_connections
andtls
options will have no effect and will be ignored by the client, as those are part of the underlying HTTP Agent configuration. keep_alive.enabled
will only regulate the default value of theConnection
header (true
->Connection: keep-alive
,false
->Connection: close
).- While the idle socket management will still work, it is now possible to disable it completely by setting the
keep_alive.idle_socket_ttl
value to0
.
- The
-
(Experimental) Added a new client configuration option:
set_basic_auth_header
, which controls whether theAuthorization
header should be set for every outgoing HTTP request (enabled by default). One of the possible scenarios when it is necessary to disable this header is when a custom HTTPS agent is used, and the server requires TLS with certificates. For example:const agent = new https.Agent({ keepAlive: true, keepAliveMsecs: 2500, maxSockets: 10, maxFreeSockets: 10, ca: fs.readFileSync('./ca.crt'), cert: fs.readFileSync('./client.crt'), key: fs.readFileSync('./client.key'), }) const client = createClient({ url: 'https://myserver:8443', http_agent: agent, // With a custom HTTPS agent, the client won't use the default HTTPS connection implementation; the headers should be provided manually http_headers: { 'X-ClickHouse-User': 'username', 'X-ClickHouse-Key': 'password', 'X-ClickHouse-SSL-Certificate-Auth': 'on', }, // Important: authorization header conflicts with the TLS headers; disable it. set_basic_auth_header: false, })
NB: It is currently not possible to set the set_basic_auth_header
option via the URL params.
See the doc entry regarding custom HTTP(s) Agent usage with code samples.
If you have feedback on these experimental features, please let us know by creating an issue in the repository or send a message in the Community Slack (#clickhouse-js
channel).
1.1.0
New features
- Added an option to override the credentials for a particular
query
/command
/exec
/insert
request via theBaseQueryParams.auth
setting; when set, the credentials will be taken from there instead of the username/password provided during the client instantiation (#278). - Added an option to override the
session_id
for a particularquery
/command
/exec
/insert
request via theBaseQueryParams.session_id
setting; when set, it will be used instead of the session id provided during the client instantiation (@holi0317, #271).
Bug fixes
- Fixed the incorrect
ResponseJSON<T>.totals
TypeScript type. Now it correctly matches the shape of the data (T
, default =unknown
) instead of the formerRecord<string, number>
definition (#274).
1.0.2
Bug fixes
- The
command
method now drains the response stream properly, as the previous implementation could cause theKeep-Alive
socket to close after each request. - (Node.js) Removed an unnecessary error log in the
ResultSet.stream
method if the request was aborted or the result set was closed (#263).
Improvements
1.0.1
1.0.0
Formal stable release milestone with many improvements and some breaking changes.
Major new features overview:
- Advanced TypeScript support for
query
+ResultSet
- URL configuration
From now on, the client will follow the official semantic versioning guidelines.
Deprecated API
The following configuration parameters are marked as deprecated:
- The
host
configuration parameter is deprecated; useurl
instead. additional_headers
configuration parameter is deprecated; usehttp_headers
instead.
The client will log a warning if any of these parameters are used. However, it is still allowed to use host
instead of url
and additional_headers
instead of http_headers
for now; this deprecation is not supposed to break the existing code.
These parameters will be removed in the next major release (2.0.0).
See the "New features" section for more details.
Breaking changes in 1.0.0
compression.response
is now disabled by default in the client configuration options, as it cannot be used with readonly=1 users, and it was not clear from the ClickHouse error message what exact client option was causing the failing query in this case. If you'd like to continue using response compression, you should explicitly enable it in the client configuration.- As the client now supports parsing URL configuration, you should specify
pathname
as a separate configuration option (as it would be considered as thedatabase
otherwise). - (TypeScript only)
ResultSet
andRow
are now more strictly typed, according to the format used during thequery
call. - (TypeScript only) Both Node.js and Web versions now uniformly export correct
ClickHouseClient
andClickHouseClientConfigOptions
types specific to each implementation. ExportedClickHouseClient
now does not have aStream
type parameter, as it was unintended to expose it there. NB: you should still use thecreateClient
factory function provided in the package.
New features in 1.0.0
Advanced TypeScript support for query
+ ResultSet
The client will now try its best to figure out the shape of the data based on the DataFormat literal specified to the query
call, as well as which methods are allowed to be called on the ResultSet
.
Live demo (see the full description below):
Screencast.from.2024-03-09.08-10-26.webm
Complete reference:
Format | ResultSet.json<T>() |
ResultSet.stream<T>() |
Stream data | Row.json<T>() |
---|---|---|---|---|
JSON | ResponseJSON<T> | never | never | never |
JSONObjectEachRow | Record<string, T> | never | never | never |
All other JSON*EachRow | Array<T> | Stream<Array<Row<T>>> | Array<Row<T>> | T |
CSV/TSV/CustomSeparated/Parquet | never | Stream<Array<Row<T>>> | Array<Row<T>> | never |
By default, T
(which represents JSONType
) is still unknown
. However, considering the JSONObjectsEachRow
example, prior to 1.0.0, you had to specify the entire type hint, including the shape of the data, manually:
type Data = { foo: string }
const resultSet = await client.query({
query: 'SELECT * FROM my_table',
format: 'JSONObjectsEachRow',
})
// pre-1.0.0, `resultOld` has type Record<string, Data>
const resultOld = resultSet.json<Record<string, Data>>()
// const resultOld = resultSet.json<Data>() // incorrect! The type hint should've been `Record<string, Data>` here.
// 1.0.0, `resultNew` also has type Record<string, Data>; the client inferred that it has to be a Record from the format literal.
const resultNew = resultSet.json<Data>()
This is even more handy in the case of streaming on the Node.js platform:
const resultSet = await client.query({
query: 'SELECT * FROM my_table',
format: 'JSONEachRow',
})
// pre-1.0.0
// `streamOld` was just a regular Node.js Stream.Readable
const streamOld = resultSet.stream()
// `rows` were `any`, needed an explicit type hint
streamNew.on('data', (rows: Row[]) => {
rows.forEach((row) => {
// without an explicit type hint to `rows`, calling `forEach` and other array methods resulted in TS compiler errors
const t = row.text
const j = row.json<Data>() // `j` needed a type hint here, otherwise, it's `unknown`
})
})
// 1.0.0
// `streamNew` is now StreamReadable<T> (Node.js Stream.Readable with a bit more type hints);
// type hint for the further `json` calls can be added here (and removed from the `json` calls)
const streamNew = resultSet.stream<Data>()
// `rows` are inferred as an Array<Row<Data, "JSONEachRow">> instead of `any`
streamNew.on('data', (rows) => {
// `row` is inferred as Row<Data, "JSONEachRow">
rows.forEach((row) => {
// no explicit type hints required, you can use `forEach` straight away and TS compiler will be happy
const t = row.text
const j = row.json() // `j` will be of type Data
})
})
// async iterator now also has type hints
//Similarly to the `on(data)` example above, `rows` are inferred as Array<Row<Data, "JSONEachRow">>
for await (const rows of streamNew) {
// `row` is inferred as Row<Data, "JSONEachRow">
rows.forEach((row) => {
const t = row.text
const j = row.json() // `j` will be of type Data
})
}
Calling ResultSet.stream
is not allowed for specific data formats, such as JSON
and JSONObjectsEachRow
(unlike JSONEachRow
and the rest of JSON*EachRow
, these formats return a single object). In these cases, the client throws an error. However, it was previously not reflected on the type level; now, calling stream
on these formats will result in a TS compiler error. For example:
const resultSet = await client.query('SELECT * FROM table', {
format: 'JSON',
})
const stream = resultSet.stream() // `stream` is `never`
Calling ResultSet.json
also does not make sense on CSV
and similar "raw" formats, and the client throws. Again, now, it is typed properly:
const resultSet = await client.query('SELECT * FROM table', {
format: 'CSV',
})
// `json` is `never`; same if you stream CSV, and call `Row.json` - it will be `never`, too.
const json = resultSet.json()
Currently, there is one known limitation: as the general shape of the data and the methods allowed for calling are inferred from the format literal, there might be situations where it will fail to do so, for example:
// assuming that `queryParams` has `JSONObjectsEachRow` format inside
async function runQuery(
queryParams: QueryParams,
): Promise<Record<string, Data>> {
const resultSet = await client.query(queryParams)
// type hint here will provide a union of all known shapes instead of a specific one
// inferred shapes: Data[] | ResponseJSON<Data> | Record<string, Data>
return resultSet.json<Data>()
}
In this case, as it is likely that you already know the desired format in advance (otherwise, returning a specific shape like Record<string, Data>
would've been incorrect), consider helping the client a bit:
async function runQuery(
queryParams: QueryParams,
): Promise<Record<string, Data>> {
const resultSet = await client.query({
...queryParams,
format: 'JSONObjectsEachRow',
})
// TS understands that it is a Record<string, Data> now
return resultSet.json<Data>()
}
If you are interested in more details, see the related test (featuring a great ESLint plugin expect-types) in the client package.
URL configuration
- Added
url
configuration parameter. It is intended to replace the deprecatedhost
, which was already supposed to be passed as a valid URL. - It is now possible to configure most of the client instance parameters with a URL. The URL format is
http[s]://[username:password@]hostname:port[/database][?param1=value1¶m2=value2]
. In almost every case, the name of a particular parameter reflects its path in the config options interface, with a few exceptions. The following parameters are supported:
Parameter | Type |
---|---|
pathname |
an arbitrary string. |
application_id |
an arbitrary string. |
session_id |
an arbitrary string. |
request_timeout |
non-negative number. |
max_open_connections |
non-negative number, greater than zero. |
compression_request |
boolean. See below [1]. |
compression_response |
boolean. |
log_level |
allowed values: OFF , TRACE , DEBUG , INFO , WARN , ERROR . |
keep_alive_enabled |
boolean. |
clickhouse_setting_* or ch_* |
see be... |
0.3.1 (Common, Node.js, Web)
Bug fixes
- Fixed an issue where query parameters containing tabs or newline characters were not encoded properly (#249).
0.3.0 (Common, Node.js)
This release primarily focuses on improving the Keep-Alive mechanism's reliability on the client side.
New features
-
Idle sockets timeout rework; now, the client attaches internal timers to idling sockets and forcefully removes them from the pool if it is considered that a particular socket has been idling for too long. This additional socket housekeeping intends to eliminate "Socket hang-up" errors that could previously still occur on certain configurations. Now, the client does not rely on the KeepAlive agent when it comes to removing the idling sockets; in most cases, the server will not close the socket before the client does.
-
There is a new
keep_alive.idle_socket_ttl
configuration parameter. The default value is2500
(milliseconds), which is considered to be safe, as ClickHouse versions prior to 23.11 hadkeep_alive_timeout
set to 3 seconds by default, andkeep_alive.idle_socket_ttl
is supposed to be slightly less than that to allow the client to remove the sockets that are about to expire before the server does so. -
Logging improvements: more internal logs on failing requests; all client methods except ping will log an error on failure now. A failed ping will log a warning since the underlying error is returned as a part of its result. Client logging still needs to be enabled explicitly by specifying the desired
log.level
config option, as the log level isOFF
by default. Currently, the client logs the following events, depending on the selectedlog.level
value:TRACE
- low-level information about the Keep-Alive sockets lifecycle.DEBUG
- response information (without authorization headers and host info).INFO
- still mostly unused, will print the current log level when the client is initialized.WARN
- non-fatal errors; failedping
request is logged as a warning, as the underlying error is included in the returned result.ERROR
- fatal errors fromquery
/insert
/exec
/command
methods, such as a failed request.
Breaking changes
keep_alive.retry_on_expired_socket
andkeep_alive.socket_ttl
configuration parameters are removed.- The
max_open_connections
configuration parameter is now 10 by default, as we should not rely on the KeepAlive agent's defaults. - Fixed the default
request_timeout
configuration value (now it is correctly set to30_000
, previously300_000
(milliseconds)).
Bug fixes
- Fixed a bug with Ping that could lead to an unhandled "Socket hang-up" propagation.
- The client ensures proper
Connection
header value considering Keep-Alive settings. If Keep-Alive is disabled, its value is now forced to "close".
0.2.10 (Common, Node.js, Web)
New features
- If
InsertParams.values
is an empty array, no request is sent to the server andClickHouseClient.insert
short-circuits itself. In this scenario, the newly addedInsertResult.executed
flag will befalse
, andInsertResult.query_id
will be an empty string.
Bug fixes
- Client no longer produces
Code: 354. inflate failed: buffer error
exception if request compression is enabled andInsertParams.values
is an empty array (see above).
0.2.9 (Common, Node.js, Web)
New features
- It is now possible to set additional HTTP headers for outgoing ClickHouse requests. This might be useful if, for example, you have a reverse proxy with authorization. (@teawithfruit)
const client = createClient({
additional_headers: {
'X-ClickHouse-User': 'clickhouse_user',
'X-ClickHouse-Key': 'clickhouse_password',
},
})