- Atom editor.
- atom-elixir package.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- mode: ruby -*- | |
# vi: set ft=ruby : | |
Vagrant.configure(2) do |config| | |
config.vm.box = "ubuntu/trusty64" | |
config.vm.network "private_network", ip: "192.168.33.10" | |
config.vm.provision "shell", inline: <<-SHELL | |
wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && sudo dpkg -i erlang-solutions_1.0_all.deb | |
sudo apt-get update | |
sudo apt-get install -y nodejs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Projections.Repo.Migrations.CreateProjectionVersions do | |
use Ecto.Migration | |
def change do | |
create table(:projection_versions, primary_key: false) do | |
add :projection_name, :text, primary_key: true | |
add :last_seen_event_id, :bigint | |
timestamps | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Aggregates are just collections of command functions, which emit events, | |
# and event handlers, which mutate state. | |
# In order to hold state, they should be also structs. | |
# There is no new() function because aggregates aren't supposed to appear | |
# out of the blue, they are always the result of a command. | |
# In this case, %OpenAccount{}. | |
defmodule Bank.Account do | |
defstruct [:account_number, :balance] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defp upsert_profile(multi, source, source_uuid, profile_url) do | |
profile = %Profile{ | |
source: source, | |
source_uuid: source_uuid, | |
profile: profile_url, | |
} | |
Ecto.Multi.insert(multi, source_uuid, profile, on_conflict: [set: [profile: profile_url]], conflict_target: [:source, :source_uuid]) | |
end |
Inspired by Peter C Marks' ddd_elixir_stage1_umbrella repo.
I've implemented the cargo event handling workflow using the approach dictated by the Commanded CQRS/ES library for Elixir.
The flow is as follows:
HandlingEventController
web controller constructs aTrackHandling
command struct from given POST params.TrackHandling
command is dispatched using theCommandRouter
, which has configured the command to handler/aggregate mapping.
Example read model projections using Commanded Ecto projections where Elixir's Registry
is used for pub/sub notifications of read model updates.
This alleviates the problem of async read model updates.
The command dispatcher can wait until the read model has been updated to the exact aggregate version (as returned by the dispatch command):
with {:ok, version} <- Router.dispatch(register_user, include_aggregate_version: true) do
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Example.Cart do | |
use Chronik.Aggregate | |
alias Example.Cart | |
alias Example.DomainEvents.{CartCreated, ItemsAdded, ItemsRemoved} | |
defstruct [id: nil, items: %{}] | |
## Public API |
with {:ok, version} <- Router.dispatch(command, include_aggregate_version: true),
{:ok, projection} <- wait_for_projection_version(ExampleProjection, uuid, version) do
# ... safely use up-to-date read model projection at expected version
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Article do | |
defstruct [:content, comments: []] | |
# public commands | |
def execute(%Article{}, %PublishArticle{content: content}) do | |
%ArticlePublished{content: content} | |
end | |
def execute(%Article{}, %CommentOnArticle{} = comment) do |