Fl4m3Ph03n1x

Fl4m3Ph03n1x

How to convert a typed definition to a typedstruct?

Background

I am moving towards defined data structures in my application, and I find that TypedStruct is quite useful.

Questions

However, I have recently found a little hickup. I don’t know how to convert this definition into a typedstruct:

  @type order_info :: %{
    (visible :: String.t()) => boolean,
    (order_type :: String.t()) => String.t(),
    (platform :: String.t()) => String.t(),
    (platinum :: String.t()) => non_neg_integer,
    (user :: String.t()) => %{
      (ingame_name :: String.t()) => String.t(),
      (status :: String.t()) => String.t()
    }
  }

My main issue here is the user map. Aside from the fact I don’t know how to define a typedstruct inside a trypedstruct, how do you folks do this?

  1. Do you simply define a map inside the order_info typedstruct and ignore the mandatory parameters for the user map?
  2. Do you create another typedstruct (called user) that goes inside the typedsctruct called order_info?
  3. What is the standard option in Elixir ?

Marked As Solved

Fl4m3Ph03n1x

Fl4m3Ph03n1x

Answer

After talking with other folks at the community I have opted for separating the User into a struct, in its own module, inside an OrderInfo directory:

lib/
  order_info/
    user.ex
  order_info.ex

I personally find this works great for readability. So for readability purposes this is what I ended up with:

defmodule AuctionHouse.Data.OrderInfo.User do
  @moduledoc """
  Represents the account information for a User.
  """

  use TypedStruct

  alias AuctionHouse.Shared.Utils

  @type user :: %{
          (ingame_name :: String.t()) => String.t(),
          (status :: String.t()) => String.t()
        }

  typedstruct enforce: true do
    @typedoc "Account information of an User"

    field(:ingame_name, String.t())
    field(:status, String.t())
  end

  @spec new(user) :: __MODULE__.t()
  def new(
        %{
          "ingame_name" => ingame_name,
          "status" => status
        } = user
      )
      when is_binary(ingame_name) and is_binary(status),
      do: Utils.string_map_to_struct(user, __MODULE__)
end

An then OrderInfo is basically the same, as seen by this typedstruct definition:

  typedstruct enforce: true do
    @typedoc "Information about an order"

    field(:visible, boolean())
    field(:order_type, String.t())
    field(:platform, String.t())
    field(:platinum, non_neg_integer())
    field(:user, __MODULE__.User.t())
  end

Extra

One thing to mention here, is that struct will not convert string maps to structures, only atom maps. So in order to achieve my goal of converting string maps to structures, I created this little helper function:

defmodule AuctionHouse.Shared.Utils do
  @moduledoc """
  Set of functions used across the app, for utility purposes, like dealing with
  tuples, maps and other data structures.
  """

  alias Morphix

  @spec string_map_to_struct(data :: map, target_struct :: module | struct) ::
          target_struct :: struct
  def string_map_to_struct(data, target_struct) do
    data
    |> Morphix.atomorphiform!()
    |> data_to_struct(target_struct)
  end

  @spec data_to_struct(data :: Enumerable.t(), target_struct :: module | struct) ::
          target_struct :: struct
  def data_to_struct(data, target_struct), do: struct(target_struct, data)
end

Here I used Morphix to do the hard work, but this can also be achieved by other means, see:

Many thanks to all of the people who helped me get this far, from other communities as well:

Where Next?

Popular Backend topics Top

New
AstonJ
Just done a fresh install of macOS Big Sur and on installing Erlang I am getting: asdf install erlang 23.1.2 Configure failed. checking ...
New
s2k
I have this code in a file that’s used to … render templates. require 'erb' require 'ostruct' MISSING_CONFIG_MARKER = :config_key_and_v...
New
Fl4m3Ph03n1x
Background I am trying to get a Github Action working with Windows and Bakeware because I am trying to create a release using it. Howeve...
New
Fl4m3Ph03n1x
Background I am trying to find a cheap and easy way to create New Types in Elixir, and Records seem to be just what I would need. Probl...
New
GermaVinsmoke
Does anyone know beginner friendly Elixir/Phoenix Open source projects? For learning purpose :slightly_smiling_face:
New
Manish_bose
Can anyone help me how to convert a long data to wide data in SQL without using hard coding? Regards Manish
New
Fl4m3Ph03n1x
Background I have a release file inside a tarball. However I want the final release to have some additional files and to move things aro...
New
Fl4m3Ph03n1x
Background I have an umbrella project, where I run mix test from the root. In one of the apps, I am mocking the File module using the Mo...
New
pillaiindu
What is the difference between using :references and :belongs_to in the following command? bin/rails generate scaffold LineItem product:...
New

Other popular topics Top

Devtalk
Hello Devtalk World! Please let us know a little about who you are and where you’re from :nerd_face:
New
PragmaticBookshelf
Learn from the award-winning programming series that inspired the Elixir language, and go on a step-by-step journey through the most impo...
New
PragmaticBookshelf
Design and develop sophisticated 2D games that are as much fun to make as they are to play. From particle effects and pathfinding to soci...
New
brentjanderson
Bought the Moonlander mechanical keyboard. Cherry Brown MX switches. Arms and wrists have been hurting enough that it’s time I did someth...
New
AstonJ
Thanks to @foxtrottwist’s and @Tomas’s posts in this thread: Poll: Which code editor do you use? I bought Onivim! :nerd_face: https://on...
New
New
AstonJ
Do the test and post your score :nerd_face: :keyboard: If possible, please add info such as the keyboard you’re using, the layout (Qw...
New
AstonJ
In case anyone else is wondering why Ruby 3 doesn’t show when you do asdf list-all ruby :man_facepalming: do this first: asdf plugin-upd...
New
New
PragmaticBookshelf
Create efficient, elegant software tests in pytest, Python's most powerful testing framework. Brian Okken @brianokken Edited by Kat...
New