-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix cluster json view adapt_v1 function #3273
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,4 +33,41 @@ defmodule Trento.Support.StructHelper do | |
def to_map(value) when is_nil(value), do: value | ||
def to_map(value) when is_atom(value), do: Atom.to_string(value) | ||
def to_map(value), do: value | ||
|
||
@doc """ | ||
Converts the string keys of a map to existing atoms. | ||
If the key does not exist as atom it continues being a string | ||
""" | ||
@spec to_atomized_map(map | [map] | struct | [struct]) :: map | [map] | ||
def to_atomized_map(%NaiveDateTime{} = value), do: value | ||
def to_atomized_map(%DateTime{} = value), do: value | ||
def to_atomized_map(%Date{} = value), do: value | ||
|
||
def to_atomized_map(struct) when is_struct(struct) do | ||
struct | ||
|> Map.from_struct() | ||
|> to_atomized_map() | ||
end | ||
|
||
def to_atomized_map(map) when is_map(map) do | ||
map | ||
|> Enum.reject(fn | ||
{:__meta__, _} -> true | ||
{_, %Ecto.Association.NotLoaded{}} -> true | ||
_ -> false | ||
end) | ||
|> Map.new(fn {k, v} -> {atomize_key(k), to_atomized_map(v)} end) | ||
end | ||
|
||
def to_atomized_map(list) when is_list(list) do | ||
Enum.map(list, &to_atomized_map/1) | ||
end | ||
|
||
def to_atomized_map(value), do: value | ||
|
||
defp atomize_key(key) do | ||
String.to_existing_atom(key) | ||
rescue | ||
ArgumentError -> key | ||
end | ||
Comment on lines
+36
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be interesting to consider using a Protocol here. One benefit is that it would allow dispatching to the appropriate defimpl (protocol implementation) for different structs in a compile-time aware way. IIRC, one should get a compile error/warning upon calling a protocol function on a struct type that is not implemented/has no fallback. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to understand your point. How do you suggest to implement a Protocol here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was a minor comment, that can be considered later too. For structs like ones you mention, we can add a default implementation that can be tapped into/customized, as needed/on-demand (e.g. via defprotocol AtomizedMap do
def to(arg)
def from(arg)
end
defmodule User do
@derive AtomizedMap
defstruct name: nil, age: nil
end
defimpl AtomizedMap, for: Any do
defmacro __deriving__(module, struct, options) do
quote do
defimpl AtomizedMap, for: unquote(module) do
def to(arg) do
...
end
def from(arg) do
...
end
end
end
end
end There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see. Alright, I guess if we see more needs to keep improving this we can think of a more sophisticated solution like this one |
||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
defmodule Trento.Support.StructHelperTest do | ||
use ExUnit.Case | ||
|
||
alias Trento.Support.StructHelper | ||
|
||
describe "to_atomize_map/1" do | ||
test "should map plain keys to atom keys" do | ||
datetime = DateTime.utc_now() | ||
date = Date.utc_today() | ||
naive_datetime = NaiveDateTime.utc_now() | ||
|
||
initial_map = %{ | ||
"id" => "some-id", | ||
"not_existing_atom" => "some-value", | ||
"not_loaded" => %Ecto.Association.NotLoaded{}, | ||
__meta__: nil, | ||
__struct__: nil, | ||
list: [ | ||
datetime, | ||
date, | ||
naive_datetime | ||
] | ||
} | ||
|
||
assert %{ | ||
"not_existing_atom" => "some-value", | ||
id: "some-id", | ||
list: [ | ||
datetime, | ||
date, | ||
naive_datetime | ||
] | ||
} == StructHelper.to_atomized_map(initial_map) | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the unique way I found of knowing if an atom exists or not.
Unfortunately I didn't find a way to remove the
try/rescue
option