tovarchristian21

tovarchristian21

Hello guys, can you please help turn this map into a pure map. Some of the members of the map are still structs.

%{
  callback_query: nil,
  channel_post: nil,
  chosen_inline_result: nil,
  edited_message: nil,
  inline_query: nil,
  message: %Nadia.Model.Message{
    audio: nil,
    caption: nil,
    channel_chat_created: nil,
    chat: %Nadia.Model.Chat{
      first_name: "Christian",
      id: 543211234,
      last_name: "Tovar",
      photo: nil,
      title: nil,
      type: "private",
      username: "ChristianTovar"
    },
    contact: nil,
    date: 1562605521,
    delete_chat_photo: nil,
    document: nil,
    edit_date: nil,
    entities: nil,
    forward_date: nil,
    forward_from: nil,
    forward_from_chat: nil,
    from: %Nadia.Model.User{
      first_name: "Christian",
      id: 543211234,
      last_name: "Tovar",
      username: "ChristianTovar"
    },
    group_chat_created: nil,
    left_chat_member: nil,
    location: nil,
    message_id: 714,
    migrate_from_chat_id: nil,
    migrate_to_chat_id: nil,
    new_chat_member: nil,
    new_chat_photo: [],
    new_chat_title: nil,
    photo: [],
    pinned_message: nil,
    reply_to_message: nil,
    sticker: nil,
    supergroup_chat_created: nil,
    text: "google meets",
    venue: nil,
    video: nil,
    voice: nil
  },
  update_id: 412827321
}

Showing Posts 1 to 10

wolfiton

wolfiton

Hello,

Welcome to the forum

This may help you
from_struct(struct)View Source

from_struct(atom() | struct()) :: map()

Converts a struct to map.

It accepts the struct module or a struct itself and simply removes the __struct__ field from the given struct or from a new struct generated from the given module.

Example

defmodule User do
  defstruct [:name]
end

Map.from_struct(User)
#=> %{name: nil}

Map.from_struct(%User{name: "john"})
#=> %{name: "john"}
tovarchristian21

tovarchristian21 OP

I actually did that for the outer map. It was a struct, however that function does not turn inner struct into maps…

NobbZ

NobbZ

You need to implement the nesting on your own. But that is a lot more expensive, as it needs to reconstruct the maps from scratch

wolfiton

wolfiton

Wouldn’t s/he be able to use

variable_with_struct
|> Enum.each
|> Map.from_struct

Like this?

Also if i am mistaken please correct me(still learning to think in elixir and the language)

NobbZ

NobbZ

No, Enum.each/2 returns :ok. Also you need to decide for each key in the map/struct if you want to convert it or not.

Eiji

Eiji

Here is example working code:

# First of all minimal definition in order to make code compillable
defmodule Nadia.Model.Chat do
  defstruct [:first_name, :id, :last_name, :photo, :title, :type, :username]
end

defmodule Nadia.Model.User do
  defstruct [:first_name, :id, :last_name, :username]
end

defmodule Nadia.Model.Message do
  defstruct [
    :audio,
    :caption,
    :channel_chat_created,
    :chat,
    :contact,
    :date,
    :delete_chat_photo,
    :document,
    :edit_date,
    :entities,
    :forward_date,
    :forward_from,
    :forward_from_chat,
    :from,
    :group_chat_created,
    :left_chat_member,
    :location,
    :message_id,
    :migrate_from_chat_id,
    :migrate_to_chat_id,
    :new_chat_member,
    :new_chat_photo,
    :new_chat_title,
    :photo,
    :pinned_message,
    :reply_to_message,
    :sticker,
    :supergroup_chat_created,
    :text,
    :venue,
    :video,
    :voice
  ]
end

# Here is code which would work only for your specific case
defmodule Example do
  def sample(map) do
    message = ensure_map(map.message)
    chat = ensure_map(message.chat)
    from = ensure_map(message.from)
    updated_message = %{message | chat: chat, from: from}
    %{map | message: updated_message}
  end

  defp ensure_map(%{__struct__: _} = struct), do: Map.from_struct(struct)
  defp ensure_map(data), do: data
end

# Here is more dynamic way
# No matter how many maps and lists have you nested
# It will iterate over all map or list elements and finally ensure that they are not structs
# NOTE: If you want you can add extra guard to limit possible __struct__ value
# For example you probably do not want to create maps from Date, DateTime, NaiveDateTime and Time structs
defmodule ExampleDynamic do
  def sample(map), do: :maps.map(&do_sample/2, map)

  def do_sample(_key, value), do: ensure_nested_map(value)

  defp ensure_nested_map(list) when is_list(list), do: Enum.map(list, &ensure_nested_map/1)

  # NOTE: In pattern-matching order of function guards is important!
  # @structs [Date, DateTime, NaiveDateTime, Time]
  # defp ensure_nested_map(%{__struct__: struct} = data) when struct in @structs, do: data

  defp ensure_nested_map(%{__struct__: _} = struct) do
    map = Map.from_struct(struct)
    :maps.map(&do_sample/2, map)
  end

  defp ensure_nested_map(data), do: data
end

# Your example data which is needed for compilation
data = %{
  callback_query: nil,
  channel_post: nil,
  chosen_inline_result: nil,
  edited_message: nil,
  inline_query: nil,
  message: %Nadia.Model.Message{
    audio: nil,
    caption: nil,
    channel_chat_created: nil,
    chat: %Nadia.Model.Chat{
      first_name: "Christian",
      id: 543_211_234,
      last_name: "Tovar",
      photo: nil,
      title: nil,
      type: "private",
      username: "ChristianTovar"
    },
    contact: nil,
    date: 1_562_605_521,
    delete_chat_photo: nil,
    document: nil,
    edit_date: nil,
    entities: nil,
    forward_date: nil,
    forward_from: nil,
    forward_from_chat: nil,
    from: %Nadia.Model.User{
      first_name: "Christian",
      id: 543_211_234,
      last_name: "Tovar",
      username: "ChristianTovar"
    },
    group_chat_created: nil,
    left_chat_member: nil,
    location: nil,
    message_id: 714,
    migrate_from_chat_id: nil,
    migrate_to_chat_id: nil,
    new_chat_member: nil,
    new_chat_photo: [],
    new_chat_title: nil,
    photo: [],
    pinned_message: nil,
    reply_to_message: nil,
    sticker: nil,
    supergroup_chat_created: nil,
    text: "google meets",
    venue: nil,
    video: nil,
    voice: nil
  },
  update_id: 412_827_321
}

# Here we are ensuring that both ways gives exactly same results
Example.sample(data) == ExampleDynamic.sample(data)

Please let me know if you have any questions.

Related documentation:

  1. &:maps.map/2
  2. &Enum.map/2
  3. &Map.from_struct/1
  4. Guards
  5. Map (describes specific update syntax)
12
Post #6
tovarchristian21

tovarchristian21 OP

Outstanding! Bravo! Thanks for the help, very complete module indeed.

idi527

idi527

:waving_hand:

Why do you want to convert these structs to maps? Maybe there’s an easier way to accomplish what you want … Personally, I don’t remember having problems with :nadia’s structs.

elielhaouzi

elielhaouzi

  def map_from_struct(%_{__meta__: %{__struct__: _}} = schema) when is_map(schema) do
    schema
    |> Map.from_struct()
    |> from_ecto_struct()
  end

  def map_from_struct(map) when is_map(map) do
    map
    |> Enum.reduce(%{}, fn {key, value}, acc ->
      value =
        case value do
          %_{__meta__: %{__struct__: _}} ->
            from_ecto_struct(value)

          value when is_list(value) ->
            value |> Enum.map(&from_ecto_struct/1)

          _ ->
            value
        end

      Map.put_new(acc, key, value)
    end)
  end

We write a lib of utils around ecto https://github.com/annatel/antl_utils_ecto

one of the functionality is
AntlUtilsEcto.map_from_struct(my_schema)

dodul

dodul

The simplest solution that I found is using Poison.

struct = %{
  callback_query: nil,
  channel_post: nil,
  chosen_inline_result: nil,
  edited_message: nil,
  inline_query: nil,
  message: %Nadia.Model.Message{
    audio: nil,
    caption: nil,
    channel_chat_created: nil,
    chat: %Nadia.Model.Chat{
      first_name: "Christian",
      id: 543211234,
      last_name: "Tovar",
      photo: nil,
      title: nil,
      type: "private",
      username: "ChristianTovar"
    },
    contact: nil,
    date: 1562605521,
    delete_chat_photo: nil,
    document: nil,
    edit_date: nil,
    entities: nil,
    forward_date: nil,
    forward_from: nil,
    forward_from_chat: nil,
    from: %Nadia.Model.User{
      first_name: "Christian",
      id: 543211234,
      last_name: "Tovar",
      username: "ChristianTovar"
    },
    group_chat_created: nil,
    left_chat_member: nil,
    location: nil,
    message_id: 714,
    migrate_from_chat_id: nil,
    migrate_to_chat_id: nil,
    new_chat_member: nil,
    new_chat_photo: [],
    new_chat_title: nil,
    photo: [],
    pinned_message: nil,
    reply_to_message: nil,
    sticker: nil,
    supergroup_chat_created: nil,
    text: "google meets",
    venue: nil,
    video: nil,
    voice: nil
  },
  update_id: 412827321
}

{:ok, json_string} = struct |> Poison.encode
{:ok, map} = json_string |> Poison.decode
map 

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
jonnycharles
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
roeland
Kia ora, We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
subsaharancoder
I’ve followed the Phoenix LiveView file upload code here Uploads — Phoenix LiveView v1.0.0-rc.7 and so far everything works just fine wit...
New
mohsen
I’m using an Umbrella project for a Phoenix application, and I want to have one Ecto Repo and one PostgreSQL database shared by all apps....
New
jaybe78
Hello, I’m developing a online persistent chat system (what’s app) like using elixir/dynamodb/aws for a mobile app(flutter). The diffic...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews