Packages
pillar
0.38.0
0.40.0
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.1
0.34.0
0.33.1
0.33.0
0.32.0
0.31.0
0.30.0
0.29.1
0.29.0
0.28.0
0.27.0
0.26.1
0.26.0
0.25.1
0.25.0
0.24.0
0.23.3
0.23.2
0.23.1
0.23.0
0.22.0
0.21.0
0.20.0
0.19.0
0.18.2
0.18.1
0.18.0
0.17.3
0.17.2
0.17.1
0.17.0
0.16.2
0.16.1
0.16.0
0.15.0
0.14.0
0.13.1
0.13.0
0.12.0
0.11.0
0.10.0
0.9.1
0.9.0
0.8.1
0.8.0
0.7.0
0.6.0
0.5.1
0.5.0
0.4.0
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.0
Elixir client for ClickHouse, a fast open-source Online Analytical Processing (OLAP) database management system.
Current section
Files
Jump to
Current section
Files
README.md
# Pillar[](https://github.com/balance-platform/pillar/actions)[](https://hexdocs.pm/pillar)[](https://hex.pm/packages/pillar)[](https://hex.pm/packages/pillar)[](https://hex.pm/packages/pillar)[](https://github.com/balance-platform/pillar/commits/master)Elixir client for [ClickHouse](https://clickhouse.tech/), a fast open-sourceOnline Analytical Processing (OLAP) database management system.# Features - [Direct Usage with connection structure](#direct-usage-with-connection-structure) - [Pool of workers](#pool-of-workers) - [Async insert](#async-insert) - [Buffer for periodical bulk inserts](#buffer-for-periodical-bulk-inserts) - [Migrations](#migrations) - [DateTime Timezones](#timezones) - [Switching between HTTP adapters](#http-adapters)## Usage### Direct Usage with connection structure```elixirconn = Pillar.Connection.new("http://user:password@localhost:8123/database")# Params are passed in brackets {} in SQL query, and map strtucture does fill# query by values.sql = "SELECT count(*) FROM users WHERE lastname = {lastname}"params = %{lastname: "Smith"}{:ok, result} = Pillar.query(conn, sql, params)result#=> [%{"count(*)" => 347}]```### Pool of workersRecommended usage, because of limited connections and supervised workers.```elixirdefmodule ClickhouseMaster do use Pillar, connection_strings: [ "http://user:password@host-master-1:8123/database", "http://user:password@host-master-2:8123/database" ], name: __MODULE__, pool_size: 15endClickhouseMaster.start_link(){:ok, result} = ClickhouseMaster.select(sql, %{param: value})```### Async insert```elixirconnection = Pillar.Connection.new("http://user:password@host-master-1:8123/database")Pillar.async_insert(connection, "INSERT INTO events (user_id, event) SELECT {user_id}, {event}", %{ user_id: user.id, event: "password_changed"}) # => :ok```### Buffer for periodical bulk insertsFor this feature required [Pool of workers](#pool-of-workers).```elixirdefmodule BulkToLogs do use Pillar.BulkInsertBuffer, pool: ClickhouseMaster, table_name: "logs", # interval_between_inserts_in_seconds, by default -> 5 interval_between_inserts_in_seconds: 5, # on_errors is optional on_errors: &__MODULE__.dump_to_file/2 @doc """ dump to file function store failed inserts into file """ def dump_to_file(_result, records) do File.write("bad_inserts/#{DateTime.utc_now()}", inspect(records)) end @doc """ retry insert is dangerous (but it is possible and listed as proof of concept) this function may be used in `on_errors` option """ def retry_insert(_result, records) do __MODULE__.insert(records) endend``````elixir:ok = BulkToLogs.insert(%{value: "online", count: 133, datetime: DateTime.utc_now()}):ok = BulkToLogs.insert(%{value: "online", count: 134, datetime: DateTime.utc_now()}):ok = BulkToLogs.insert(%{value: "online", count: 132, datetime: DateTime.utc_now()})....# All this records will be inserted with 5 second interval.```*on_errors* parameter allows you to catch any error of bulk insert (for example: one of batch is bad or clickhouse was not available )### MigrationsMigrations can be generated with mix task `mix pillar.gen.migration migration_name`.Multi-statement migration Example for this [UseCase](https://github.com/balance-platform/pillar/issues/61)```elixirdefmodule Pillar.Migrations.CreateMultipleTables do def up do # for MultiStatement migration result of this function should be List of Strings (0..4) |> Enum.map(fn i -> "CREATE TABLE IF NOT EXISTS shard_#{i} (field FixedString(10)) ENGINE = Memory" end) endend``````bashmix pillar.gen.migration events_table```But for launching them we have to write own task, like this:```elixirdefmodule Mix.Tasks.MigrateClickhouse do use Mix.Task def run(_args) do connection_string = Application.get_env(:my_project, :clickhouse_url) conn = Pillar.Connection.new(connection_string) Pillar.Migrations.migrate(conn) endend```And launch this via command.```bashmix migrate_clickhouse```### TimezonesIn order to be able to use Timezones add timezones database to your project and configure your app:```elixirconfig :elixir, :time_zone_database, Tzdata.TimeZoneDatabase```Details here https://hexdocs.pm/elixir/1.12/DateTime.html#module-time-zone-database### HTTP AdaptersIf you have problems with default Pillar HTTP Adapter (Mint over Tesla), you can use alternative one, based on :httpc or define your own and pass itthrough config.```config :pillar, Pillar.HttpClient, http_adapter: Pillar.HttpClient.TeslaMintAdapter```Adapter should define one function `post/3` and return 2 possible results (`%Pillar.HttpClient.Response{}`, `%Pillar.HttpClient.TransportError{}`)# ContributionFeel free to make a pull request. All contributions are appreciated!