DAL v0.3.0 DAL
Global Data Access Layer to replace direct use of Ecto.Repo
and other data services.
The DAL performs two core functions:
- Provides an abstraction for other data repositories
- Provides a set of macros representing all available data types that can be used in services
Data Abstraction
We use a number of different databases at Expert360. Right now all of them are SQL (either MySQL or PostgreSQL) and use Ecto.Repo
but in the future they may also be other databases such as Redis or Elasticsearch.
The DAL uses a discovery mechanism (see DAL.Repo.Discovery
) which uses Elixir protocols to determine what Repo and
attached database to use for a particular query. This way the caller does not need to know where to find the data - they
just need to query the DAL.
The DAL emulates the Ecto.Repo
API so that it can be used in place of an actual Repo in most scenarios (for example in ex_machina
factories).
But be aware that it does not actually adhere to the Ecto.Repo
behaviour as it does not define callbacks such as start_link/1
.
You can use the DAL in exactly the same way that you would a normal ecto repo:
DAL.get(Profiles.Project, 1)
Schema Macros
In the DAL architecture, services need to define their own schema models. However, to have multiple services that define schema fields would be cumbersome and error prone.
Consequently, the DAL defines macros for each data type that it supports (including implementations for DAL.Repo.Discoverable
)
that can be used by services.
For example, to create a project schema model in the Profiles
service:
defmodule Profiles.Project do
use DAL.Types.Project
end
Link to this section Summary
Functions
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.aggregate/4
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.get_by!/2
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
and then constrains the results to the given list of ids before passing to all/2
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.delete/2
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.delete!/2
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.delete_all/2
Convenience function for using repo discovery
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.get/3
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.get!/3
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.get_by/3
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.get_by!/3
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.insert/2
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.insert!/2
Callback implementation for DAL.Behaviour.insert_all/3
Helper function that inserts a list of Ecto.Changeset
via Ecto.Multi
, wrapping it in a transaction.'
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.insert_or_update/2
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.insert_or_update!/2
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.one!/2
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.stream/2
Wrapper over Ecto.transaction
to handle Ecto.Multi
and a standard Ecto.Query
, built in repo discovery
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.update/2
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.update!/2
Link to this section Functions
aggregate(queryable, aggregate, field, opts \\ [])
aggregate(
queryable :: Ecto.Query.t(),
aggregate :: :avg | :count | :max | :min | :sum,
field :: atom(),
opts :: Keyword.t()
) :: [Ecto.Schema.t()] | no_return()
aggregate( queryable :: Ecto.Query.t(), aggregate :: :avg | :count | :max | :min | :sum, field :: atom(), opts :: Keyword.t() ) :: [Ecto.Schema.t()] | no_return()
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.aggregate/4
all(queryable, opts \\ [])
all(queryable :: Ecto.Query.t(), opts :: Keyword.t()) ::
[Ecto.Schema.t()] | no_return()
all(queryable :: Ecto.Query.t(), opts :: Keyword.t()) :: [Ecto.Schema.t()] | no_return()
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.get_by!/2
all_ids(queryable, id_list, opts \\ [])
all_ids(queryable :: Ecto.Query.t(), id_list :: [term()], opts :: Keyword.t()) ::
[Ecto.Schema.t()] | no_return()
all_ids(queryable :: Ecto.Query.t(), id_list :: [term()], opts :: Keyword.t()) :: [Ecto.Schema.t()] | no_return()
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
and then constrains the results to the given list of ids before passing to all/2
.
delete(struct_or_changeset, opts \\ [])
delete(
struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t(),
opts :: Keyword.t()
) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
delete( struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t(), opts :: Keyword.t() ) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.delete/2
delete!(struct_or_changeset, opts \\ [])
delete!(
struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t(),
opts :: Keyword.t()
) :: Ecto.Schema.t() | no_return()
delete!( struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t(), opts :: Keyword.t() ) :: Ecto.Schema.t() | no_return()
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.delete!/2
delete_all(queryable, opts \\ [])
delete_all(queryable :: Ecto.Queryable.t(), opts :: Keyword.t()) ::
{:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
delete_all(queryable :: Ecto.Queryable.t(), opts :: Keyword.t()) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.delete_all/2
discover(structs)
discover(
queryable ::
nil
| Ecto.Query.t()
| Ecto.Changeset.t()
| Ecto.Schema.t()
| [Ecto.Schema.t()]
) :: Ecto.Repo.t()
discover( queryable :: nil | Ecto.Query.t() | Ecto.Changeset.t() | Ecto.Schema.t() | [Ecto.Schema.t()] ) :: Ecto.Repo.t()
Convenience function for using repo discovery.
get(queryable, id, opts \\ [])
get(queryable :: Ecto.Queryable.t(), id :: term(), opts :: Keyword.t()) ::
Ecto.Schema.t() | nil | no_return()
get(queryable :: Ecto.Queryable.t(), id :: term(), opts :: Keyword.t()) :: Ecto.Schema.t() | nil | no_return()
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.get/3
get!(queryable, id, opts \\ [])
get!(queryable :: Ecto.Queryable.t(), id :: term(), opts :: Keyword.t()) ::
Ecto.Schema.t() | nil | no_return()
get!(queryable :: Ecto.Queryable.t(), id :: term(), opts :: Keyword.t()) :: Ecto.Schema.t() | nil | no_return()
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.get!/3
get_by(queryable, params, opts \\ [])
get_by(
queryable :: Ecto.Queryable.t(),
clauses :: Keyword.t() | map(),
opts :: Keyword.t()
) :: Ecto.Schema.t() | nil | no_return()
get_by( queryable :: Ecto.Queryable.t(), clauses :: Keyword.t() | map(), opts :: Keyword.t() ) :: Ecto.Schema.t() | nil | no_return()
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.get_by/3
get_by!(queryable, params, opts \\ [])
get_by!(
queryable :: Ecto.Queryable.t(),
clauses :: Keyword.t() | map(),
opts :: Keyword.t()
) :: Ecto.Schema.t() | nil | no_return()
get_by!( queryable :: Ecto.Queryable.t(), clauses :: Keyword.t() | map(), opts :: Keyword.t() ) :: Ecto.Schema.t() | nil | no_return()
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.get_by!/3
insert(struct_or_changeset, opts \\ [])
insert(
struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t(),
opts :: Keyword.t()
) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
insert( struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t(), opts :: Keyword.t() ) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.insert/2
insert!(struct_or_changeset, opts \\ [])
insert!(
struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t(),
opts :: Keyword.t()
) :: Ecto.Schema.t() | no_return()
insert!( struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t(), opts :: Keyword.t() ) :: Ecto.Schema.t() | no_return()
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.insert!/2
insert_all(schema_or_source, entries, opts \\ [])
insert_all(
schema_or_source :: binary() | {binary(), Ecto.Schema.t()} | Ecto.Schema.t(),
entries :: [map() | Keyword.t()],
opts :: Keyword.t()
) :: {integer(), nil | [term()]} | no_return()
insert_all( schema_or_source :: binary() | {binary(), Ecto.Schema.t()} | Ecto.Schema.t(), entries :: [map() | Keyword.t()], opts :: Keyword.t() ) :: {integer(), nil | [term()]} | no_return()
Callback implementation for DAL.Behaviour.insert_all/3
.
insert_bulk(changesets, opts \\ [])
insert_bulk(changesets :: [Ecto.Changeset.t()], [{:opts, list()}]) ::
{:ok, [map()]} | {:error, Ecto.Changeset.t()}
insert_bulk(changesets :: [Ecto.Changeset.t()], [{:opts, list()}]) :: {:ok, [map()]} | {:error, Ecto.Changeset.t()}
Helper function that inserts a list of Ecto.Changeset
via Ecto.Multi
, wrapping it in a transaction.'
insert_or_update(struct_or_changeset, opts \\ [])
insert_or_update(
struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t(),
opts :: Keyword.t()
) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
insert_or_update( struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t(), opts :: Keyword.t() ) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.insert_or_update/2
insert_or_update!(struct_or_changeset, opts \\ [])
insert_or_update!(
struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t(),
opts :: Keyword.t()
) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
insert_or_update!( struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t(), opts :: Keyword.t() ) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.insert_or_update!/2
one(queryable, opts \\ [])
one(queryable :: Ecto.Query.t(), opts :: Keyword.t()) ::
Ecto.Schema.t() | nil | no_return()
one(queryable :: Ecto.Query.t(), opts :: Keyword.t()) :: Ecto.Schema.t() | nil | no_return()
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.one!/2
preload(struct_or_structs_or_nil, preloads, opts \\ [])
stream(queryable, opts \\ [])
stream(queryable :: Ecto.Query.t(), opts :: Keyword.t()) :: Enum.t()
stream(queryable :: Ecto.Query.t(), opts :: Keyword.t()) :: Enum.t()
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.stream/2
transaction(queryable, opts \\ [])
Wrapper over Ecto.transaction
to handle Ecto.Multi
and a standard Ecto.Query
, built in repo discovery.
update(struct_or_changeset, opts \\ [])
update(
struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t(),
opts :: Keyword.t()
) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
update( struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t(), opts :: Keyword.t() ) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.update/2
update!(struct_or_changeset, opts \\ [])
update!(
struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t(),
opts :: Keyword.t()
) :: Ecto.Schema.t() | no_return()
update!( struct_or_changeset :: Ecto.Schema.t() | Ecto.Changeset.t(), opts :: Keyword.t() ) :: Ecto.Schema.t() | no_return()
Delegates to an appropriate repo determined by DAL.Repo.Discoverable
then behaves just like Ecto.Repo.update!/2