defmodule Ecto.Adapters.Firebird do
@moduledoc """
Adapter module for Firebird.
It uses `Firebirdex` for communicating to the database.
## Options
### Connection options
* `:hostname` - Server hostname
* `:port` - Server port (default: 3305)
* `:username` - Username
* `:password` - User password (or use FIREBIRD_PASSWORD environment)
* `:database` - the database to connect to
* `:pool` - The connection pool module, defaults to `DBConnection.ConnectionPool`
We also recommend developers to consult the `Firebirdex.start_link/1` documentation.
"""
use Ecto.Adapters.SQL, driver: :firebirdex
@behaviour Ecto.Adapter.Storage
alias Ecto.Adapters.Firebird.Codec
## Storage API
@impl Ecto.Adapter.Storage
def storage_down(opts) do
# TODO:
:ok
end
@impl Ecto.Adapter.Storage
def storage_status(options) do
db_path = Keyword.fetch!(options, :database)
if File.exists?(db_path) do
:up
else
:down
end
end
@impl true
def storage_up(opts) do
Keyword.fetch!(opts, :database) ||
raise ":database is nil in repository configuration"
opts =
opts
|> Keyword.put(:createdb, true)
{:ok, state} = Firebirdex.Connection.connect(opts)
:ok = Firebirdex.Connection.disconnect(:normal, state)
end
@impl Ecto.Adapter.Migration
def supports_ddl_transaction? do
true
end
@impl Ecto.Adapter.Migration
def lock_for_migrations(_meta, _opts, fun) do
fun.()
end
@impl Ecto.Adapter.Schema
def autogenerate(:id), do: nil
def autogenerate(:embed_id) do
Ecto.UUID.generate()
end
def autogenerate(:binary_id) do
Ecto.UUID.generate()
end
##
## Loaders
##
# @default_datetime_type :iso8601
@impl Ecto.Adapter
def loaders(:boolean, type) do
[&Codec.bool_decode/1, type]
end
# @impl Ecto.Adapter
# def loaders(:naive_datetime_usec, type) do
# [&Codec.naive_datetime_decode/1, type]
# end
#
# @impl Ecto.Adapter
# def loaders(:time, type) do
# [&Codec.time_decode/1, type]
# end
#
# @impl Ecto.Adapter
# def loaders(:utc_datetime_usec, type) do
# [&Codec.utc_datetime_decode/1, type]
# end
#
# @impl Ecto.Adapter
# def loaders(:utc_datetime, type) do
# [&Codec.utc_datetime_decode/1, type]
# end
#
# @impl Ecto.Adapter
# def loaders(:naive_datetime, type) do
# [&Codec.naive_datetime_decode/1, type]
# end
#
# @impl Ecto.Adapter
# def loaders(:date, type) do
# [&Codec.date_decode/1, type]
# end
#
@impl Ecto.Adapter
def loaders({:map, _}, type) do
[&Codec.json_decode/1, &Ecto.Type.embedded_load(type, &1, :json)]
end
@impl Ecto.Adapter
def loaders({:array, _}, type) do
[&Codec.json_decode/1, type]
end
@impl Ecto.Adapter
def loaders(:map, type) do
[&Codec.json_decode/1, type]
end
@impl Ecto.Adapter
def loaders(:float, type) do
[&Codec.float_decode/1, type]
end
@impl Ecto.Adapter
def loaders(:decimal, type) do
[&Codec.decimal_decode/1, type]
end
@impl Ecto.Adapter
def loaders(:binary_id, type) do
[type]
end
@impl Ecto.Adapter
def loaders(:uuid, type) do
[type]
end
# when we have an e.g., max(created_date) function
# Ecto does not truly know the return type, hence :maybe
# see Ecto.Query.Planner.collect_fields
# @impl Ecto.Adapter
# def loaders({:maybe, :naive_datetime}, type) do
# [&Codec.naive_datetime_decode/1, type]
# end
@impl Ecto.Adapter
def loaders(_, type) do
[type]
end
##
## Dumpers
##
@impl Ecto.Adapter
def dumpers(:binary, type) do
[type, &Codec.blob_encode/1]
end
@impl Ecto.Adapter
def dumpers(:boolean, type) do
[type, &Codec.bool_encode/1]
end
@impl Ecto.Adapter
def dumpers(:decimal, type) do
[type, &Codec.decimal_encode/1]
end
@impl Ecto.Adapter
def dumpers(:binary_id, type) do
[type, &Codec.uuid_encode/1]
end
@impl Ecto.Adapter
def dumpers(:uuid, type) do
[type, &Codec.uuid_encode/1]
end
# @impl Ecto.Adapter
# def dumpers(:time, type) do
# [type, &Codec.time_encode/1]
# end
#
# @impl Ecto.Adapter
# def dumpers(:utc_datetime, type) do
# dt_type = Application.get_env(:ecto_sqlite3, :datetime_type, @default_datetime_type)
# [type, &Codec.utc_datetime_encode(&1, dt_type)]
# end
#
# @impl Ecto.Adapter
# def dumpers(:utc_datetime_usec, type) do
# dt_type = Application.get_env(:ecto_sqlite3, :datetime_type, @default_datetime_type)
# [type, &Codec.utc_datetime_encode(&1, dt_type)]
# end
#
# @impl Ecto.Adapter
# def dumpers(:naive_datetime, type) do
# dt_type = Application.get_env(:ecto_sqlite3, :datetime_type, @default_datetime_type)
# [type, &Codec.naive_datetime_encode(&1, dt_type)]
# end
#
# @impl Ecto.Adapter
# def dumpers(:naive_datetime_usec, type) do
# dt_type = Application.get_env(:ecto_sqlite3, :datetime_type, @default_datetime_type)
# [type, &Codec.naive_datetime_encode(&1, dt_type)]
# end
@impl Ecto.Adapter
def dumpers({:array, _}, type) do
[type, &Codec.json_encode/1]
end
@impl Ecto.Adapter
def dumpers({:map, _}, type) do
[&Ecto.Type.embedded_dump(type, &1, :json), &Codec.json_encode/1]
end
@impl Ecto.Adapter
def dumpers(:map, type) do
[type, &Codec.json_encode/1]
end
@impl Ecto.Adapter
def dumpers(_, type) do
[type]
end
end