-
-
Notifications
You must be signed in to change notification settings - Fork 251
Add ClickHouse module #981
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
cristianrgreco
merged 5 commits into
testcontainers:main
from
Victorlouisdg:feat/clickhouse
Apr 11, 2025
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
23fc5c3
feat: Add ClickHouse module initial implementation
Victorlouisdg 6c7986c
Use "/" path instead of ping + use HTTP wait strategy
cristianrgreco fb21ab6
feat(clickhouse): improve helper methods to align with @clickhouse/cl…
Victorlouisdg 4eefcf1
feat(clickhouse): update docs
Victorlouisdg 4bc1a57
fix(clickhouse): change image version, streamline test cases, and fix…
Victorlouisdg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| # ClickHouse Module | ||
|
|
||
| [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. | ||
|
|
||
| ## Install | ||
|
|
||
| ```bash | ||
| npm install @testcontainers/clickhouse --save-dev | ||
| ``` | ||
|
|
||
| ## Examples | ||
|
|
||
| <!--codeinclude--> | ||
| [Connect and execute query:](../../packages/modules/clickhouse/src/clickhouse-container.test.ts) inside_block:connectWithOptions | ||
| <!--/codeinclude--> | ||
|
|
||
| <!--codeinclude--> | ||
| [Connect using URL and execute query:](../../packages/modules/clickhouse/src/clickhouse-container.test.ts) inside_block:connectWithUrl | ||
| <!--/codeinclude--> | ||
|
|
||
| <!--codeinclude--> | ||
| [Connect with username and password and execute query:](../../packages/modules/clickhouse/src/clickhouse-container.test.ts) inside_block:connectWithUsernameAndPassword | ||
| <!--/codeinclude--> | ||
|
|
||
| <!--codeinclude--> | ||
| [Set database:](../../packages/modules/clickhouse/src/clickhouse-container.test.ts) inside_block:setDatabase | ||
| <!--/codeinclude--> | ||
|
|
||
| <!--codeinclude--> | ||
| [Set username:](../../packages/modules/clickhouse/src/clickhouse-container.test.ts) inside_block:setUsername | ||
| <!--/codeinclude--> | ||
|
|
||
| ### Connection Methods | ||
|
|
||
| The module provides several methods to connect to the ClickHouse container: | ||
|
|
||
| 1. `getClientOptions()` - Returns a configuration object suitable for `@clickhouse/client`: | ||
| ```typescript | ||
| { | ||
| url: string; // HTTP URL with host and port | ||
| username: string; // Container username | ||
| password: string; // Container password | ||
| database: string; // Container database | ||
| } | ||
| ``` | ||
| 2. `getConnectionUrl()` - Returns a complete HTTP URL including credentials and database: | ||
| ``` | ||
| http://[username[:password]@][host[:port]]/database | ||
| ``` | ||
| 3. `getHttpUrl()` - Returns the base HTTP URL without credentials: | ||
| ``` | ||
| http://[host[:port]] | ||
| ``` | ||
|
|
||
| These methods can be used with the `@clickhouse/client` package or any other ClickHouse client. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| { | ||
| "name": "@testcontainers/clickhouse", | ||
| "version": "10.24.1", | ||
| "license": "MIT", | ||
| "keywords": [ | ||
| "clickhouse", | ||
| "testing", | ||
| "docker", | ||
| "testcontainers" | ||
| ], | ||
| "description": "ClickHouse module for Testcontainers", | ||
| "homepage": "https://github.com/testcontainers/testcontainers-node#readme", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git+https://github.com/testcontainers/testcontainers-node.git" | ||
| }, | ||
| "bugs": { | ||
| "url": "https://github.com/testcontainers/testcontainers-node/issues" | ||
| }, | ||
| "main": "build/index.js", | ||
| "files": [ | ||
| "build" | ||
| ], | ||
| "publishConfig": { | ||
| "access": "public" | ||
| }, | ||
| "scripts": { | ||
| "prepack": "shx cp ../../../README.md . && shx cp ../../../LICENSE .", | ||
| "build": "tsc --project tsconfig.build.json" | ||
| }, | ||
| "devDependencies": { | ||
| "@clickhouse/client": "^1.11.0" | ||
| }, | ||
| "dependencies": { | ||
| "testcontainers": "^10.24.1" | ||
| } | ||
| } |
129 changes: 129 additions & 0 deletions
129
packages/modules/clickhouse/src/clickhouse-container.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| import { createClient } from "@clickhouse/client"; | ||
| import { ClickHouseContainer } from "./clickhouse-container"; | ||
|
|
||
| interface ClickHouseQueryResponse<T> { | ||
| data: T[]; | ||
| } | ||
|
|
||
| describe("ClickHouseContainer", { timeout: 180_000 }, () => { | ||
| // connectWithOptions { | ||
| it("should connect using the client options object", async () => { | ||
Victorlouisdg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| const container = await new ClickHouseContainer().start(); | ||
| const client = createClient(container.getClientOptions()); | ||
|
|
||
| const result = await client.query({ | ||
| query: "SELECT 1 AS value", | ||
| format: "JSON", | ||
| }); | ||
| const data = (await result.json()) as ClickHouseQueryResponse<{ value: number }>; | ||
| expect(data?.data?.[0]?.value).toBe(1); | ||
|
|
||
| await client.close(); | ||
| await container.stop(); | ||
| }); | ||
| // } | ||
|
|
||
| // connectWithUrl { | ||
| it("should connect using the URL", async () => { | ||
| const container = await new ClickHouseContainer().start(); | ||
| const client = createClient({ | ||
| url: container.getConnectionUrl(), | ||
| }); | ||
|
|
||
| const result = await client.query({ | ||
| query: "SELECT 1 AS value", | ||
| format: "JSON", | ||
| }); | ||
|
|
||
| const data = (await result.json()) as ClickHouseQueryResponse<{ value: number }>; | ||
| expect(data?.data?.[0]?.value).toBe(1); | ||
|
|
||
| await client.close(); | ||
| await container.stop(); | ||
| }); | ||
| // } | ||
|
|
||
| // connectWithUsernameAndPassword { | ||
| it("should connect using the username and password", async () => { | ||
| const container = await new ClickHouseContainer() | ||
| .withUsername("customUsername") | ||
| .withPassword("customPassword") | ||
| .start(); | ||
|
|
||
| const client = createClient({ | ||
| url: container.getHttpUrl(), | ||
| username: container.getUsername(), | ||
| password: container.getPassword(), | ||
| }); | ||
|
|
||
| const result = await client.query({ | ||
| query: "SELECT 1 AS value", | ||
| format: "JSON", | ||
| }); | ||
|
|
||
| const data = (await result.json()) as ClickHouseQueryResponse<{ value: number }>; | ||
| expect(data?.data?.[0]?.value).toBe(1); | ||
|
|
||
| await client.close(); | ||
| await container.stop(); | ||
| }); | ||
| // } | ||
|
|
||
| // setDatabase { | ||
| it("should set database", async () => { | ||
| const customDatabase = "customDatabase"; | ||
| const container = await new ClickHouseContainer().withDatabase(customDatabase).start(); | ||
|
|
||
| const client = createClient(container.getClientOptions()); | ||
|
|
||
| const result = await client.query({ | ||
| query: "SELECT currentDatabase() AS current_database", | ||
| format: "JSON", | ||
| }); | ||
|
|
||
| const data = (await result.json()) as ClickHouseQueryResponse<{ current_database: string }>; | ||
| expect(data?.data?.[0]?.current_database).toBe(customDatabase); | ||
|
|
||
| await client.close(); | ||
| await container.stop(); | ||
| }); | ||
| // } | ||
|
|
||
| // setUsername { | ||
| it("should set username", async () => { | ||
| const customUsername = "customUsername"; | ||
| const container = await new ClickHouseContainer().withUsername(customUsername).start(); | ||
|
|
||
| const client = createClient(container.getClientOptions()); | ||
|
|
||
| const result = await client.query({ | ||
| query: "SELECT currentUser() AS current_user", | ||
| format: "JSON", | ||
| }); | ||
|
|
||
| const data = (await result.json()) as ClickHouseQueryResponse<{ current_user: string }>; | ||
| expect(data?.data?.[0]?.current_user).toBe(customUsername); | ||
|
|
||
| await client.close(); | ||
| await container.stop(); | ||
| }); | ||
| // } | ||
|
|
||
| it("should work with restarted container", async () => { | ||
| const container = await new ClickHouseContainer().start(); | ||
| await container.restart(); | ||
|
|
||
| const client = createClient(container.getClientOptions()); | ||
|
|
||
| const result = await client.query({ | ||
| query: "SELECT 1 AS value", | ||
| format: "JSON", | ||
| }); | ||
|
|
||
| const data = (await result.json()) as ClickHouseQueryResponse<{ value: number }>; | ||
| expect(data?.data?.[0]?.value).toBe(1); | ||
|
|
||
| await client.close(); | ||
| await container.stop(); | ||
| }); | ||
| }); | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.