Packages
cqrs_tools
0.1.0
0.5.28
0.5.27
0.5.26
0.5.25
0.5.24
0.5.23
0.5.22
0.5.21
0.5.20
0.5.19
0.5.18
0.5.17
0.5.16
0.5.15
0.5.14
0.5.13
0.5.12
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.22
0.3.21
0.3.20
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.30
0.2.29
0.2.28
0.2.27
0.2.26
0.2.25
0.2.24
0.2.23
0.2.22
0.2.21
0.2.20
0.2.19
0.2.18
0.2.17
0.2.16
0.2.15
0.2.14
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.1
0.1.0
A collection of handy Elixir macros for CQRS applications.
Current section
Files
Jump to
Current section
Files
lib/cqrs/bounded_context.ex
defmodule Cqrs.BoundedContext do
alias Cqrs.{BoundedContext, Command, Query}
@moduledoc """
Macros to create proxy functions to [commands](`#{Command}`) and [queries](`#{Query}`) in a module.
## Examples
defmodule Users do
use Cqrs.BoundedContext
command CreateUser
command CreateUser, as: :create_user2
query GetUser
query GetUser, as: :get_user2
end
### Commands
iex> {:error, {:invalid_command, state}} =
...> Users.create_user(name: "chris", email: "wrong")
...> state.errors
%{email: ["has invalid format"]}
iex> {:error, {:invalid_command, state}} =
...> Users.create_user2(name: "chris", email: "wrong")
...> state.errors
%{email: ["has invalid format"]}
iex> Users.create_user(name: "chris", email: "chris@example.com")
{:ok, :dispatched}
iex> Users.create_user2(name: "chris", email: "chris@example.com")
{:ok, :dispatched}
### Queries
iex> Users.get_user!()
** (Cqrs.Query.QueryError) %{email: ["can't be blank"]}
iex> Users.get_user2!()
** (Cqrs.Query.QueryError) %{email: ["can't be blank"]}
iex> Users.get_user!(email: "wrong")
** (Cqrs.Query.QueryError) %{email: ["has invalid format"]}
iex> {:error, %{errors: errors}} = Users.get_user()
...> errors
[email: {"can't be blank", [validation: :required]}]
iex> {:error, %{errors: errors}} = Users.get_user(email: "wrong")
...> errors
[email: {"has invalid format", [validation: :format]}]
iex> {:ok, query} = Users.get_user_query(email: "chris@example.com")
...> query
#Ecto.Query<from u0 in User, where: u0.email == ^"chris@example.com">
iex> {:ok, user} = Users.get_user(email: "chris@example.com")
...> %{id: user.id, email: user.email}
%{id: "052c1984-74c9-522f-858f-f04f1d4cc786", email: "chris@example.com"}
"""
defmacro __using__(_) do
quote do
import BoundedContext, only: [command: 1, command: 2, query: 1, query: 2]
end
end
defmacro query(command, opts \\ []) do
function_name = BoundedContext.__function_name__(command, opts)
quote do
def unquote(function_name)(attrs \\ [], opts \\ []) do
BoundedContext.__execute_query__(unquote(command), attrs, opts)
end
def unquote(:"#{function_name}!")(attrs \\ [], opts \\ []) do
BoundedContext.__execute_query__!(unquote(command), attrs, opts)
end
def unquote(:"#{function_name}_query")(attrs \\ [], opts \\ []) do
BoundedContext.__create_query__(unquote(command), attrs, opts)
end
def unquote(:"#{function_name}_query!")(attrs \\ [], opts \\ []) do
BoundedContext.__create_query__!(unquote(command), attrs, opts)
end
end
end
defmacro command(command, opts \\ []) do
function_name = BoundedContext.__function_name__(command, opts)
quote do
def unquote(function_name)(attrs \\ [], opts \\ []) do
BoundedContext.__dispatch_command__(unquote(command), attrs, opts)
end
def unquote(:"#{function_name}!")(attrs \\ [], opts \\ []) do
BoundedContext.__dispatch_command__!(unquote(command), attrs, opts)
end
end
end
def __function_name__({_, _, module}, opts) do
[name | _] = Enum.reverse(module)
default_function_name =
name
|> to_string
|> Macro.underscore()
|> String.to_atom()
Keyword.get(opts, :as, default_function_name)
end
def __dispatch_command__(module, attrs, opts) do
then = Keyword.get(opts, :then, &Function.identity/1)
attrs
|> module.new(opts)
|> module.dispatch(opts)
|> __handle_command_result__(then)
end
def __dispatch_command__!(module, attrs, opts) do
then = Keyword.get(opts, :then, &Function.identity/1)
attrs
|> module.new!(opts)
|> module.dispatch(opts)
|> __handle_command_result__(then)
end
def __handle_command_result__(result, fun) when is_function(fun, 1), do: fun.(result)
def __handle_command_result__(_result, _other), do: raise("'then' should be a function/1")
def __create_query__(module, attrs, opts) do
module.new(attrs, opts)
end
def __create_query__!(module, attrs, opts) do
module.new!(attrs, opts)
end
def __execute_query__(module, attrs, opts) do
attrs
|> module.new(opts)
|> module.execute(opts)
end
def __execute_query__!(module, attrs, opts) do
attrs
|> module.new!(opts)
|> module.execute(opts)
end
end