clickhouse 0.1.1
clickhouse: ^0.1.1 copied to clipboard
A fast, native Dart driver for ClickHouse over the TCP binary protocol — queries, batch inserts, connection pooling, LZ4 compression, and full column-type support.
clickhouse #
A native Dart driver for ClickHouse over the TCP binary protocol.
clickhouse is a pure-Dart client for querying ClickHouse, streaming
result rows, batch inserting data, pooling connections, using LZ4 compression,
and reading/writing ClickHouse column types without going through HTTP.
Features #
- Native TCP protocol on port
9000 - Queries, exec statements, async inserts, and external tables
- Streaming
RowsAPI with typed getters, scans, maps, and row records - Batch inserts with row-wise, named, map, struct, and columnar append APIs
- Connection pooling with bounded open/idle connections and health checks
- Per-query settings, query parameters, client-side binding, query IDs, quotas, and timeouts
- LZ4/LZ4HC compression with pluggable codecs for additional methods
- Progress, profile info, profile events, server logs, and structured errors
- Broad ClickHouse type support, including arrays, maps, tuples, nullable, low-cardinality, decimals, dates/times, UUID, IPv4/IPv6, enums, JSON, Dynamic, Variant, intervals, and geo types
Installation #
Add the package to your pubspec.yaml:
dependencies:
clickhouse: ^0.1.0
Then run:
dart pub get
Quick Start #
import 'package:clickhouse/clickhouse.dart';
Future<void> main() async {
final conn = await ClickHouseConnection.connect(const ClickHouseOptions(
host: 'localhost',
port: 9000,
database: 'default',
username: 'default',
password: '',
compress: true,
));
await conn.exec('''
CREATE TABLE IF NOT EXISTS dart_demo (
id UInt32,
name String,
score Float64
) ENGINE = MergeTree()
ORDER BY id
''');
final batch = await conn.prepareBatch('INSERT INTO dart_demo');
batch.addRow([1, 'Alice', 9.5]);
batch.addRow([2, 'Bob', 8.2]);
await batch.send();
final rows = await conn.query(
'SELECT id, name, score FROM dart_demo ORDER BY id',
);
try {
while (await rows.next()) {
final id = rows.getByName<int>('id');
final name = rows.getByName<String>('name');
final score = rows.getByName<double>('score');
print('$id $name $score');
}
} finally {
await rows.close();
}
await conn.exec('DROP TABLE IF EXISTS dart_demo');
await conn.close();
}
Connection Options #
Create a connection directly:
final conn = await ClickHouseConnection.connect(const ClickHouseOptions(
host: 'localhost',
port: 9000,
database: 'default',
username: 'default',
password: '',
));
Or parse a DSN:
final options = ClickHouseOptions.fromDsn(
'clickhouse://default@localhost:9000/default?compress=true',
);
final conn = await ClickHouseConnection.connect(options);
TLS is enabled with secure: true or the clickhouses:// DSN scheme.
Querying #
query returns streaming Rows. Always close rows if you do not fully drain the
result.
final rows = await conn.query(
'SELECT number, toString(number) AS label FROM numbers(3)',
);
try {
while (await rows.next()) {
print(rows.toMap());
}
} finally {
await rows.close();
}
Useful row accessors:
final number = rows.getByName<int>('number');
final label = rows.tryGetByName<String>('label');
final pair = rows.row2<int, String>();
final map = rows.toMap();
For one-row and all-row helpers:
final row = await conn.queryRow('SELECT 1 AS value');
final values = await conn.selectAll(
'SELECT number FROM numbers(5)',
(row) => row['number'] as int,
);
Inserts #
Use batches for inserts:
final batch = await conn.prepareBatch('INSERT INTO events');
batch.addRow([1, 'created']);
batch.appendFromMap({'id': 2, 'name': 'updated'});
await batch.send();
Columnar append is also supported:
final batch = await conn.prepareBatch('INSERT INTO events');
batch.columnByName('id').appendSlice([1, 2, 3]);
batch.columnByName('name').appendSlice(['a', 'b', 'c']);
await batch.send();
For fire-and-forget style inserts:
await conn.asyncInsert(
"INSERT INTO events VALUES (1, 'created')",
wait: true,
);
Connection Pooling #
final pool = ClickHousePool(
options: const ClickHouseOptions(host: 'localhost'),
maxOpen: 10,
maxIdle: 5,
);
final rows = await pool.query('SELECT version()');
await rows.close();
await pool.close();
The pool exposes query, exec, asyncInsert, prepareBatch, ping, and
serverVersion.
Settings and Parameters #
Per-query settings:
final rows = await conn.query(
'SELECT number FROM system.numbers LIMIT 10',
settings: {
'max_result_rows': 5,
'result_overflow_mode': 'break',
},
);
await rows.close();
Use ImportantSetting for normal ClickHouse settings and CustomSetting for
settings that should be forwarded without server validation.
Server-side query parameters:
final rows = await conn.query(
'SELECT {name:String} AS name',
parameters: {'name': 'Alice'},
);
await rows.close();
Client-side binding is also available:
final sql = bind(
'SELECT * FROM users WHERE id = ? AND status = @status',
[42, const NamedValue('status', 'active')],
);
External Tables #
final ids = ExternalTable('ids')
..addColumn('id', 'UInt32')
..addRow([1])
..addRow([2]);
final rows = await conn.query(
'SELECT id FROM ids ORDER BY id',
externalTables: [ids],
);
await rows.close();
Observability #
Callbacks are available for server progress, profile info, profile events, and logs:
final rows = await conn.query(
'SELECT sum(number) FROM numbers(1000000)',
onProgress: (progress) => print(progress.readRows),
onLog: (logs) => logs.forEach((log) => print(log.message)),
);
await rows.close();
ClickHouse server exceptions are surfaced as ClickHouseException with a code,
name, message, stack trace, and nested cause when available.
Compression #
Enable LZ4 compression with:
final conn = await ClickHouseConnection.connect(const ClickHouseOptions(
host: 'localhost',
compress: true,
));
Additional compression methods can be plugged in with registerCodec.
Local Testing #
Start ClickHouse:
docker run -d --name clickhouse-dart-test \
-p 9000:9000 -p 8123:8123 \
-e CLICKHOUSE_SKIP_USER_SETUP=1 \
clickhouse/clickhouse-server:latest
Run tests:
dart test
Integration tests read these environment variables:
CLICKHOUSE_HOSTCLICKHOUSE_PORTCLICKHOUSE_USERNAMECLICKHOUSE_PASSWORDCLICKHOUSE_DATABASE
Current Scope #
This package targets the native TCP interface only. HTTP transport is not included.