FYI: This topic is a continuation of Why doesn't ecto support dynamic map query
In particular:
I want dynamic solution.
otherwise
query = from p in Qber.V1.JobModel, where: p.id == 1, select: %{provider_id: p.id, price: p.cost}
would have been an acceptable solution in the first place.
Another alternative:
defmodule Demo do
# 1) "tuple" is already in a format ready to
# be converted to a Map which can be used repeatedly
# over multiple rows/maps for the purpose of a key lookup
# 2) Return a function that "knows" the key mappings
# via the to_new_key map in the function closure.
# 3) We're avoiding turning strings into atoms as
# atoms aren't garbage collected. So we prefer
# ways where we turn atoms into strings.
# Note: Kernel.to_string/1 relies on the
# String.Chars protocol.
# If we know that we will always be using
# atoms, Atom.to_string seems more appropriate.
# 4) We are not really "replacing" keys. We are only
# selecting values found under a key specified
# in the to_new_key lookup - and only if we find
# it, do be store it in new_map.
# 4a) the original key is found, the value is stored
# under new_key in new_map.
# 4b) the original key IS NOT FOUND
# SO THE value IS IGNORED - we simply
# return the existing new_map.
# FOR "replacement" we would either need
# Map.put(new_map, key, value)
# or possibly
# Map.put(new_map, Atom.to_string(key), value)
#
def make_mapper(key_list) do
to_new_key = Map.new(key_list)
fn ({key, value}, new_map) ->
case Map.fetch(to_new_key, Atom.to_string(key)) do
{:ok, new_key} ->
Map.put(new_map, new_key, value) # (4a)
_ ->
new_map # (4b)
end
end
end
def transform(row_list, key_list) do
#
# 5) create key_mapper function to reuse on each map/row in row_list
#
key_mapper = make_mapper(key_list)
for row <- row_list,
do: Enum.reduce(row, %{}, key_mapper)
end
end
tuple = [{"id", "provider_id"}, {"cost", "price"}]
list_of_maps =[
%{cost: 211.0, id: 1},
%{cost: 149.0, id: 2},
%{cost: 247.0, id: 3},
%{cost: 137.0, id: 4},
%{cost: 272.0, id: 5},
%{cost: 150.0, id: 6}
]
result = Demo.transform(list_of_maps, tuple)
IO.inspect(result)
$ elixir demo.exs
[
%{"price" => 211.0, "provider_id" => 1},
%{"price" => 149.0, "provider_id" => 2},
%{"price" => 247.0, "provider_id" => 3},
%{"price" => 137.0, "provider_id" => 4},
%{"price" => 272.0, "provider_id" => 5},
%{"price" => 150.0, "provider_id" => 6}
]
$