Skip to content

Commit e4fa915

Browse files
Add ClickHouse module (#981)
1 parent 24d02ce commit e4fa915

File tree

9 files changed

+408
-0
lines changed

9 files changed

+408
-0
lines changed

docs/modules/clickhouse.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# ClickHouse Module
2+
3+
[ClickHouse](https://clickhouse.com/) is a column-oriented database management system for online analytical processing (OLAP) that allows users to generate analytical reports using SQL queries in real-time.
4+
5+
## Install
6+
7+
```bash
8+
npm install @testcontainers/clickhouse --save-dev
9+
```
10+
11+
## Examples
12+
13+
<!--codeinclude-->
14+
[Connect and execute query:](../../packages/modules/clickhouse/src/clickhouse-container.test.ts) inside_block:connectWithOptions
15+
<!--/codeinclude-->
16+
17+
<!--codeinclude-->
18+
[Connect using URL and execute query:](../../packages/modules/clickhouse/src/clickhouse-container.test.ts) inside_block:connectWithUrl
19+
<!--/codeinclude-->
20+
21+
<!--codeinclude-->
22+
[Connect with username and password and execute query:](../../packages/modules/clickhouse/src/clickhouse-container.test.ts) inside_block:connectWithUsernameAndPassword
23+
<!--/codeinclude-->
24+
25+
<!--codeinclude-->
26+
[Set database:](../../packages/modules/clickhouse/src/clickhouse-container.test.ts) inside_block:setDatabase
27+
<!--/codeinclude-->
28+
29+
<!--codeinclude-->
30+
[Set username:](../../packages/modules/clickhouse/src/clickhouse-container.test.ts) inside_block:setUsername
31+
<!--/codeinclude-->
32+
33+
### Connection Methods
34+
35+
The module provides several methods to connect to the ClickHouse container:
36+
37+
1. `getClientOptions()` - Returns a configuration object suitable for `@clickhouse/client`:
38+
```typescript
39+
{
40+
url: string; // HTTP URL with host and port
41+
username: string; // Container username
42+
password: string; // Container password
43+
database: string; // Container database
44+
}
45+
```
46+
2. `getConnectionUrl()` - Returns a complete HTTP URL including credentials and database:
47+
```
48+
http://[username[:password]@][host[:port]]/database
49+
```
50+
3. `getHttpUrl()` - Returns the base HTTP URL without credentials:
51+
```
52+
http://[host[:port]]
53+
```
54+
55+
These methods can be used with the `@clickhouse/client` package or any other ClickHouse client.

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ nav:
5151
- Azurite: modules/azurite.md
5252
- Cassandra: modules/cassandra.md
5353
- ChromaDB: modules/chromadb.md
54+
- ClickHouse: modules/clickhouse.md
5455
- CosmosDB: modules/cosmosdb.md
5556
- Couchbase: modules/couchbase.md
5657
- CockroachDB: modules/cockroachdb.md

package-lock.json

Lines changed: 35 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "@testcontainers/clickhouse",
3+
"version": "10.24.1",
4+
"license": "MIT",
5+
"keywords": [
6+
"clickhouse",
7+
"testing",
8+
"docker",
9+
"testcontainers"
10+
],
11+
"description": "ClickHouse module for Testcontainers",
12+
"homepage": "https://github.com/testcontainers/testcontainers-node#readme",
13+
"repository": {
14+
"type": "git",
15+
"url": "git+https://github.com/testcontainers/testcontainers-node.git"
16+
},
17+
"bugs": {
18+
"url": "https://github.com/testcontainers/testcontainers-node/issues"
19+
},
20+
"main": "build/index.js",
21+
"files": [
22+
"build"
23+
],
24+
"publishConfig": {
25+
"access": "public"
26+
},
27+
"scripts": {
28+
"prepack": "shx cp ../../../README.md . && shx cp ../../../LICENSE .",
29+
"build": "tsc --project tsconfig.build.json"
30+
},
31+
"devDependencies": {
32+
"@clickhouse/client": "^1.11.0"
33+
},
34+
"dependencies": {
35+
"testcontainers": "^10.24.1"
36+
}
37+
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import { createClient } from "@clickhouse/client";
2+
import { ClickHouseContainer } from "./clickhouse-container";
3+
4+
interface ClickHouseQueryResponse<T> {
5+
data: T[];
6+
}
7+
8+
describe("ClickHouseContainer", { timeout: 180_000 }, () => {
9+
// connectWithOptions {
10+
it("should connect using the client options object", async () => {
11+
const container = await new ClickHouseContainer().start();
12+
const client = createClient(container.getClientOptions());
13+
14+
const result = await client.query({
15+
query: "SELECT 1 AS value",
16+
format: "JSON",
17+
});
18+
const data = (await result.json()) as ClickHouseQueryResponse<{ value: number }>;
19+
expect(data?.data?.[0]?.value).toBe(1);
20+
21+
await client.close();
22+
await container.stop();
23+
});
24+
// }
25+
26+
// connectWithUrl {
27+
it("should connect using the URL", async () => {
28+
const container = await new ClickHouseContainer().start();
29+
const client = createClient({
30+
url: container.getConnectionUrl(),
31+
});
32+
33+
const result = await client.query({
34+
query: "SELECT 1 AS value",
35+
format: "JSON",
36+
});
37+
38+
const data = (await result.json()) as ClickHouseQueryResponse<{ value: number }>;
39+
expect(data?.data?.[0]?.value).toBe(1);
40+
41+
await client.close();
42+
await container.stop();
43+
});
44+
// }
45+
46+
// connectWithUsernameAndPassword {
47+
it("should connect using the username and password", async () => {
48+
const container = await new ClickHouseContainer()
49+
.withUsername("customUsername")
50+
.withPassword("customPassword")
51+
.start();
52+
53+
const client = createClient({
54+
url: container.getHttpUrl(),
55+
username: container.getUsername(),
56+
password: container.getPassword(),
57+
});
58+
59+
const result = await client.query({
60+
query: "SELECT 1 AS value",
61+
format: "JSON",
62+
});
63+
64+
const data = (await result.json()) as ClickHouseQueryResponse<{ value: number }>;
65+
expect(data?.data?.[0]?.value).toBe(1);
66+
67+
await client.close();
68+
await container.stop();
69+
});
70+
// }
71+
72+
// setDatabase {
73+
it("should set database", async () => {
74+
const customDatabase = "customDatabase";
75+
const container = await new ClickHouseContainer().withDatabase(customDatabase).start();
76+
77+
const client = createClient(container.getClientOptions());
78+
79+
const result = await client.query({
80+
query: "SELECT currentDatabase() AS current_database",
81+
format: "JSON",
82+
});
83+
84+
const data = (await result.json()) as ClickHouseQueryResponse<{ current_database: string }>;
85+
expect(data?.data?.[0]?.current_database).toBe(customDatabase);
86+
87+
await client.close();
88+
await container.stop();
89+
});
90+
// }
91+
92+
// setUsername {
93+
it("should set username", async () => {
94+
const customUsername = "customUsername";
95+
const container = await new ClickHouseContainer().withUsername(customUsername).start();
96+
97+
const client = createClient(container.getClientOptions());
98+
99+
const result = await client.query({
100+
query: "SELECT currentUser() AS current_user",
101+
format: "JSON",
102+
});
103+
104+
const data = (await result.json()) as ClickHouseQueryResponse<{ current_user: string }>;
105+
expect(data?.data?.[0]?.current_user).toBe(customUsername);
106+
107+
await client.close();
108+
await container.stop();
109+
});
110+
// }
111+
112+
it("should work with restarted container", async () => {
113+
const container = await new ClickHouseContainer().start();
114+
await container.restart();
115+
116+
const client = createClient(container.getClientOptions());
117+
118+
const result = await client.query({
119+
query: "SELECT 1 AS value",
120+
format: "JSON",
121+
});
122+
123+
const data = (await result.json()) as ClickHouseQueryResponse<{ value: number }>;
124+
expect(data?.data?.[0]?.value).toBe(1);
125+
126+
await client.close();
127+
await container.stop();
128+
});
129+
});

0 commit comments

Comments
 (0)