Git Product home page Git Product logo

Comments (11)

slashdotdash avatar slashdotdash commented on July 2, 2024

@drozzy By default Commanded will set the event type to the event module's full namespace (prepended with Elixir.). This behaviour is implemented in the Commanded.Serialization.ModuleNameTypeProvider module, as shown below:

defmodule Commanded.Serialization.ModuleNameTypeProvider do
  @moduledoc """
  A type provider that uses the Elixir module name

  Example:
    - %An.Event{} module mapped to "Elixir.An.Event".
  """

  @behaviour Commanded.EventStore.TypeProvider

  def to_string(struct), do: Atom.to_string(struct.__struct__)

  def to_struct(type) do
    type |> String.to_existing_atom() |> struct()
  end
end

You can write your own type name provider by implementing the Commanded.EventStore.TypeProvider behaviour in your own module. It's only two functions: to_string/1 and to_struct/1.

As an example, you could use just the event module name, excluding the namespace:

defmodule ExampleTypeProvider do  
  @behaviour Commanded.EventStore.TypeProvider

  def to_string(%Elixir.Foo.Events.BurgerRequested{}), do: "BurgerRequested"
  def to_struct("BurgerRequested"), do: %Elixir.Foo.Events.BurgerRequested{}
end

Then configure it in your environment config file (config/config.exs):

config :commanded,
  type_provider: ExampleTypeProvider

I'm not entirely sure of your exact use case but events should be deserialized to the same module they were serialized from. Perhaps you need to separate the event modules into their own library or umbrella app to be referenced by both nodes (e.g. myapp_events or myapp_contracts)?

The events are the contracts for your application so it is acceptable to extract them into their own app to support shared use.

Does that help you out?

from commanded.

drozzy avatar drozzy commented on July 2, 2024

Yes, this solves my issue completely.
Thank you.

P.S.: To answer you question about my use case: I'm not using umbrella apps. Instead, I actually have separate nodes doing rpc-calls to each other. They communicate through event-store events as a means for pub-sub. That is why I need to deserialize them in a different name space.

from commanded.

drozzy avatar drozzy commented on July 2, 2024

Hm.. are you sure the config is right with type_provided key?

I did everything but no change in behavior...

from commanded.

slashdotdash avatar slashdotdash commented on July 2, 2024

Sorry @drozzy, I forgot to say that you need to recompile Commanded after changing this config setting. It's compiled into Commanded using a macro. The config setting is type_provider.

You need to run:

$ mix deps.compile commanded --force

Let me know if that still doesn't work.

from commanded.

drozzy avatar drozzy commented on July 2, 2024

When I do this compile I get this really weird error:

warning: function ModelAR.TypeProvider.to_struct/1 is undefined (module ModelAR.TypeProvider is not available) lib/commanded/serialization/json_serializer.ex:25

Even though I have a module ModelAR.TypeProvider in the file type_provider.ex.

Here is my config:

config :commanded,
  event_store_adapter: Commanded.EventStore.Adapters.Extreme,
  type_provider:  ModelAR.TypeProvider

Now, it's probably me making some sort of typo, so I'll keep debugging. But maybe something jumps out at you?

from commanded.

drozzy avatar drozzy commented on July 2, 2024

Keeps saying it's not defined. I do pretty much the same thing as in the standard type provider:

https://github.com/slashdotdash/commanded/blob/master/lib/commanded/serialization/module_name_type_provider.ex

from commanded.

slashdotdash avatar slashdotdash commented on July 2, 2024

Yes, I've just tried to reproduce this and have encountered the same compilation error. The good news is that it does actually work when you run your application.

I used the following type provider module which excludes the Elixir. prefix from type name:

defmodule ExampleTypeProvider do
  @behaviour Commanded.EventStore.TypeProvider

  def to_string(struct) do
    "Elixir." <> type = Atom.to_string(struct.__struct__)
    type
  end

  def to_struct(type) do
    "Elixir." <> type |> String.to_existing_atom() |> struct()
  end
end

Peeking into the events table I can see it using the provider I've specified above (as there's no Elixir. prefix on any event_type values). I also included logging just to prove it was using my own module and saw output in the console when appending events to a stream.

I'll have a think about how best to suppress that warning.

from commanded.

drozzy avatar drozzy commented on July 2, 2024

Yap! It works. Thanks.

from commanded.

drozzy avatar drozzy commented on July 2, 2024

P.S.: Just out of curiosity (and not being an expert in Elixir) why are you using macros?

from commanded.

slashdotdash avatar slashdotdash commented on July 2, 2024

In this case it's only used for performance reasons. Reading the value from the application configuration is done once, at compile time, and not each time an event is (de)serialized.

I'm reconsidering this approach now due to it not being very user friendly.

from commanded.

drozzy avatar drozzy commented on July 2, 2024

Compared to read-times over the network, deserialization etc.. I think this is still going to be very fast, even if you read it anew every time.

But that's just my 2c haha.

from commanded.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.