Skip to content
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

Add r2dbc support for Clickhouse #8434

Merged
merged 6 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/modules/databases/r2dbc.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ So that the URL becomes:

### R2DBC URL examples

#### Using ClickHouse

`r2dbc:tc:clickhouse:///databasename?TC_IMAGE_TAG=21.9.2-alpine`

#### Using MySQL

`r2dbc:tc:mysql:///databasename?TC_IMAGE_TAG=8.0.36`
Expand Down
7 changes: 6 additions & 1 deletion modules/clickhouse/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ dependencies {
api project(':testcontainers')
api project(':jdbc')

compileOnly project(':r2dbc')
compileOnly(group: 'com.clickhouse', name: 'clickhouse-r2dbc', version: '0.7.0', classifier: 'http')

testImplementation project(':jdbc-test')
testRuntimeOnly 'ru.yandex.clickhouse:clickhouse-jdbc:0.3.2'
testRuntimeOnly(group: 'com.clickhouse', name: 'clickhouse-jdbc', version: '0.7.0', classifier: 'http')
testImplementation 'org.assertj:assertj-core:3.26.3'
testImplementation testFixtures(project(':r2dbc'))
testRuntimeOnly(group: 'com.clickhouse', name: 'clickhouse-r2dbc', version: '0.7.0', classifier: 'http')
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,29 @@ public class ClickHouseContainer extends JdbcDatabaseContainer<ClickHouseContain

private static final String NAME = "clickhouse";

private static final DockerImageName CLICKHOUSE_IMAGE_NAME = DockerImageName.parse("clickhouse/clickhouse-server");
static final String CLICKHOUSE_CLICKHOUSE_SERVER = "clickhouse/clickhouse-server";

private static final Integer HTTP_PORT = 8123;
private static final DockerImageName CLICKHOUSE_IMAGE_NAME = DockerImageName.parse(CLICKHOUSE_CLICKHOUSE_SERVER);

private static final Integer NATIVE_PORT = 9000;
static final Integer HTTP_PORT = 8123;

static final Integer NATIVE_PORT = 9000;

private static final String DRIVER_CLASS_NAME = "com.clickhouse.jdbc.ClickHouseDriver";

private static final String JDBC_URL_PREFIX = "jdbc:" + NAME + "://";

private static final String TEST_QUERY = "SELECT 1";

static final String DEFAULT_USER = "default";

static final String DEFAULT_PASSWORD = "";

private String databaseName = "default";

private String username = "default";
private String username = DEFAULT_USER;

private String password = "";
private String password = DEFAULT_PASSWORD;

public ClickHouseContainer(String dockerImageName) {
this(DockerImageName.parse(dockerImageName));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.testcontainers.clickhouse;

import io.r2dbc.spi.ConnectionFactoryOptions;
import org.testcontainers.r2dbc.R2DBCDatabaseContainer;

/**
* ClickHouse R2DBC support
*/
public class ClickHouseR2DBCDatabaseContainer implements R2DBCDatabaseContainer {

private final ClickHouseContainer container;

public ClickHouseR2DBCDatabaseContainer(ClickHouseContainer container) {
this.container = container;
}

public static ConnectionFactoryOptions getOptions(ClickHouseContainer container) {
ConnectionFactoryOptions options = ConnectionFactoryOptions
.builder()
.option(ConnectionFactoryOptions.DRIVER, ClickHouseR2DBCDatabaseContainerProvider.DRIVER)
.build();

return new ClickHouseR2DBCDatabaseContainer(container).configure(options);
}

@Override
public void start() {
this.container.start();
}

@Override
public void stop() {
this.container.stop();
}

@Override
public ConnectionFactoryOptions configure(ConnectionFactoryOptions options) {
return options
.mutate()
.option(ConnectionFactoryOptions.HOST, container.getHost())
.option(ConnectionFactoryOptions.PORT, container.getMappedPort(ClickHouseContainer.HTTP_PORT))
.option(ConnectionFactoryOptions.DATABASE, container.getDatabaseName())
.option(ConnectionFactoryOptions.USER, container.getUsername())
.option(ConnectionFactoryOptions.PASSWORD, container.getPassword())
.option(ConnectionFactoryOptions.PROTOCOL, "http")
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.testcontainers.clickhouse;

import com.clickhouse.r2dbc.connection.ClickHouseConnectionFactoryProvider;
import io.r2dbc.spi.ConnectionFactoryMetadata;
import io.r2dbc.spi.ConnectionFactoryOptions;
import org.testcontainers.r2dbc.R2DBCDatabaseContainer;
import org.testcontainers.r2dbc.R2DBCDatabaseContainerProvider;

import javax.annotation.Nullable;

public class ClickHouseR2DBCDatabaseContainerProvider implements R2DBCDatabaseContainerProvider {

static final String DRIVER = ClickHouseConnectionFactoryProvider.CLICKHOUSE_DRIVER;

@Override
public boolean supports(ConnectionFactoryOptions options) {
return DRIVER.equals(options.getRequiredValue(ConnectionFactoryOptions.DRIVER));
}

@Override
public R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options) {
String image =
ClickHouseContainer.CLICKHOUSE_CLICKHOUSE_SERVER + ":" + options.getRequiredValue(IMAGE_TAG_OPTION);
ClickHouseContainer container = new ClickHouseContainer(image)
.withDatabaseName((String) options.getRequiredValue(ConnectionFactoryOptions.DATABASE));

if (Boolean.TRUE.equals(options.getValue(REUSABLE_OPTION))) {
container.withReuse(true);
}
return new ClickHouseR2DBCDatabaseContainer(container);
}

@Nullable
@Override
public ConnectionFactoryMetadata getMetadata(ConnectionFactoryOptions options) {
ConnectionFactoryOptions.Builder builder = options.mutate();
if (!options.hasOption(ConnectionFactoryOptions.USER)) {
builder.option(ConnectionFactoryOptions.USER, ClickHouseContainer.DEFAULT_USER);
}
if (!options.hasOption(ConnectionFactoryOptions.PASSWORD)) {
builder.option(ConnectionFactoryOptions.PASSWORD, ClickHouseContainer.DEFAULT_PASSWORD);
}
builder.option(ConnectionFactoryOptions.PROTOCOL, "http");
return R2DBCDatabaseContainerProvider.super.getMetadata(builder.build());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.testcontainers.clickhouse.ClickHouseR2DBCDatabaseContainerProvider
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@
import org.testcontainers.utility.DockerImageName;

public interface ClickhouseTestImages {
DockerImageName YANDEX_CLICKHOUSE_IMAGE = DockerImageName.parse("yandex/clickhouse-server:18.10.3");
DockerImageName CLICKHOUSE_IMAGE = DockerImageName.parse("clickhouse/clickhouse-server:21.9.2-alpine");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.testcontainers.clickhouse;

import io.r2dbc.spi.ConnectionFactoryOptions;
import org.testcontainers.r2dbc.AbstractR2DBCDatabaseContainerTest;

public class ClickHouseR2DBCDatabaseContainerTest extends AbstractR2DBCDatabaseContainerTest<ClickHouseContainer> {

@Override
protected ConnectionFactoryOptions getOptions(ClickHouseContainer container) {
return ClickHouseR2DBCDatabaseContainer.getOptions(container);
}

@Override
protected String createR2DBCUrl() {
return "r2dbc:tc:clickhouse:///db?TC_IMAGE_TAG=21.9.2-alpine";
}

@Override
protected ClickHouseContainer createContainer() {
return new ClickHouseContainer("clickhouse/clickhouse-server:21.9.2-alpine");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ public SimpleClickhouseTest(DockerImageName imageName) {
public static Object[][] data() {
return new Object[][] { //
{ ClickhouseTestImages.CLICKHOUSE_IMAGE },
{ ClickhouseTestImages.YANDEX_CLICKHOUSE_IMAGE },
};
}

Expand Down
Loading