Some days ago I posted a question and got an answer that might help You.
Here was the question Ecto and map with tuple keys
Jose Valim told me to look at Ecto.Type
In short, You can cast your data before saving, and uncast after loading. So, no need to modify controller or so… data is serialized at type level.
Does it looks like a solution for You?
This is an example type…
defmodule Whatever.Coordinates do
@behaviour Ecto.Type
def type, do: :map
structure to database
def cast(map) when is_map(map) do
new_map = map
|> Enum.map(fn({key, value}) ->
{coordinate_to_move(key), to_string(value)}
end)
|> Enum.into(%{})
{:ok, new_map}
end
def cast(_), do: :error
database to structure
def load(map) when is_map(map) do
new_map = map
|> Enum.map(fn({key, value}) ->
{move_to_coordinate(key), String.to_atom(value)}
end)
|> Enum.into(%{})
{:ok, new_map}
end
def load(_), do: :error
def dump(map) when is_map(map), do: {:ok, map}
def dump(_), do: :error
“ab” => {x, y}
defp move_to_coordinate(move) do
array_of_index = move
|> to_charlist
|> Enum.map(& &1 - 97)
{Enum.at(array_of_index, 0), Enum.at(array_of_index, 1)}
end
{x, y} => “ab”
defp coordinate_to_move(coordinate) do
[elem(coordinate, 0) + 97, elem(coordinate, 1) + 97]
|> to_string
end
end
In my schema, I use
field :coordinates, Coordinates
And now, everything is transformed just before db actions.
I hope this helps
NB:
I tried to save array of array of any, but got ** (ArgumentError) nested lists must have lists with matching lengths. Be careful if your inner array can vary in size.