Skip to main content

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}