clickhouse_kit/client.rs
1//! The bring-your-own-client seam. `clickhouse-kit` never depends on a concrete
2//! ClickHouse driver — the I/O layer (migration runner, drift gate) is written
3//! against the small [`ChExecutor`] trait, and the caller implements it over
4//! whatever client they already have (the `clickhouse` crate, an HTTP shim, a
5//! test double). This keeps the crate driver-agnostic and dependency-light.
6
7use std::future::Future;
8
9/// Errors surfaced by the I/O layer — either the backing client failed, or we
10/// hit a local filesystem error while reading migration files.
11#[derive(Debug, thiserror::Error)]
12pub enum ChError {
13 /// The underlying ClickHouse client returned an error. The caller's
14 /// [`ChExecutor`] implementation maps its driver error into this string.
15 #[error("clickhouse backend error: {0}")]
16 Backend(String),
17 /// A local filesystem error (e.g. reading the migrations directory).
18 #[error("io error: {0}")]
19 Io(#[from] std::io::Error),
20}
21
22/// A single live column as introspected from `system.columns` — name + the
23/// ClickHouse type string. The canonical definition lives in [`crate::evolve`];
24/// it's re-exported here so the I/O layer and the drift/evolve modules all share
25/// exactly one `LiveColumn` type.
26pub use crate::evolve::LiveColumn;
27
28/// The minimal async execution surface the I/O layer needs from a ClickHouse
29/// client. Implement it over your driver of choice.
30///
31/// Methods return `impl Future + Send` rather than using `async fn` directly so
32/// the futures are guaranteed `Send` (spawn-friendly) regardless of toolchain
33/// object-safety quirks; an impl may still write `async fn`. (The explicit
34/// `+ Send` is the whole point, so `manual_async_fn` is intentionally allowed.)
35#[allow(clippy::manual_async_fn)]
36pub trait ChExecutor {
37 /// Run a single statement that returns no rows (DDL, INSERT, …).
38 fn command(&self, sql: &str) -> impl Future<Output = Result<(), ChError>> + Send;
39
40 /// Run a query whose result is a single `String` column, returning one entry
41 /// per row (used for applied-migration filenames).
42 fn fetch_strings(&self, sql: &str)
43 -> impl Future<Output = Result<Vec<String>, ChError>> + Send;
44
45 /// Introspect the live columns (name + type) of `table` from
46 /// `system.columns`, in declaration order.
47 fn fetch_columns(
48 &self,
49 table: &str,
50 ) -> impl Future<Output = Result<Vec<LiveColumn>, ChError>> + Send;
51}