DAL v0.2.0 DAL

Global Data Access Layer to replace direct use of Ecto.Repo and other data services.

The DAL performs two core functions:

  1. Provides an abstraction for other data repositories
  2. 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

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

Link to this function 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()

Delegates to an appropriate repo determined by DAL.Repo.Discoverable then behaves just like Ecto.Repo.aggregate/4

Link to this function all(queryable, opts \\ [])
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

Link to this function all_ids(queryable, id_list, opts \\ [])
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.

Link to this function 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()}

Delegates to an appropriate repo determined by DAL.Repo.Discoverable then behaves just like Ecto.Repo.delete/2

Link to this function delete!(struct_or_changeset, opts \\ [])
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

Link to this function delete_all(queryable, opts \\ [])
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

Link to this function discover(queryable)
discover(queryable :: Ecto.Query.t() | Ecto.Changeset.t()) :: Ecto.Repo.t()

Convenience function for using repo discovery.

Link to this function get(queryable, id, opts \\ [])
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

Link to this function get!(queryable, id, opts \\ [])
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

Link to this function get_by(queryable, params, opts \\ [])
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

Link to this function get_by!(queryable, params, opts \\ [])
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

Link to this function 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()}

Delegates to an appropriate repo determined by DAL.Repo.Discoverable then behaves just like Ecto.Repo.insert/2

Link to this function insert!(struct_or_changeset, opts \\ [])
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

Link to this function 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()

Callback implementation for DAL.Behaviour.insert_all/3.

Link to this function insert_bulk(changesets, opts \\ [])
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.’

Link to this function 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()}

Delegates to an appropriate repo determined by DAL.Repo.Discoverable then behaves just like Ecto.Repo.insert_or_update/2

Link to this function 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()}

Delegates to an appropriate repo determined by DAL.Repo.Discoverable then behaves just like Ecto.Repo.insert_or_update!/2

Link to this function one(queryable, opts \\ [])
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

Link to this function preload(struct_or_structs_or_nil, preloads, opts \\ [])
Link to this function stream(queryable, opts \\ [])
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

Link to this function transaction(queryable, opts \\ [])

Wrapper over Ecto.transaction to handle Ecto.Multi and a standard Ecto.Query, built in repo discovery.

Link to this function 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()}

Delegates to an appropriate repo determined by DAL.Repo.Discoverable then behaves just like Ecto.Repo.update/2

Link to this function update!(struct_or_changeset, opts \\ [])
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