CRUD for an array of arrays of integers

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.

1 Like