{"id":17570564,"url":"https://github.com/plausible/ecto_ch","last_synced_at":"2025-12-11T23:42:51.825Z","repository":{"id":64055840,"uuid":"572972102","full_name":"plausible/ecto_ch","owner":"plausible","description":"ClickHouse adapter for Ecto","archived":false,"fork":false,"pushed_at":"2025-03-20T18:36:26.000Z","size":435,"stargazers_count":94,"open_issues_count":11,"forks_count":13,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-05-01T04:28:26.383Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/plausible.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-12-01T12:32:49.000Z","updated_at":"2025-04-17T02:07:10.000Z","dependencies_parsed_at":"2023-12-02T17:24:56.386Z","dependency_job_id":"370c7e99-028a-4ae5-abb4-c653c519da51","html_url":"https://github.com/plausible/ecto_ch","commit_stats":{"total_commits":268,"total_committers":12,"mean_commits":"22.333333333333332","dds":0.4776119402985075,"last_synced_commit":"807bcb6103bd82df5658f1707d8d0bdbc5f750d4"},"previous_names":["plausible/chto"],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plausible%2Fecto_ch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plausible%2Fecto_ch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plausible%2Fecto_ch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plausible%2Fecto_ch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/plausible","download_url":"https://codeload.github.com/plausible/ecto_ch/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254501548,"owners_count":22081526,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-21T18:01:14.806Z","updated_at":"2025-12-11T23:42:51.819Z","avatar_url":"https://github.com/plausible.png","language":"Elixir","funding_links":[],"categories":["Elixir","Language bindings"],"sub_categories":["Elixir"],"readme":"# Ecto ClickHouse Adapter\n\n[![Documentation badge](https://img.shields.io/badge/Documentation-ff69b4)](https://hexdocs.pm/ecto_ch)\n[![Hex.pm badge](https://img.shields.io/badge/Package%20on%20hex.pm-informational)](https://hex.pm/packages/ecto_ch)\n\nUses [Ch](https://github.com/plausible/ch) as driver.\n\n## Installation\n\n```elixir\ndefp deps do\n  [\n    {:ecto_ch, \"~\u003e 0.8.0\"}\n  ]\nend\n```\n\n## Usage\n\nIn your `config/config.exs`\n\n```elixir\nconfig :my_app, ecto_repos: [MyApp.Repo]\nconfig :my_app, MyApp.Repo, url: \"http://username:password@localhost:8123/database\"\n```\n\nIn your application code\n\n```elixir\ndefmodule MyApp.Repo do\n  use Ecto.Repo,\n    otp_app: :my_app,\n    adapter: Ecto.Adapters.ClickHouse\nend\n```\n\nOptionally you can also set the default table engine and options to use in migrations\n\n```elixir\nconfig :ecto_ch,\n  default_table_engine: \"TinyLog\",\n  default_table_options: [cluster: \"little-giant\", order_by: \"tuple()\"]\n```\n\n#### Ecto schemas\n\nFor automatic RowBinary encoding please use the custom `Ch` Ecto type:\n\n```elixir\ndefmodule MyApp.Example do\n  use Ecto.Schema\n\n  @primary_key false\n  schema \"example\" do\n    field :number, Ch, type: \"UInt32\"\n    field :name, Ch, type: \"String\"\n    field :maybe_name, Ch, type: \"Nullable(String)\"\n    field :country_code, Ch, type: \"FixedString(2)\"\n    field :price, Ch, type: \"Decimal32(2)\"\n    field :map, Ch, type: \"Map(String, UInt64)\"\n    field :ipv4, Ch, type: \"IPv4\"\n    field :ipv4s, {:array, Ch}, type: \"IPv4\"\n    field :enum, Ch, type: \"Enum8('hello' = 1, 'world' = 2)\"\n    # etc.\n  end\nend\n\nMyApp.Repo.insert_all(MyApp.Example, rows)\n```\n\nSome Ecto types like `:string`, `:date`, and `Ecto.UUID` would also work. Others like `:decimal`, `:integer` are ambiguous and should not be used.\n\n[`ecto.ch.schema`](https://hexdocs.pm/ecto_ch/Mix.Tasks.Ecto.Ch.Schema.html) mix task can be used to generate a schema from an existing ClickHouse table.\n\n#### Schemaless inserts\n\nFor schemaless inserts `:types` option with a mapping of `field-\u003etype` needs to be provided:\n\n```elixir\ntypes = [\n  number: \"UInt32\",\n  # or `number: :u32`\n  # or `number: Ch.Types.u32()`\n  # etc.\n]\n\nMyApp.Repo.insert_all(\"example\", rows, types: types)\n```\n\n#### Settings\n\n`:settings` option can be used to enable [asynchronous inserts,](https://clickhouse.com/docs/en/optimize/asynchronous-inserts) lightweight [deletes,](https://clickhouse.com/docs/en/guides/developer/lightweght-delete) global [FINAL](https://clickhouse.com/docs/en/operations/settings/settings#final) modifier, and [more:](https://clickhouse.com/docs/en/operations/settings/settings)\n\n```elixir\nMyApp.Repo.insert_all(MyApp.Example, rows, settings: [async_insert: 1])\nMyApp.Repo.delete_all(\"example\", settings: [allow_experimental_lightweight_delete: 1])\nMyApp.Repo.all(MyApp.AggregatedExample, settings: [final: 1])\n```\n\n#### Migrations\n\nClickHouse-specific options can be passed into `table.options` and `index.options`\n\n```elixir\ntable_options = [cluster: \"my-cluster\"]\nengine_options = [order_by: \"tuple()\"]\noptions = table_options ++ engine_options\n\ncreate table(:posts, primary_key: false, engine: \"ReplicatedMergeTree\", options: options) do\n  add :message, :string\n  add :user_id, :UInt64\nend\n```\n\nis equivalent to\n\n```sql\nCREATE TABLE `posts` ON CLUSTER `my-cluster` (\n  `message` String,\n  `user_id` UInt64\n) ENGINE ReplicatedMergeTree ORDER BY tuple()\n```\n\n## Caveats\n\n#### [ALTER TABLE ... UPDATE](https://clickhouse.com/docs/en/sql-reference/statements/alter/update)\n\nClickHouse doesn't support `UPDATE` statements as of now, so `Repo.update/2` and `Repo.update_all/3` raise when called. But `Repo.alter_update_all/3` -- which executes `ALTER TABLE ... UPDATE` -- can be used instead.\n\nNote that `ALTER TABLE ... UPDATE` is considered an admin operation and comes with a performance cost. Please read https://clickhouse.com/blog/handling-updates-and-deletes-in-clickhouse for more information.\n\nFor examples, please see [clickhouse_alter_update_test.exs.](./test/ecto/integration/clickhouse_alter_update_test.exs)\n\n#### [ARRAY JOIN](https://clickhouse.com/docs/en/sql-reference/statements/select/array-join)\n\nFor `ARRAY JOIN` examples and other ClickHouse-specific JOIN types please see [clickhouse_joins_test.exs.](./test/ecto/integration/clickhouse_joins_test.exs)\n\n#### NULL\n\n`DEFAULT` expressions on columns are ignored when inserting RowBinary.\n\n[See Ch for more details and an example.](https://github.com/plausible/ch#null-in-rowbinary)\n\n## Benchmarks\n\n[See Ch for benchmarks.](https://github.com/plausible/ch#benchmarks)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplausible%2Fecto_ch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fplausible%2Fecto_ch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplausible%2Fecto_ch/lists"}