From 033b5ad3a820076b9da2f579f47cc8c669f6b5bc Mon Sep 17 00:00:00 2001 From: Justin Smestad Date: Wed, 8 Apr 2020 11:06:55 -0600 Subject: [PATCH 1/8] Support composite Ecto.Type definitions --- README.md | 11 ++++++----- lib/commanded/command.ex | 5 +++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7299e3d..fc59211 100644 --- a/README.md +++ b/README.md @@ -30,10 +30,11 @@ defmodule CreateAccount do use Commanded.Command, username: :string, email: :string, - age: :integer + age: {:integer, default: 0}, + aliases: {{:array, :string}} # Composite Type requires extra brace to avoid being interprated as opts end -iex> CreateAccount.new() +iex> CreateAccount.new() #Ecto.Changeset, valid?: true> ``` @@ -54,7 +55,7 @@ defmodule CreateAccount do end end -iex> CreateAccount.new() +iex> CreateAccount.new() #Ecto.Changeset< action: nil, changes: %{}, @@ -67,7 +68,7 @@ iex> CreateAccount.new() valid?: false > -iex> changeset = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) +iex> changeset = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) #Ecto.Changeset< action: nil, changes: %{age: 5, email: "chris@example.com", username: "chris"}, @@ -149,7 +150,7 @@ iex> event = AccountCreated.new(cmd) You may have noticed that we provide a default version of `1`. -You can change the version of an event at anytime. +You can change the version of an event at anytime. After doing so, you should define an upcast instance that knows how to transform older events into the latest version. diff --git a/lib/commanded/command.ex b/lib/commanded/command.ex index 7cc197d..8aa7ce2 100644 --- a/lib/commanded/command.ex +++ b/lib/commanded/command.ex @@ -35,6 +35,8 @@ defmodule Commanded.Command do @primary_key false embedded_schema do Enum.map(unquote(schema), fn + {name, {{_, _} = composite_type, opts}} -> field(name, field_type(composite_type), opts) + {name, {{_, _} = composite_type}} -> field(name, field_type(composite_type)) {name, {type, opts}} -> field(name, field_type(type), opts) {name, type} -> field(name, field_type(type)) end) @@ -60,5 +62,8 @@ defmodule Commanded.Command do end def field_type(:binary_id), do: Ecto.UUID + def field_type(:array) do + raise "`:array` is not a valid Ecto.Type\nIf you are using a composite data type, wrap the type definition like this `{{:array, :string}}`" + end def field_type(type), do: type end From e35bae47d3fa26234783f3787184ac00d336a771 Mon Sep 17 00:00:00 2001 From: Justin Smestad Date: Wed, 8 Apr 2020 11:23:59 -0600 Subject: [PATCH 2/8] Update doctest for compound data types --- lib/commanded/command.ex | 9 +++++---- test/support/messages.ex | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/commanded/command.ex b/lib/commanded/command.ex index 8aa7ce2..7652ae3 100644 --- a/lib/commanded/command.ex +++ b/lib/commanded/command.ex @@ -6,18 +6,19 @@ defmodule Commanded.Command do use Commanded.Command, username: :string, email: :string, - age: :integer + age: :integer, + aliases: {{:array, :string}} def handle_validate(changeset) do changeset - |> validate_required([:username, :email, :age]) + |> validate_required([:username, :email, :age, :aliases]) |> validate_format(:email, ~r/@/) |> validate_number(:age, greater_than: 12) end end - iex> CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) - #Ecto.Changeset, valid?: false> + iex> CreateAccount.new(username: "chris", email: "chris@example.com", age: 5, aliases: ["christopher", "kris"]) + #Ecto.Changeset, valid?: false> """ @doc """ diff --git a/test/support/messages.ex b/test/support/messages.ex index f403792..236c792 100644 --- a/test/support/messages.ex +++ b/test/support/messages.ex @@ -9,7 +9,8 @@ defmodule CreateAccount do use Commanded.Command, username: :string, email: :string, - age: :integer + age: :integer, + aliases: {{:array, :string}} def handle_validate(changeset) do changeset From 76bf1fa7f13414e5d1fb6066fff49cd72e7a28f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberts=20Gu=C4=BC=C4=81ns?= Date: Fri, 17 Jul 2020 18:59:45 +0300 Subject: [PATCH 3/8] formated --- lib/commanded/command.ex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/commanded/command.ex b/lib/commanded/command.ex index 7652ae3..0afd989 100644 --- a/lib/commanded/command.ex +++ b/lib/commanded/command.ex @@ -63,8 +63,10 @@ defmodule Commanded.Command do end def field_type(:binary_id), do: Ecto.UUID + def field_type(:array) do raise "`:array` is not a valid Ecto.Type\nIf you are using a composite data type, wrap the type definition like this `{{:array, :string}}`" end + def field_type(type), do: type end From 4e03c339e275f3449ebe3185d831e0fc3327da3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberts=20Gu=C4=BC=C4=81ns?= Date: Fri, 17 Jul 2020 23:12:18 +0300 Subject: [PATCH 4/8] Commands are validated via middleware --- lib/commanded/command.ex | 32 ++++++++- lib/commanded/command_dispatch_validation.ex | 2 +- .../command_validation_middleware.ex | 66 +++++++++++++++++++ lib/commanded/event.ex | 9 ++- lib/commanded_messaging.ex | 21 +++--- mix.exs | 4 +- mix.lock | 4 +- test/commanded_messaging_test.exs | 1 + test/support/messages.ex | 15 +++++ 9 files changed, 128 insertions(+), 26 deletions(-) create mode 100644 lib/commanded/command_validation_middleware.ex diff --git a/lib/commanded/command.ex b/lib/commanded/command.ex index 0afd989..d2eacf9 100644 --- a/lib/commanded/command.ex +++ b/lib/commanded/command.ex @@ -18,7 +18,13 @@ defmodule Commanded.Command do end iex> CreateAccount.new(username: "chris", email: "chris@example.com", age: 5, aliases: ["christopher", "kris"]) + %CreateAccount{username: "chris", email: "chris@example.com", age: 5, aliases: ["christopher", "kris"]} + + iex> CreateAccount.validate(%{username: "chris", email: "chris@example.com", age: 5, aliases: ["christopher", "kris"]}) #Ecto.Changeset, valid?: false> + + iex> CreateAccount.validate(%{email: "emailson", age: 5}) + #Ecto.Changeset, valid?: false> """ @doc """ @@ -43,14 +49,34 @@ defmodule Commanded.Command do end) end - def new(attrs \\ []) do - attrs + def new(), do: %__MODULE__{} + def new(source) + + def new(%{__struct__: _} = source) do + source + |> Map.from_struct() + |> new() + end + + def new(source) when is_list(source) do + source |> Enum.into(%{}) + |> new() + end + + def new(source) when is_map(source) do + source |> create() + end + + use ExConstructor, :create + + def validate(command) when is_map(command) do + command |> cast() |> handle_validate() end - def handle_validate(changeset), do: changeset + def handle_validate(%Ecto.Changeset{} = changeset), do: changeset defoverridable handle_validate: 1 diff --git a/lib/commanded/command_dispatch_validation.ex b/lib/commanded/command_dispatch_validation.ex index b17766d..fcdfc4d 100644 --- a/lib/commanded/command_dispatch_validation.ex +++ b/lib/commanded/command_dispatch_validation.ex @@ -23,7 +23,7 @@ defmodule Commanded.CommandDispatchValidation do def validate_and_dispatch(%Command{valid?: true} = command, opts) do command - |> Command.apply_changes() + |> Ecto.Changeset.apply_changes() |> __MODULE__.dispatch(opts) end diff --git a/lib/commanded/command_validation_middleware.ex b/lib/commanded/command_validation_middleware.ex new file mode 100644 index 0000000..e3fa460 --- /dev/null +++ b/lib/commanded/command_validation_middleware.ex @@ -0,0 +1,66 @@ +defmodule Commanded.Middleware.CommandValidation do + @moduledoc ~S""" + ## Examples + + defmodule CreateFakeAccount do + use Commanded.Command, + username: :string, + email: :string, + age: :integer, + aliases: {{:array, :string}} + + def handle_validate(changeset) do + changeset + |> validate_required([:username, :email, :age, :aliases]) + |> validate_format(:email, ~r/@/) + |> validate_number(:age, greater_than: 12) + end + end + + Successfull command validation result will continue pipeline + + iex> cmd = CreateFakeAccount.new(username: "chris", email: "chris@example.com", age: "13") + iex> pipeline = %Commanded.Middleware.Pipeline{command: cmd} + iex> Commanded.Middleware.CommandValidation.before_dispatch(pipeline) + %Commanded.Middleware.Pipeline{halted: false, command: CreateFakeAccount.new(username: "chris", email: "chris@example.com", age: 13)} + + On error validation halt execution with changeset as response + + iex> cmd = CreateFakeAccount.new(username: nil, email: "chrisexample.com", age: 5) + iex> pipeline = %Commanded.Middleware.Pipeline{command: cmd} + iex> response = Commanded.Middleware.CommandValidation.before_dispatch(pipeline) + iex> {:error, resp} = Map.get(response, :response) + iex> resp + #Ecto.Changeset, valid?: false> + """ + + @behaviour Commanded.Middleware + + alias Commanded.Middleware.Pipeline + + def before_dispatch(%Pipeline{command: command} = pipeline) do + case validate_command(command) do + %{valid?: true} = changeset -> + %{pipeline | command: Ecto.Changeset.apply_changes(changeset)} + + %{valid?: false} = changeset -> + pipeline + |> Map.put(:halted, true) + |> Map.put(:response, {:error, changeset}) + end + end + + def after_dispatch(%Pipeline{} = pipeline) do + pipeline + end + + def after_failure(%Pipeline{} = pipeline) do + pipeline + end + + defp validate_command(%{__struct__: command} = source) do + source + |> Map.from_struct() + |> command.validate() + end +end diff --git a/lib/commanded/event.ex b/lib/commanded/event.ex index bc6e0d0..f723d01 100644 --- a/lib/commanded/event.ex +++ b/lib/commanded/event.ex @@ -28,11 +28,10 @@ defmodule Commanded.Event do end end - iex> changeset = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) - iex> cmd = Ecto.Changeset.apply_changes(changeset) - iex> event = AccountCreatedWithDroppedKeys.new(cmd) - iex> Commanded.Event.Upcaster.upcast(event, %{}) - %AccountCreatedVersioned{age: 5, date: nil, sex: "maybe", username: "chris", version: 2} + # iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) + # iex> event = AccountCreatedWithDroppedKeys.new(cmd) + # iex> Commanded.Event.Upcaster.upcast(event, %{}) + # %AccountCreatedVersioned{age: 5, date: nil, sex: "maybe", username: "chris", version: 2} """ defmacro __using__(opts) do diff --git a/lib/commanded_messaging.ex b/lib/commanded_messaging.ex index c9d8322..d1198c4 100644 --- a/lib/commanded_messaging.ex +++ b/lib/commanded_messaging.ex @@ -16,8 +16,7 @@ defmodule CommandedMessaging do end iex> BasicCreateAccount.new() - #Ecto.Changeset, valid?: true> - + %BasicCreateAccount{age: nil, email: nil, username: nil} ### Validation @@ -35,15 +34,15 @@ defmodule CommandedMessaging do end end - iex> CreateAccount.new() + iex> CreateAccount.validate(%{age: nil, aliases: nil, email: nil, username: nil}) #Ecto.Changeset, valid?: false> - iex> CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) + iex> CreateAccount.validate(%{username: "chris", email: "chris@example.com", age: 5}) #Ecto.Changeset, valid?: false> To create the actual command struct, use `Ecto.Changeset.apply_changes/1` - iex> command = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) + iex> command = CreateAccount.validate(%{username: "chris", email: "chris@example.com", age: 5}) iex> Ecto.Changeset.apply_changes(command) %CreateAccount{age: 5, email: "chris@example.com", username: "chris"} @@ -58,8 +57,7 @@ defmodule CommandedMessaging do from: CreateAccount end - iex> command = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) - iex> cmd = Ecto.Changeset.apply_changes(command) + iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) iex> BasicAccountCreated.new(cmd) %BasicAccountCreated{ age: 5, @@ -79,8 +77,7 @@ defmodule CommandedMessaging do with: [:date] end - iex> command = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) - iex> cmd = Ecto.Changeset.apply_changes(command) + iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) iex> AccountCreatedWithExtraKeys.new(cmd, date: ~D[2019-07-25]) %AccountCreatedWithExtraKeys{ age: 5, @@ -102,8 +99,7 @@ defmodule CommandedMessaging do drop: [:email] end - iex> command = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) - iex> cmd = Ecto.Changeset.apply_changes(command) + iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) iex> AccountCreatedWithDroppedKeys.new(cmd) %AccountCreatedWithDroppedKeys{ age: 5, @@ -138,8 +134,7 @@ defmodule CommandedMessaging do end end - iex> command = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) - iex> cmd = Ecto.Changeset.apply_changes(command) + iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) iex> event = AccountCreatedWithDroppedKeys.new(cmd) iex> Commanded.Event.Upcaster.upcast(event, %{}) %AccountCreatedVersioned{age: 5, date: nil, sex: "maybe", username: "chris", version: 2} diff --git a/mix.exs b/mix.exs index 92fdc84..d358d0d 100644 --- a/mix.exs +++ b/mix.exs @@ -42,10 +42,10 @@ defmodule EsMessaging.MixProject do defp deps do [ {:ecto, "~> 3.3"}, - {:elixir_uuid, "~> 1.2", only: :test}, + {:elixir_uuid, "~> 1.2"}, {:exconstructor, "~> 1.1"}, {:jason, "~> 1.1"}, - {:commanded, "~> 1.0", only: :test}, + {:commanded, "~> 1.1"}, {:ex_doc, "~> 0.14", only: :dev, runtime: false} ] end diff --git a/mix.lock b/mix.lock index b72a0e5..14c5036 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "backoff": {:hex, :backoff, "1.1.6", "83b72ed2108ba1ee8f7d1c22e0b4a00cfe3593a67dbc792799e8cce9f42f796b", [:rebar3], [], "hexpm", "cf0cfff8995fb20562f822e5cc47d8ccf664c5ecdc26a684cbe85c225f9d7c39"}, - "commanded": {:hex, :commanded, "1.0.1", "d4d0583aeedfda8d6c129064155695349352d51e7729f6025590172f94fbd7bf", [:mix], [{:backoff, "~> 1.1", [hex: :backoff, repo: "hexpm", optional: false]}, {:elixir_uuid, "~> 1.2", [hex: :elixir_uuid, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: true]}], "hexpm", "5b08b8dc940aaf8fae7e47b536601b77a442e857eb55afaa32c34e4c4e12d13c"}, + "commanded": {:hex, :commanded, "1.1.1", "0464d7fd30314b595e29229f927f38308698a10bb4106e5bf34b332dd6ff65ad", [:mix], [{:backoff, "~> 1.1", [hex: :backoff, repo: "hexpm", optional: false]}, {:elixir_uuid, "~> 1.2", [hex: :elixir_uuid, repo: "hexpm", optional: false]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: true]}], "hexpm", "4a956f47818d9f8c99fd0db2a941290311195210a6c7529b088a497e9d14f0f7"}, "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"}, "db_connection": {:hex, :db_connection, "2.1.0", "122e2f62c4906bf2e49554f1e64db5030c19229aa40935f33088e7d543aa79d0", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"}, "decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm", "3cb154b00225ac687f6cbd4acc4b7960027c757a5152b369923ead9ddbca7aec"}, @@ -10,7 +10,7 @@ "elixir_uuid": {:hex, :elixir_uuid, "1.2.1", "dce506597acb7e6b0daeaff52ff6a9043f5919a4c3315abb4143f0b00378c097", [:mix], [], "hexpm", "f7eba2ea6c3555cea09706492716b0d87397b88946e6380898c2889d68585752"}, "ex_doc": {:hex, :ex_doc, "0.21.3", "857ec876b35a587c5d9148a2512e952e24c24345552259464b98bfbb883c7b42", [:mix], [{:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "0db1ee8d1547ab4877c5b5dffc6604ef9454e189928d5ba8967d4a58a801f161"}, "exconstructor": {:hex, :exconstructor, "1.1.0", "272623a7b203cb2901c20cbb92c5c3ab103cc0087ff7c881979e046043346752", [:mix], [], "hexpm", "0edd55e8352e04dabf71f35453a57650175c7d7e6af707b1d3df610e5052afe0"}, - "jason": {:hex, :jason, "1.2.0", "10043418c42d2493d0ee212d3fddd25d7ffe484380afad769a0a38795938e448", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "116747dbe057794c3a3e4e143b7c8390b29f634e16c78a7f59ba75bfa6852e7f"}, + "jason": {:hex, :jason, "1.2.1", "12b22825e22f468c02eb3e4b9985f3d0cb8dc40b9bd704730efa11abd2708c44", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b659b8571deedf60f79c5a608e15414085fa141344e2716fbd6988a084b5f993"}, "makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a10c6eb62cca416019663129699769f0c2ccf39428b3bb3c0cb38c718a0c186d"}, "makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "d4b316c7222a85bbaa2fd7c6e90e37e953257ad196dc229505137c5e505e9eff"}, "nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"}, diff --git a/test/commanded_messaging_test.exs b/test/commanded_messaging_test.exs index b888a48..c832f3a 100644 --- a/test/commanded_messaging_test.exs +++ b/test/commanded_messaging_test.exs @@ -3,4 +3,5 @@ defmodule CommandTest do doctest Commanded.Event doctest Commanded.Command doctest CommandedMessaging + doctest Commanded.Middleware.CommandValidation end diff --git a/test/support/messages.ex b/test/support/messages.ex index 236c792..5738228 100644 --- a/test/support/messages.ex +++ b/test/support/messages.ex @@ -20,6 +20,21 @@ defmodule CreateAccount do end end +defmodule CreateFakeAccount do + use Commanded.Command, + username: :string, + email: :string, + age: :integer, + aliases: {{:array, :string}} + + def handle_validate(changeset) do + changeset + |> validate_required([:username, :email, :age]) + |> validate_format(:email, ~r/@/) + |> validate_number(:age, greater_than: 12) + end +end + defmodule BasicAccountCreated do use Commanded.Event, from: CreateAccount From 8025d508a9c3091b810864a215b51e260cb74ea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberts=20Gu=C4=BC=C4=81ns?= Date: Fri, 17 Jul 2020 23:49:16 +0300 Subject: [PATCH 5/8] tests and versioning normalized --- lib/commanded/command.ex | 30 ++-- .../command_validation_middleware.ex | 6 +- lib/commanded/event.ex | 47 +++--- lib/commanded_messaging.ex | 157 ++++++++---------- test/support/messages.ex | 19 ++- 5 files changed, 126 insertions(+), 133 deletions(-) diff --git a/lib/commanded/command.ex b/lib/commanded/command.ex index d2eacf9..0f9509b 100644 --- a/lib/commanded/command.ex +++ b/lib/commanded/command.ex @@ -2,20 +2,20 @@ defmodule Commanded.Command do @moduledoc ~S""" Creates an `Ecto.Schema.embedded_schema` that supplies a command with all the validation power of the `Ecto.Changeset` data structure. - defmodule CreateAccount do - use Commanded.Command, - username: :string, - email: :string, - age: :integer, - aliases: {{:array, :string}} - - def handle_validate(changeset) do - changeset - |> validate_required([:username, :email, :age, :aliases]) - |> validate_format(:email, ~r/@/) - |> validate_number(:age, greater_than: 12) - end + defmodule CreateAccount do + use Commanded.Command, + username: :string, + email: :string, + age: :integer, + aliases: {{:array, :string}} + + def handle_validate(changeset) do + changeset + |> Changeset.validate_required([:username, :email, :age]) + |> Changeset.validate_format(:email, ~r/@/) + |> Changeset.validate_number(:age, greater_than: 12) end + end iex> CreateAccount.new(username: "chris", email: "chris@example.com", age: 5, aliases: ["christopher", "kris"]) %CreateAccount{username: "chris", email: "chris@example.com", age: 5, aliases: ["christopher", "kris"]} @@ -35,8 +35,10 @@ defmodule Commanded.Command do defmacro __using__(schema) do quote do use Ecto.Schema - import Ecto.Changeset + import Ecto.Schema, only: [embedded_schema: 1, field: 2, field: 3] import Commanded.Command + + alias Ecto.Changeset @behaviour Commanded.Command @primary_key false diff --git a/lib/commanded/command_validation_middleware.ex b/lib/commanded/command_validation_middleware.ex index e3fa460..1f84f11 100644 --- a/lib/commanded/command_validation_middleware.ex +++ b/lib/commanded/command_validation_middleware.ex @@ -11,9 +11,9 @@ defmodule Commanded.Middleware.CommandValidation do def handle_validate(changeset) do changeset - |> validate_required([:username, :email, :age, :aliases]) - |> validate_format(:email, ~r/@/) - |> validate_number(:age, greater_than: 12) + |> Changeset.validate_required([:username, :email, :age]) + |> Changeset.validate_format(:email, ~r/@/) + |> Changeset.validate_number(:age, greater_than: 12) end end diff --git a/lib/commanded/event.ex b/lib/commanded/event.ex index f723d01..afe3d2c 100644 --- a/lib/commanded/event.ex +++ b/lib/commanded/event.ex @@ -11,27 +11,28 @@ defmodule Commanded.Event do ## Example - # This is for demonstration purposes only. You don't need to create a new event to version one. - defmodule AccountCreatedVersioned do - use Commanded.Event, - version: 2, - from: CreateAccount, - with: [:date, :sex], - drop: [:email], - - defimpl Commanded.Event.Upcaster, for: AccountCreatedWithDroppedKeys do - def upcast(%{version: 1} = event, _metadata) do - AccountCreatedVersioned.new(event, sex: "maybe", version: 2) - end - - def upcast(event, _metadata), do: event - end + This is for demonstration purposes only. You don't need to create a new event to version one. + + defmodule AccountCreatedVersioned do + use Commanded.Event, + from: CreateAccount, + with: [:date, :sex], + drop: [:email], + version: 2 + + defimpl Commanded.Event.Upcaster, for: AccountCreatedWithDroppedKeys do + def upcast(%{version: 1} = event, _metadata) do + AccountCreatedVersioned.new(event, sex: "maybe") end - # iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) - # iex> event = AccountCreatedWithDroppedKeys.new(cmd) - # iex> Commanded.Event.Upcaster.upcast(event, %{}) - # %AccountCreatedVersioned{age: 5, date: nil, sex: "maybe", username: "chris", version: 2} + def upcast(event, _metadata), do: event + end + end + + iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) + iex> event = AccountCreatedWithDroppedKeys.new(cmd) + iex> Commanded.Event.Upcaster.upcast(event, %{}) + %AccountCreatedVersioned{age: 5, date: nil, sex: "maybe", username: "chris", version: 2} """ defmacro __using__(opts) do @@ -60,6 +61,10 @@ defmodule Commanded.Event do |> Kernel.++(explicit_keys) |> Enum.reject(&Enum.member?(keys_to_drop, &1)) |> Kernel.++([{:version, version}]) + |> Enum.uniq_by(fn + {key, _} -> key + key -> key + end) def new(), do: %__MODULE__{} def new(source, attrs \\ []) @@ -77,7 +82,9 @@ defmodule Commanded.Event do end def new(source, attrs) when is_map(source) do - Map.merge(source, Enum.into(attrs, %{})) + source + |> Map.drop([:version]) + |> Map.merge(Enum.into(attrs, %{})) |> create() end diff --git a/lib/commanded_messaging.ex b/lib/commanded_messaging.ex index d1198c4..924a1c5 100644 --- a/lib/commanded_messaging.ex +++ b/lib/commanded_messaging.ex @@ -8,43 +8,44 @@ defmodule CommandedMessaging do The `Commanded.Command` macro creates an Ecto `embedded_schema` so you can take advantage of the well known `Ecto.Changeset` API. - defmodule BasicCreateAccount do - use Commanded.Command, - username: :string, - email: :string, - age: :integer - end + defmodule BasicCreateAccount do + use Commanded.Command, + username: :string, + email: :string, + age: :integer + end - iex> BasicCreateAccount.new() - %BasicCreateAccount{age: nil, email: nil, username: nil} + iex> BasicCreateAccount.new() + %BasicCreateAccount{age: nil, email: nil, username: nil} ### Validation - defmodule CreateAccount do - use Commanded.Command, - username: :string, - email: :string, - age: :integer - - def handle_validate(command) do - command - |> validate_required([:username, :email, :age]) - |> validate_format(:email, ~r/@/) - |> validate_number(:age, greater_than: 12) - end + defmodule CreateAccount do + use Commanded.Command, + username: :string, + email: :string, + age: :integer, + aliases: {{:array, :string}} + + def handle_validate(changeset) do + changeset + |> Changeset.validate_required([:username, :email, :age]) + |> Changeset.validate_format(:email, ~r/@/) + |> Changeset.validate_number(:age, greater_than: 12) end + end - iex> CreateAccount.validate(%{age: nil, aliases: nil, email: nil, username: nil}) - #Ecto.Changeset, valid?: false> + iex> CreateAccount.validate(%{age: nil, aliases: nil, email: nil, username: nil}) + #Ecto.Changeset, valid?: false> - iex> CreateAccount.validate(%{username: "chris", email: "chris@example.com", age: 5}) - #Ecto.Changeset, valid?: false> + iex> CreateAccount.validate(%{username: "chris", email: "chris@example.com", age: 5}) + #Ecto.Changeset, valid?: false> To create the actual command struct, use `Ecto.Changeset.apply_changes/1` - iex> command = CreateAccount.validate(%{username: "chris", email: "chris@example.com", age: 5}) - iex> Ecto.Changeset.apply_changes(command) - %CreateAccount{age: 5, email: "chris@example.com", username: "chris"} + iex> command = CreateAccount.validate(%{username: "chris", email: "chris@example.com", age: 5}) + iex> Ecto.Changeset.apply_changes(command) + %CreateAccount{age: 5, email: "chris@example.com", username: "chris"} > Note that `apply_changes` will not validate values. @@ -52,62 +53,44 @@ defmodule CommandedMessaging do Most events mirror the commands that produce them. So we make it easy to reduce the boilerplate in creating them with the `Commanded.Event` macro. - defmodule BasicAccountCreated do - use Commanded.Event, - from: CreateAccount - end + defmodule BasicAccountCreated do + use Commanded.Event, + from: CreateAccount + end - iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) - iex> BasicAccountCreated.new(cmd) - %BasicAccountCreated{ - age: 5, - email: "chris@example.com", - username: "chris", - version: 1 - } + iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) + iex> BasicAccountCreated.new(cmd) + %BasicAccountCreated{age: 5, email: "chris@example.com", username: "chris", version: 1} ### Extra Keys There are times when we need keys defined on an event that aren't part of the originating command. We can add these very easily. - defmodule AccountCreatedWithExtraKeys do - use Commanded.Event, - from: CreateAccount, - with: [:date] - end - - iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) - iex> AccountCreatedWithExtraKeys.new(cmd, date: ~D[2019-07-25]) - %AccountCreatedWithExtraKeys{ - age: 5, - date: ~D[2019-07-25], - email: "chris@example.com", - username: "chris", - version: 1 - } + defmodule AccountCreatedWithExtraKeys do + use Commanded.Event, + from: CreateAccount, + with: [:date] + end + iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) + iex> AccountCreatedWithExtraKeys.new(cmd, date: ~D[2019-07-25]) + %AccountCreatedWithExtraKeys{age: 5, date: ~D[2019-07-25], email: "chris@example.com", username: "chris", version: 1} ### Excluding Keys And you may also want to drop some keys from your command. - defmodule AccountCreatedWithDroppedKeys do - use Commanded.Event, - from: CreateAccount, - with: [:date], - drop: [:email] - end - - iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) - iex> AccountCreatedWithDroppedKeys.new(cmd) - %AccountCreatedWithDroppedKeys{ - age: 5, - date: nil, - username: "chris", - version: 1 - } + defmodule AccountCreatedWithDroppedKeys do + use Commanded.Event, + from: CreateAccount, + with: [:date], + drop: [:email] + end + iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) + iex> AccountCreatedWithDroppedKeys.new(cmd) + %AccountCreatedWithDroppedKeys{age: 5, date: nil, username: "chris", version: 1} ### Versioning @@ -117,27 +100,27 @@ defmodule CommandedMessaging do After doing so, you should define an upcast instance that knows how to transform older events into the latest version. - # This is for demonstration purposes only. You don't need to create a new event to version one. - defmodule AccountCreatedVersioned do - use Commanded.Event, - version: 2, - from: CreateAccount, - with: [:date, :sex], - drop: [:email], - - defimpl Commanded.Event.Upcaster, for: AccountCreatedWithDroppedKeys do - def upcast(%{version: 1} = event, _metadata) do - AccountCreatedVersioned.new(event, sex: "maybe", version: 2) - end - - def upcast(event, _metadata), do: event + # This is for demonstration purposes only. You don't need to create a new event to version one. + defmodule AccountCreatedVersioned do + use Commanded.Event, + from: CreateAccount, + with: [:date, :sex], + drop: [:email], + version: 2 + + defimpl Commanded.Event.Upcaster, for: AccountCreatedWithDroppedKeys do + def upcast(%{version: 1} = event, _metadata) do + AccountCreatedVersioned.new(event, sex: "maybe") end + + def upcast(event, _metadata), do: event end + end - iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) - iex> event = AccountCreatedWithDroppedKeys.new(cmd) - iex> Commanded.Event.Upcaster.upcast(event, %{}) - %AccountCreatedVersioned{age: 5, date: nil, sex: "maybe", username: "chris", version: 2} + iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) + iex> event = AccountCreatedWithDroppedKeys.new(cmd) + iex> Commanded.Event.Upcaster.upcast(event, %{}) + %AccountCreatedVersioned{age: 5, date: nil, sex: "maybe", username: "chris", version: 2} > Note that you won't normally call `upcast` manually. `Commanded` will take care of that for you. diff --git a/test/support/messages.ex b/test/support/messages.ex index 5738228..66463f4 100644 --- a/test/support/messages.ex +++ b/test/support/messages.ex @@ -14,9 +14,9 @@ defmodule CreateAccount do def handle_validate(changeset) do changeset - |> validate_required([:username, :email, :age]) - |> validate_format(:email, ~r/@/) - |> validate_number(:age, greater_than: 12) + |> Changeset.validate_required([:username, :email, :age]) + |> Changeset.validate_format(:email, ~r/@/) + |> Changeset.validate_number(:age, greater_than: 12) end end @@ -29,9 +29,9 @@ defmodule CreateFakeAccount do def handle_validate(changeset) do changeset - |> validate_required([:username, :email, :age]) - |> validate_format(:email, ~r/@/) - |> validate_number(:age, greater_than: 12) + |> Changeset.validate_required([:username, :email, :age]) + |> Changeset.validate_format(:email, ~r/@/) + |> Changeset.validate_number(:age, greater_than: 12) end end @@ -56,12 +56,13 @@ end defmodule AccountCreatedVersioned do use Commanded.Event, from: CreateAccount, - with: [:date, :sex, version: 2], - drop: [:email] + with: [:date, :sex, sex: "oh"], + drop: [:email], + version: 2 defimpl Commanded.Event.Upcaster, for: AccountCreatedWithDroppedKeys do def upcast(%{version: 1} = event, _metadata) do - AccountCreatedVersioned.new(event, sex: "maybe", version: 2) + AccountCreatedVersioned.new(event, sex: "maybe") end def upcast(event, _metadata), do: event From 584393821ccfda03164b400383c951ddd4dadb61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberts=20Gu=C4=BC=C4=81ns?= Date: Fri, 17 Jul 2020 23:59:17 +0300 Subject: [PATCH 6/8] default values tests --- lib/commanded/event.ex | 4 ++-- lib/commanded_messaging.ex | 4 ++-- test/support/messages.ex | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/commanded/event.ex b/lib/commanded/event.ex index afe3d2c..b52fec2 100644 --- a/lib/commanded/event.ex +++ b/lib/commanded/event.ex @@ -16,7 +16,7 @@ defmodule Commanded.Event do defmodule AccountCreatedVersioned do use Commanded.Event, from: CreateAccount, - with: [:date, :sex], + with: [:date, :sex, field_with_default_value: "default_value"], drop: [:email], version: 2 @@ -32,7 +32,7 @@ defmodule Commanded.Event do iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) iex> event = AccountCreatedWithDroppedKeys.new(cmd) iex> Commanded.Event.Upcaster.upcast(event, %{}) - %AccountCreatedVersioned{age: 5, date: nil, sex: "maybe", username: "chris", version: 2} + %AccountCreatedVersioned{age: 5, date: nil, sex: "maybe", username: "chris", version: 2, field_with_default_value: "default_value"} """ defmacro __using__(opts) do diff --git a/lib/commanded_messaging.ex b/lib/commanded_messaging.ex index 924a1c5..797a742 100644 --- a/lib/commanded_messaging.ex +++ b/lib/commanded_messaging.ex @@ -104,7 +104,7 @@ defmodule CommandedMessaging do defmodule AccountCreatedVersioned do use Commanded.Event, from: CreateAccount, - with: [:date, :sex], + with: [:date, :sex, field_with_default_value: "default_value"], drop: [:email], version: 2 @@ -120,7 +120,7 @@ defmodule CommandedMessaging do iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) iex> event = AccountCreatedWithDroppedKeys.new(cmd) iex> Commanded.Event.Upcaster.upcast(event, %{}) - %AccountCreatedVersioned{age: 5, date: nil, sex: "maybe", username: "chris", version: 2} + %AccountCreatedVersioned{age: 5, date: nil, sex: "maybe", username: "chris", version: 2, field_with_default_value: "default_value"} > Note that you won't normally call `upcast` manually. `Commanded` will take care of that for you. diff --git a/test/support/messages.ex b/test/support/messages.ex index 66463f4..7d55c69 100644 --- a/test/support/messages.ex +++ b/test/support/messages.ex @@ -56,7 +56,7 @@ end defmodule AccountCreatedVersioned do use Commanded.Event, from: CreateAccount, - with: [:date, :sex, sex: "oh"], + with: [:date, :sex, field_with_default_value: "default_value"], drop: [:email], version: 2 From a853962113d80b273e0b644f231572901f748654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberts=20Gu=C4=BC=C4=81ns?= Date: Sat, 18 Jul 2020 00:03:21 +0300 Subject: [PATCH 7/8] Removed version as special field --- lib/commanded/event.ex | 11 +++-------- lib/commanded_messaging.ex | 19 +++++++------------ test/support/messages.ex | 5 ++--- 3 files changed, 12 insertions(+), 23 deletions(-) diff --git a/lib/commanded/event.ex b/lib/commanded/event.ex index b52fec2..2fbdb46 100644 --- a/lib/commanded/event.ex +++ b/lib/commanded/event.ex @@ -7,7 +7,6 @@ defmodule Commanded.Event do * `from` - A struct to adapt the keys from. * `with` - A list of keys to add to the event. * `drop` - A list of keys to drop from the keys adapted from a struct. - * `version` - An optional version of the event. Defaults to `1`. ## Example @@ -17,11 +16,10 @@ defmodule Commanded.Event do use Commanded.Event, from: CreateAccount, with: [:date, :sex, field_with_default_value: "default_value"], - drop: [:email], - version: 2 + drop: [:email] defimpl Commanded.Event.Upcaster, for: AccountCreatedWithDroppedKeys do - def upcast(%{version: 1} = event, _metadata) do + def upcast(event, _metadata) do AccountCreatedVersioned.new(event, sex: "maybe") end @@ -32,7 +30,7 @@ defmodule Commanded.Event do iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) iex> event = AccountCreatedWithDroppedKeys.new(cmd) iex> Commanded.Event.Upcaster.upcast(event, %{}) - %AccountCreatedVersioned{age: 5, date: nil, sex: "maybe", username: "chris", version: 2, field_with_default_value: "default_value"} + %AccountCreatedVersioned{age: 5, date: nil, sex: "maybe", username: "chris", field_with_default_value: "default_value"} """ defmacro __using__(opts) do @@ -52,7 +50,6 @@ defmodule Commanded.Event do |> Map.keys() end - version = Keyword.get(opts, :version, 1) keys_to_drop = Keyword.get(opts, :drop, []) explicit_keys = Keyword.get(opts, :with, []) @@ -60,7 +57,6 @@ defmodule Commanded.Event do defstruct from |> Kernel.++(explicit_keys) |> Enum.reject(&Enum.member?(keys_to_drop, &1)) - |> Kernel.++([{:version, version}]) |> Enum.uniq_by(fn {key, _} -> key key -> key @@ -83,7 +79,6 @@ defmodule Commanded.Event do def new(source, attrs) when is_map(source) do source - |> Map.drop([:version]) |> Map.merge(Enum.into(attrs, %{})) |> create() end diff --git a/lib/commanded_messaging.ex b/lib/commanded_messaging.ex index 797a742..8838e0e 100644 --- a/lib/commanded_messaging.ex +++ b/lib/commanded_messaging.ex @@ -60,7 +60,7 @@ defmodule CommandedMessaging do iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) iex> BasicAccountCreated.new(cmd) - %BasicAccountCreated{age: 5, email: "chris@example.com", username: "chris", version: 1} + %BasicAccountCreated{age: 5, email: "chris@example.com", username: "chris"} ### Extra Keys @@ -75,7 +75,7 @@ defmodule CommandedMessaging do iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) iex> AccountCreatedWithExtraKeys.new(cmd, date: ~D[2019-07-25]) - %AccountCreatedWithExtraKeys{age: 5, date: ~D[2019-07-25], email: "chris@example.com", username: "chris", version: 1} + %AccountCreatedWithExtraKeys{age: 5, date: ~D[2019-07-25], email: "chris@example.com", username: "chris"} ### Excluding Keys @@ -90,26 +90,21 @@ defmodule CommandedMessaging do iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) iex> AccountCreatedWithDroppedKeys.new(cmd) - %AccountCreatedWithDroppedKeys{age: 5, date: nil, username: "chris", version: 1} + %AccountCreatedWithDroppedKeys{age: 5, date: nil, username: "chris"} ### Versioning - You may have noticed that we provide a default version of `1`. - - You can change the version of an event at anytime. - - After doing so, you should define an upcast instance that knows how to transform older events into the latest version. + You should define an upcast instance that knows how to transform older events into the latest version. # This is for demonstration purposes only. You don't need to create a new event to version one. defmodule AccountCreatedVersioned do use Commanded.Event, from: CreateAccount, with: [:date, :sex, field_with_default_value: "default_value"], - drop: [:email], - version: 2 + drop: [:email] defimpl Commanded.Event.Upcaster, for: AccountCreatedWithDroppedKeys do - def upcast(%{version: 1} = event, _metadata) do + def upcast(event, _metadata) do AccountCreatedVersioned.new(event, sex: "maybe") end @@ -120,7 +115,7 @@ defmodule CommandedMessaging do iex> cmd = CreateAccount.new(username: "chris", email: "chris@example.com", age: 5) iex> event = AccountCreatedWithDroppedKeys.new(cmd) iex> Commanded.Event.Upcaster.upcast(event, %{}) - %AccountCreatedVersioned{age: 5, date: nil, sex: "maybe", username: "chris", version: 2, field_with_default_value: "default_value"} + %AccountCreatedVersioned{age: 5, date: nil, sex: "maybe", username: "chris", field_with_default_value: "default_value"} > Note that you won't normally call `upcast` manually. `Commanded` will take care of that for you. diff --git a/test/support/messages.ex b/test/support/messages.ex index 7d55c69..fd80071 100644 --- a/test/support/messages.ex +++ b/test/support/messages.ex @@ -57,11 +57,10 @@ defmodule AccountCreatedVersioned do use Commanded.Event, from: CreateAccount, with: [:date, :sex, field_with_default_value: "default_value"], - drop: [:email], - version: 2 + drop: [:email] defimpl Commanded.Event.Upcaster, for: AccountCreatedWithDroppedKeys do - def upcast(%{version: 1} = event, _metadata) do + def upcast(event, _metadata) do AccountCreatedVersioned.new(event, sex: "maybe") end From 2d14f961fec0209953c13c25b8af9d228a62ab2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberts=20Gu=C4=BC=C4=81ns?= Date: Sat, 18 Jul 2020 00:09:13 +0300 Subject: [PATCH 8/8] versioning --- README.md | 17 +++++------------ lib/commanded/event.ex | 2 +- lib/commanded_messaging.ex | 2 +- mix.lock | 15 ++++++++------- test/support/messages.ex | 2 +- 5 files changed, 16 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index fc59211..6f13923 100644 --- a/README.md +++ b/README.md @@ -104,8 +104,7 @@ iex> AccountCreated.new(cmd) %AccountCreated{ age: 5, email: "chris@example.com", - username: "chris", - version: 1 + username: "chris" } ``` @@ -125,8 +124,7 @@ iex> AccountCreated.new(cmd, date: NaiveDateTime.utc_now()) age: 5, date: ~N[2019-07-25 08:03:15.372212], email: "chris@example.com", - username: "chris", - version: 1 + username: "chris" } ``` @@ -143,23 +141,18 @@ defmodule AccountCreated do end iex> event = AccountCreated.new(cmd) -%AccountCreated{age: 5, date: nil, username: "chris", version: 1} +%AccountCreated{age: 5, date: nil, username: "chris"} ``` #### Versioning -You may have noticed that we provide a default version of `1`. - -You can change the version of an event at anytime. - -After doing so, you should define an upcast instance that knows how to transform older events into the latest version. +You should define an upcast instance that knows how to transform older events into the latest version. ```elixir defmodule AccountCreated do use Commanded.Event, - version: 2, from: CreateAccount, - with: [:date, :sex], + with: [:date, :sex, version: 2], drop: [:email] defimpl Commanded.Event.Upcaster do diff --git a/lib/commanded/event.ex b/lib/commanded/event.ex index 2fbdb46..3776f30 100644 --- a/lib/commanded/event.ex +++ b/lib/commanded/event.ex @@ -19,7 +19,7 @@ defmodule Commanded.Event do drop: [:email] defimpl Commanded.Event.Upcaster, for: AccountCreatedWithDroppedKeys do - def upcast(event, _metadata) do + def upcast(%AccountCreatedWithDroppedKeys{} = event, _metadata) do AccountCreatedVersioned.new(event, sex: "maybe") end diff --git a/lib/commanded_messaging.ex b/lib/commanded_messaging.ex index 8838e0e..e5e163a 100644 --- a/lib/commanded_messaging.ex +++ b/lib/commanded_messaging.ex @@ -104,7 +104,7 @@ defmodule CommandedMessaging do drop: [:email] defimpl Commanded.Event.Upcaster, for: AccountCreatedWithDroppedKeys do - def upcast(event, _metadata) do + def upcast(%AccountCreatedWithDroppedKeys{} = event, _metadata) do AccountCreatedVersioned.new(event, sex: "maybe") end diff --git a/mix.lock b/mix.lock index 14c5036..d473cdb 100644 --- a/mix.lock +++ b/mix.lock @@ -4,15 +4,16 @@ "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"}, "db_connection": {:hex, :db_connection, "2.1.0", "122e2f62c4906bf2e49554f1e64db5030c19229aa40935f33088e7d543aa79d0", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"}, "decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm", "3cb154b00225ac687f6cbd4acc4b7960027c757a5152b369923ead9ddbca7aec"}, - "earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"}, - "ecto": {:hex, :ecto, "3.3.4", "95b05c82ae91361475e5491c9f3ac47632f940b3f92ae3988ac1aad04989c5bb", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "9b96cbb83a94713731461ea48521b178b0e3863d310a39a3948c807266eebd69"}, + "earmark": {:hex, :earmark, "1.4.9", "837e4c1c5302b3135e9955f2bbf52c6c52e950c383983942b68b03909356c0d9", [:mix], [{:earmark_parser, ">= 1.4.9", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "0d72df7d13a3dc8422882bed5263fdec5a773f56f7baeb02379361cb9e5b0d8e"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.9", "819bda2049e6ee1365424e4ced1ba65806eacf0d2867415f19f3f80047f8037b", [:mix], [], "hexpm", "8bf54fddabf2d7e137a0c22660e71b49d5a0a82d1fb05b5af62f2761cd6485c4"}, + "ecto": {:hex, :ecto, "3.4.5", "2bcd262f57b2c888b0bd7f7a28c8a48aa11dc1a2c6a858e45dd8f8426d504265", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "8c6d1d4d524559e9b7a062f0498e2c206122552d63eacff0a6567ffe7a8e8691"}, "ecto_sql": {:hex, :ecto_sql, "3.1.6", "1e80e30d16138a729c717f73dcb938590bcdb3a4502f3012414d0cbb261045d8", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:myxql, "~> 0.2.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0 or ~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, "elixir_uuid": {:hex, :elixir_uuid, "1.2.1", "dce506597acb7e6b0daeaff52ff6a9043f5919a4c3315abb4143f0b00378c097", [:mix], [], "hexpm", "f7eba2ea6c3555cea09706492716b0d87397b88946e6380898c2889d68585752"}, - "ex_doc": {:hex, :ex_doc, "0.21.3", "857ec876b35a587c5d9148a2512e952e24c24345552259464b98bfbb883c7b42", [:mix], [{:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "0db1ee8d1547ab4877c5b5dffc6604ef9454e189928d5ba8967d4a58a801f161"}, + "ex_doc": {:hex, :ex_doc, "0.22.1", "9bb6d51508778193a4ea90fa16eac47f8b67934f33f8271d5e1edec2dc0eee4c", [:mix], [{:earmark, "~> 1.4.0", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "d957de1b75cb9f78d3ee17820733dc4460114d8b1e11f7ee4fd6546e69b1db60"}, "exconstructor": {:hex, :exconstructor, "1.1.0", "272623a7b203cb2901c20cbb92c5c3ab103cc0087ff7c881979e046043346752", [:mix], [], "hexpm", "0edd55e8352e04dabf71f35453a57650175c7d7e6af707b1d3df610e5052afe0"}, "jason": {:hex, :jason, "1.2.1", "12b22825e22f468c02eb3e4b9985f3d0cb8dc40b9bd704730efa11abd2708c44", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b659b8571deedf60f79c5a608e15414085fa141344e2716fbd6988a084b5f993"}, - "makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a10c6eb62cca416019663129699769f0c2ccf39428b3bb3c0cb38c718a0c186d"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "d4b316c7222a85bbaa2fd7c6e90e37e953257ad196dc229505137c5e505e9eff"}, - "nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"}, - "telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"}, + "makeup": {:hex, :makeup, "1.0.3", "e339e2f766d12e7260e6672dd4047405963c5ec99661abdc432e6ec67d29ef95", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "2e9b4996d11832947731f7608fed7ad2f9443011b3b479ae288011265cdd3dad"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.14.1", "4f0e96847c63c17841d42c08107405a005a2680eb9c7ccadfd757bd31dabccfb", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f2438b1a80eaec9ede832b5c41cd4f373b38fd7aa33e3b22d9db79e640cbde11"}, + "nimble_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"}, + "telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"}, } diff --git a/test/support/messages.ex b/test/support/messages.ex index fd80071..1320cf9 100644 --- a/test/support/messages.ex +++ b/test/support/messages.ex @@ -60,7 +60,7 @@ defmodule AccountCreatedVersioned do drop: [:email] defimpl Commanded.Event.Upcaster, for: AccountCreatedWithDroppedKeys do - def upcast(event, _metadata) do + def upcast(%AccountCreatedWithDroppedKeys{} = event, _metadata) do AccountCreatedVersioned.new(event, sex: "maybe") end