Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically populate event_type in EventStore.EventData #116

Closed
OleMchls opened this issue May 8, 2018 · 3 comments · Fixed by #118
Closed

Automatically populate event_type in EventStore.EventData #116

OleMchls opened this issue May 8, 2018 · 3 comments · Fixed by #118

Comments

@OleMchls
Copy link
Contributor

OleMchls commented May 8, 2018

Hey there,

This is really a neat project! While I am digging into the codebase and the usage of this I was wondering why I need to set event_type in EventStore.EventData especially when data is a Struct. The library could internally call Atom.to_string/1 and only optionally allow an overwrite via setting event_type.

Would you folks be open to a PR?

@slashdotdash
Copy link
Member

slashdotdash commented May 8, 2018

The event_type string can be optionally used when deserializing events by your configured serializer module.

Typically you'd create a module per event you persist:

events = [
  %EventData{
    event_type: "Elixir.ExampleEvent",
    data: %ExampleEvent{..},
    metadata: %{"user" => "user@example.com"}
  }
]

:ok = EventStore.append_to_stream(source_stream_uuid, 0, events)

The deserialize/2 function in the EventStore.Serializer behaviour module is passed the event_type for you to use as necessary in your serializer.

defmodule EventStore.RecordedEvent do
  def deserialize(%RecordedEvent{} = recorded_event, serializer) do
    %RecordedEvent{data: data, metadata: metadata, event_type: event_type} = recorded_event

    %RecordedEvent{
      recorded_event
      | data: serializer.deserialize(data, type: event_type),
        metadata: serializer.deserialize(metadata, [])
    }
  end
end

The example JSON serializer, using the Poison library, deserializes events using the type option as follows:

defmodule EventStore.JsonSerializer do
  @behaviour EventStore.Serializer

  def serialize(term) do
    Poison.encode!(term)
  end

  def deserialize(binary, config) do
    type =
      case Keyword.get(config, :type, nil) do
        nil -> []
        type -> type |> String.to_existing_atom() |> struct
      end

    Poison.decode!(binary, as: type)
  end
end

Populating the event_type field is not done automatically to allow you use your own preferred serialization and type name mapping. However, this is all done for you automatically when using Commanded with the EventStore.

@OleMchls
Copy link
Contributor Author

OleMchls commented May 9, 2018

I was thinking about something along the lines of

  defp map_to_recorded_event(
         %EventData{
           data: %{__struct__: event_type},
           event_type: nil
         } = event,
         created_at,
         serializer
       ) do
    %{event | event_type: Atom.to_string(event_type)}
    |> map_to_recorded_event(created_at, serializer)
  end

in lib/stream.ex line 169 before the current map_to_recorded_event definition.

That way you can remove event_type from all examples and let the Library figure out the correct event_type.

I'm happy to file a PR for this.

@slashdotdash
Copy link
Member

Right, I understand what you're proposing thanks to the code example. Yes, it would be useful to allow the event_type to be defaulted as you suggest when nil.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants