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

jaimeiniesta
I maintain a project that lists hundreds of thousands of web pages, and I’d like to show a screenshot for each web page. There are alread...
New
mrmurphy
I’ve run into a situation where I’ve got a list of posts inside of a container that uses phx-update=“prepend”, and the posts on the socke...
New
Fl4m3Ph03n1x
Background While playing around with dialyzer, typespecs and currying, I was able to create an example of a false positive in dialyzer. ...
New
MarkIden
Hi, Recommend pls your favorite learning resources in Go, with best books, podcasts etc.
/go
New
GermaVinsmoke
Does anyone know beginner friendly Elixir/Phoenix Open source projects? For learning purpose :slightly_smiling_face:
New
AstonJ
If when trying to create (or recreate) your dev db with rails db:create you are getting: PG::ConnectionBad: connection to server on soc...
New
sona11
I studied very basic PHP (I believe). After that, I feel like I’ve gotten a handle on the language. My dream is to work as a web develope...
New
Fl4m3Ph03n1x
Background When trying to execute mix release on a Windows 11 machine for a Phoenix project I get the following error: * assembling mark...
New
jaeyson
Hi! I have clarifications (please correct me, as I mostly mix/confuse this details) with the following: The term RAG here where it read...
New
AstonJ
If you’re getting errors like this: psql: error: connection to server on socket “/tmp/.s.PGSQL.5432” failed: No such file or directory ...
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
Brace yourself for a fun challenge: build a photorealistic 3D renderer from scratch! In just a couple of weeks, build a ray tracer that r...
New
AstonJ
What chair do you have while working… and why? Is there a ‘best’ type of chair or working position for developers?
New
AstonJ
Curious to know which languages and frameworks you’re all thinking about learning next :upside_down_face: Perhaps if there’s enough peop...
New
New
PragmaticBookshelf
Rust is an exciting new programming language combining the power of C with memory safety, fearless concurrency, and productivity boosters...
New
PragmaticBookshelf
Tailwind CSS is an exciting new CSS framework that allows you to design your site by composing simple utility classes to create complex e...
New
PragmaticBookshelf
Learn different ways of writing concurrent code in Elixir and increase your application's performance, without sacrificing scalability or...
New
Maartz
Hi folks, I don’t know if I saw this here but, here’s a new programming language, called Roc Reminds me a bit of Elm and thus Haskell. ...
New
AstonJ
If you’re getting errors like this: psql: error: connection to server on socket “/tmp/.s.PGSQL.5432” failed: No such file or directory ...
New