matiso
Idiomatic way to convert from one struct to another
My use case is the following. I have an umbrella application that clearly separates the DB access layer from the business logic. By doing this, I don’t want to directly expose the DB resources to the other applications.
Instead, what I want is to have an edge interface that will expose the DB resource, and a receiver that will do the conversion from the “DB resource” struct, to an internal POEXS (plain old Elixir struct).
I know it might be overcomplicating things, but I want to see how far I can get with this approach.
What bothers me is that I don’t see a way to directly transform StructA into StructB.
So if I have:
%DB.FooResource{name: "bar"}
And I’d like to convert it into:
%MyApp.Foo{name: "bar"}
What I’d need to do is to convert the first one into a map, and create a struct from that map.
data = db_resource |> Map.from_struct()
struct(MyApp.Foo, data)
A bit cumbersome in my opinion, especially if you get an array of those.
Is there a better way of doing this, or is it cumbersome, because it’s a wrong approach?
Most Liked
axelson
I’d think that you’d probably want to create a MyApp.Foo.from_foo_resource/1 to encapsulate the knowledge of how to transform a %DB.FooResource{} into a %MyApp.Foo{} rather than potentially hard-coding that knowledge in multiple places. It might look something like:
defmodule MyApp.Foo do
defstruct [:name]
def from_foo_resource(%DB.FooResource{} = foo_resource) do
struct(MyApp.Foo, Map.from_struct(foo_resource))
end
end
Then if you have a list of %DB.FooResource{} you can do
resource_list = [%DB.FooResource{name: "a"}, %DB.FooResource{name: "b"}]
foo_list = Enum.map(resource_list, &MyApp.Foo.from_foo_resource/1)
Although if all you have is a one-to-one mapping this entire approach sounds like it is overkill (but it is an interesting experiment). I’d imagine if you’re combining multiple DB resources into one representation then something like this definitely makes sense. Or if you’re doing some type of CQRS system.
LostKobrakai
anthonator
@matiso we’re doing something similar with an umbrella app.
Here’s what we came up with.
defmodule Context.Primary.Helpers.Entity do
def new(nil, _entity) do
nil
end
def new(%_{} = struct, entity) do
struct
|> Map.from_struct()
|> new(entity)
end
def new(data, entity) do
struct(entity, data)
end
end
Pretty straightforward. This does break down when you need to compose something from multiple sources.
Last Post!
rogerdff
I was searching for the same decoupling, defining in my umbrella project an ADT Interface (Abstract Data Type).
And using direct Phoenix PubSub and RPC for data exchange through the ADTs types.
Works perfectly, just dont know yet how that will perform when in Prod Env.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex










