Ecto.Adapters.ClickHouse (clickhouse_adapter_ecto v0.1.0)

Copy Markdown

A minimal Ecto.Adapters.SQL-based adapter for ClickHouse, backed by ChDriver (a native-protocol DBConnection driver).

This module wires Ecto.Adapters.SQL (which provides Ecto.Adapter, Ecto.Adapter.Queryable, Ecto.Adapter.Schema, and Ecto.Adapter.Transaction for free, delegating SQL generation to Ecto.Adapters.ClickHouse.Connection) up to ChDriver.

Scope of this phase

This adapter currently targets basic SELECT/INSERT round-trips through a real Ecto.Repo -- see Ecto.Adapters.ClickHouse.Connection's moduledoc for exactly which query shapes are supported.

Storage (mix ecto.create / mix ecto.drop)

Ecto.Adapter.Storage is implemented: storage_up/1 and storage_down/1 issue a plain CREATE DATABASE/DROP DATABASE over a short-lived maintenance connection (see run_storage_query/2), and storage_status/1 checks system.databases. There is no ClickHouse equivalent of "does this role have CREATEDB" to worry about, and no encoding/collation options are supported (ClickHouse databases don't have either).

Migrations (mix ecto.migrate)

Ecto.Adapter.Migration is implemented well enough for straightforward migrations to run: supports_ddl_transaction?/0 returns false (ClickHouse has no transactional DDL), and lock_for_migrations/3 is a deliberate no-op that just calls the given function directly -- see its doc below for why. Ecto.Adapters.ClickHouse.Connection's execute_ddl/1 turns create table(...)/drop table(...) into CREATE TABLE/DROP TABLE (see that module's ## DDL section for exactly what's supported and how the ENGINE/ORDER BY clause is chosen), which is what lets Ecto.Migrator create and populate schema_migrations automatically.

mix ecto.rollback / Ecto.Migrator.run(repo, path, :down, ...) is supported for the common case: a change/0 migration doing create table(...) auto-reverses to drop table(...) cleanly (both are synchronous, metadata-only DDL), and the schema_migrations bookkeeping row removal that Ecto.Migration.SchemaMigration's down/4 issues via Repo.delete_all/2 is handled by Ecto.Adapters.ClickHouse.Connection's delete_all/1, which translates it into an ALTER TABLE ... DELETE WHERE ... SETTINGS mutations_sync = 1 mutation that blocks until the row is actually gone, so the migrator's post-delete state is correct with no polling. See Connection's moduledoc for exactly how narrowly that delete_all support is scoped (single table, no joins/LIMIT/OFFSET).

Not supported: :alter (existing migrations that add/remove/modify columns), indexes, and constraints -- see Ecto.Adapters.ClickHouse.Connection's ## DDL moduledoc section for the full breakdown of which DDL operations are safe to auto-reverse via change/0 (create/drop table; add/remove column, once :alter support lands) versus which are genuinely unsafe and must be written as explicit up/0 + down/0 (column type changes via MODIFY COLUMN, ORDER BY/ partition key changes, and any UPDATE/DELETE-shaped data mutation). execute_ddl/1 raises a specific, actionable error if asked to auto-generate DDL for an unsafe :modify column-type change.