# Ecto ClickHouse Adapter

[![Hex Package](](
[![Hex Docs](](

Uses [Ch]( as driver.

## Installation

defp deps do
    {:ecto_ch, "~> 0.1.0"}

## Usage

In your `config/config.exs`

config :my_app, ecto_repos: [MyApp.Repo]
config :my_app, MyApp.Repo, url: "http://username:password@localhost:8123/database"

In your application code

defmodule MyApp.Repo do
  use Ecto.Repo,
    otp_app: :my_app,
    adapter: Ecto.Adapters.ClickHouse

Optionally you can also set the default table engine to use in migrations

config :ecto_ch, default_table_engine: "TinyLog"

#### Ecto schemas

For automatic RowBinary encoding please use the custom `Ch` Ecto type:

defmodule MyApp.Example do
  use Ecto.Schema

  @primary_key false
  schema "example" do
    field :number, Ch, type: "UInt32"
    field :name, Ch, type: "String"
    field :maybe_name, Ch, type: "Nullable(String)"
    field :country_code, Ch, type: "FixedString(2)"
    field :price, Ch, type: "Decimal32(2)"
    field :map, Ch, type: "Map(String, UInt64)"
    field :ipv4, Ch, type: "IPv4"
    field :ipv4s, {:array, Ch}, type: "IPv4"
    field :enum, Ch, type: "Enum8('hello' = 1, 'world' = 2)"
    # etc.

MyApp.Repo.insert_all(MyApp.Example, rows)

Some Ecto types like `:string`, `:date`, and `Ecto.UUID` would also work. Others like `:decimal`, `:integer` are ambiguous and should not be used.

[``]( mix task can be used to generate a schema from an existing ClickHouse table.

Usage: `mix <database>.<table>`

Example: `mix system.numbers`

#### Schemaless inserts

For schemaless inserts `:types` option with a mapping of `field->type` needs to be provided:

types = [
  number: "UInt64",
  # or `number: :u64`
  # or `number: Ch.Types.u64()`
  # etc.

MyApp.Repo.insert_all("example", rows, types: types)

#### Settings

`:settings` option can be used to enable [asynchronous inserts,]( lightweght [deletes,]( and [more:](

MyApp.Repo.insert_all(MyApp.Example, rows, settings: [async_insert: 1])
MyApp.Repo.delete_all("example", settings: [allow_experimental_lightweight_delete: 1])

## Caveats

#### [ARRAY JOIN](

For now `:inner_lateral` and `:left_lateral` are used for `ARRAY` and `LEFT ARRAY` joins:

|> join(:inner_lateral, [a], r in "arr")
|> select([a, r], {a.s, r.arr})

is equivalent to

SELECT a0."s", a1."arr"
FROM "arrays_test" AS a0
ARRAY JOIN "arr" AS a1

#### NULL

`DEFAULT` expressions on columns are ignored when inserting RowBinary.

[See Ch for more details and an example.](

## Benchmarks

[See Ch for benchmarks.](