>_EXECUTIVE SUMMARY
stryke-clickhouse is an opt-in connector package in the stryke ecosystem — a ClickHouse client. It exposes SELECTs, bulk insert via JSONEachRow, DDL, and schema introspection as the Clickhouse package, against any ClickHouse server over its HTTP interface (default port 8123).
Transport is ureq over rustls — synchronous, pure-Rust, no tokio, no OpenSSL. The cdylib caches a keep-alive connection pool and ships once on demand rather than being linked into stryke core.
>_TRANSPORT
The client uses ClickHouse's HTTP interface (default port 8123) via ureq — synchronous, pure-Rust, rustls-backed, no async runtime, no OpenSSL. SQL is sent in the POST body. SELECTs append default_format=JSON so results return as { meta, data, rows, statistics }; DDL/DML return an empty body on success.
~CONNECTION CACHE
One ureq::Agent (HTTP keep-alive pool) is cached per (base_url, auth, database) tuple in a OnceCell<Mutex<HashMap>> for the life of the stryke process, so repeated queries reuse the connection. The database rides on the query string (?database=) and HTTP Basic carries the credentials (default user default).
~INSERTS
insert serializes an array of row objects into an INSERT INTO <table> FORMAT JSONEachRow body — one JSON object per line — which is ClickHouse's high-throughput ingestion path and avoids per-row round trips.
$FFI CONTRACT + PURE HELPERS
Each #[no_mangle] extern "C" fn clickhouse__* is a JSON-string-in / JSON-string-out wrapper; handlers run inside catch_unwind so a panic becomes an { "error": … } result rather than crossing the C ABI into the host shell. The SQL-escaping and value-formatting helpers and the URL helpers take no connection and are unit-tested in-crate, so they validate in CI with no server present.
| Group | Functions |
|---|---|
| Liveness | version, ping, server_version |
| Query | query, query_rows, query_row, query_value, exec, insert, delete_where, raw |
| Introspection | databases, tables, describe, columns, count, table_exists, database_exists, settings, parts, disk_usage, mutations, processes |
| DDL | create_database, drop_database, create_table, drop_table, truncate_table, rename_table, add_column, drop_column, optimize |
| Pure helpers | escape, escape_like, quote_literal, quote_ident, valid_identifier, format_value, format_in_list, format_array, build_url, parse_url, redact_url |
@SQL MAPPING
Introspection functions resolve against ClickHouse's system.* tables; DDL functions emit idempotent statements (IF [NOT] EXISTS). Identifiers/values interpolated into system.* predicates are run through the in-crate escape_string first.
| Function | Statement |
|---|---|
server_version | SELECT version() |
databases | SELECT name FROM system.databases ORDER BY name |
tables | SELECT name FROM system.tables WHERE database = '…' ORDER BY name |
describe | DESCRIBE TABLE <table> |
table_exists | SELECT count() AS c FROM system.tables WHERE database = '…' AND name = '…' |
database_exists | SELECT count() AS c FROM system.databases WHERE name = '…' |
settings | SELECT name, value, changed, description FROM system.settings ORDER BY name |
columns | SELECT name, type, default_kind, default_expression, data_compressed_bytes, data_uncompressed_bytes, comment FROM system.columns WHERE database = '…' AND table = '…' ORDER BY position |
parts | SELECT … FROM system.parts WHERE database = '…' AND table = '…' AND active ORDER BY name |
disk_usage | SELECT sum(rows), sum(bytes_on_disk), sum(data_compressed_bytes), sum(data_uncompressed_bytes), round(uncompressed/greatest(compressed,1),3) AS ratio FROM system.parts WHERE … AND active |
mutations | SELECT mutation_id, command, create_time, parts_to_do, is_done, latest_fail_reason FROM system.mutations WHERE … ORDER BY create_time DESC |
processes | SELECT query_id, user, query, elapsed, read_rows, read_bytes, memory_usage FROM system.processes ORDER BY elapsed DESC |
create_database | CREATE DATABASE IF NOT EXISTS <name> |
drop_database | DROP DATABASE IF EXISTS <name> |
create_table | CREATE TABLE IF NOT EXISTS <name> (<columns>) ENGINE = <engine, default MergeTree> ORDER BY <order_by, default tuple()> — or a full sql CREATE verbatim |
drop_table | DROP TABLE IF EXISTS <table> |
truncate_table | TRUNCATE TABLE IF EXISTS <table> |
rename_table | RENAME TABLE <from> TO <to> |
add_column | ALTER TABLE <table> ADD COLUMN IF NOT EXISTS <name> <type> [DEFAULT <expr>] |
drop_column | ALTER TABLE <table> DROP COLUMN IF EXISTS <name> |
delete_where | DELETE FROM <table> WHERE <where> (lightweight delete, ClickHouse 22.8+) |
optimize | OPTIMIZE TABLE <table> [FINAL] |
%PURE-HELPER SEMANTICS
The SQL-building helpers take no connection and are exercised by the in-crate unit tests, so they validate in CI with no server present.
| Helper | Rule |
|---|---|
escape | Escapes \ → \\ and ' → \' for a single-quoted literal body. |
quote_literal | '<escape(value)>' — the escaped body wrapped in single quotes. |
quote_ident | Backtick-wraps; embedded ` becomes \`. |
valid_identifier | True iff the value matches [A-Za-z_][A-Za-z0-9_]* (leading underscore allowed). |
escape_like | Backslash-escapes \, %, _ — the body to wrap with surrounding % and quote. |
format_value | string→'…', number→as-is, bool→true/false, null→NULL, array→[…], object→quoted JSON string. |
format_in_list | (v1, v2, …) via format_value; empty input → (NULL) (matches nothing). |
format_array | [v1, v2, …] via format_value. |
build_url | Resolves the base URL the opts connect to (scheme + host + port). |
redact_url | Rewrites userinfo to ***: scheme://***@host…. |
?URL PARSING
parse_url decomposes a URL into the connection fields. A missing scheme defaults to http; a missing port defaults to 8443 when the scheme is https, otherwise 8123; a leading /<db> path names the database.
| Field | Source |
|---|---|
scheme | Before ://; defaults to http. |
host | Authority host (after any user:pass@). |
port | Explicit port, else 8443 (https) / 8123 (http). |
username / password | From the user:pass@ userinfo, when present. |
database | Leading path segment, or null when absent. |
tls | True when scheme is https. |
&RESULT EXTRACTION
query returns the full result object { meta, data, rows, statistics }; query_rows / query_row / query_value peel off the array / first row / first scalar respectively. exec is for statements that return no rows. The extraction logic is unit-tested in-crate against captured JSON payloads, so it validates without a live server.
/DEPENDENCIES
ureq (HTTP, rustls TLS) for transport and serde_json for the FFI payloads and result parsing. Pure-Rust throughout — no tokio, no OpenSSL, no native client library.
#PROJECT METADATA
| Item | Value |
|---|---|
| License | MIT |
| Repository | github.com/MenkeTechnologies/stryke-clickhouse |
| Parent language | strykelang |
| Meta umbrella | MenkeTechnologiesMeta |
| Issues | github.com/MenkeTechnologies/stryke-clickhouse/issues |