Current section

Files

Jump to
ecto_druid lib ecto adapters druid.ex
Raw

lib/ecto/adapters/druid.ex

defmodule Ecto.Adapters.Druid do
@moduledoc """
This adapter allows you to use Druid as a database with Ecto.
## Installation
To use the Druid adapter, you need to add it to your `mix.exs` file:
defp deps do
[
{:ecto_adapters_druid, "~> 0.1.0"}
]
end
## Usage
You can now use Ecto with Druid by defining a repository that uses the Druid adapter:
defmodule MyApp.Repo do
use Ecto.Repo,
otp_app: :my_app,
adapter: Ecto.Adapters.Druid
end
## Configuration
Then you need to configure your repository to use the Druid adapter:
config :my_app, MyApp.Repo,
host: "localhost",
port: 8082
finch_opts: [pools: %{default: [size: 10]}]
The following options are supported:
* `:host` - The host of the Druid server.
* `:port` - The port of the Druid server.
* `:scheme` - The scheme of the Druid server (http or https).
* `:finch_opts` - [Options](https://hexdocs.pm/finch/Finch.html#start_link/1-options) to pass to Finch when making requests to Druid.
"""
@behaviour Ecto.Adapter
@behaviour Ecto.Adapter.Queryable
@impl Ecto.Adapter
defmacro __before_compile__(_env) do
quote do
def to_sql(query) do
Ecto.Adapters.SQL.to_sql(:all, get_dynamic_repo(), query)
end
def native_query(query, opts \\ []) do
Ecto.Adapters.Druid.native_query(get_dynamic_repo(), query, opts)
end
def insert_all(schema_or_source, entries, opts \\ []) do
repo = get_dynamic_repo()
Ecto.Repo.Schema.insert_all(
__MODULE__,
repo,
schema_or_source,
entries,
Ecto.Repo.Supervisor.tuplet(repo, prepare_opts(:insert_all, opts))
)
end
end
end
@impl Ecto.Adapter
def ensure_all_started(config, _type) do
{:ok, [config]}
end
@impl Ecto.Adapter
def init(config) do
finch_opts =
Keyword.get(config, :finch_opts, [])
|> Keyword.put(:name, __MODULE__.Finch)
{:ok, Supervisor.child_spec({Finch, finch_opts}, []), %{config: config}}
end
@impl Ecto.Adapter
def checkout(_meta, _opts, fun) do
fun.()
end
@impl Ecto.Adapter
def checked_out?(_meta), do: false
@impl Ecto.Adapter
def dumpers(primitive_type, ecto_type) do
__MODULE__.Types.dumpers(primitive_type, ecto_type)
end
@impl Ecto.Adapter
def loaders(primitive_type, ecto_type) do
__MODULE__.Types.loaders(primitive_type, ecto_type)
end
@impl Ecto.Adapter.Queryable
def prepare(kind, query) do
case kind do
:all ->
sql = IO.iodata_to_binary(__MODULE__.Query.all(query))
{:cache, {System.unique_integer([:positive]), sql}}
_ ->
raise RuntimeError, "Unsupported query kind: #{inspect(kind)}"
end
end
@impl Ecto.Adapter.Queryable
def execute(repo, _query_meta, query, params, opts) do
{_, _, {_, sql}} = query
params = Enum.map(params, &__MODULE__.Types.to_db/1)
request_opts = repo.config |> Keyword.merge(opts) |> Keyword.put(:finch, __MODULE__.Finch)
values =
Druid.Client.SQL.query(sql, params, opts)
|> Druid.Client.request!(request_opts)
{Enum.count(values), values}
end
@doc false
def insert_all(
adapter_meta,
schema_meta,
header,
rows,
on_conflict,
returning,
placeholders,
opts
) do
__MODULE__.Ingest.insert_all(
adapter_meta,
schema_meta,
header,
rows,
on_conflict,
returning,
placeholders,
opts
)
end
@impl Ecto.Adapter.Queryable
def stream(_adapter_meta, _query_meta, _query_cache, _params, _opts) do
[]
end
@doc false
def native_query(repo, query, opts) do
request_opts = repo.config |> Keyword.merge(opts) |> Keyword.put(:finch, __MODULE__.Finch)
Druid.Client.Native.query(query)
|> Druid.Client.request!(request_opts)
end
end