WuunderUtils.Maps (Wuunder Utils v0.1.0)
Contains a set of helpers to deal with some complex stuff with Maps and Structs
Summary
Functions
Maps a given field from given (if not in params)
Mass maps a given input with aliasses
Deletes a list of keys from a map (and all nested maps, lists) Usefull when you want to scrub out IDs for instance.
Removes a key from a map. Doesn't matter if the key is an atom or string
Flattens a map. This results in a map that just contains one level
Creates a clean map from a given struct.
This function deep structs, maps, lists etc. to a map
and uses a set of default transformers as defined in default_struct_fransform/0
.
Retrieves a key from a map regardless of the key type (atom/string) Note that this function does not try to convert a given string key to an atom to prevent an atom overload.
Lazy helper that grabs the field of a map and tries to convert it to a decimal in one pass
Tests if the given map only consists of atom keys
Tests if the map or struct is present
Acts as an IndifferentMap. Put a key/value regardless of the key type. If the map contains keys as atoms, the value will be stored as atom: value. If the map contains strings as keys it will store the value as binary: value
Only puts value in map when value is actually nil (not the same as empty)
Only puts value in map when the value is considered empty
Conditionally puts a value to a given map. Depending on the condition or the value, the key+value will be set to the map
Types
map_key()
Functions
alias_field(params, from, to)
Maps a given field from given (if not in params)
Examples
iex> WuunderUtils.Maps.alias_field(%{country: "NL"}, :country, :country_code)
%{country_code: "NL"}
iex> WuunderUtils.Maps.alias_field(%{"country" => "NL"}, :country, :country_code)
%{"country_code" => "NL"}
iex> WuunderUtils.Maps.alias_field(%{street_name: "Straatnaam"}, :street, :street_address)
%{street_name: "Straatnaam"}
alias_fields(params, aliasses)
Mass maps a given input with aliasses
Examples
iex> WuunderUtils.Maps.alias_fields(%{country: "NL", street: "Straat", number: 666}, %{country: :country_code, street: :street_name, number: :house_number})
%{country_code: "NL", house_number: 666, street_name: "Straat"}
delete_all(map, keys_to_delete)
Deletes a list of keys from a map (and all nested maps, lists) Usefull when you want to scrub out IDs for instance.
Examples
iex> WuunderUtils.Maps.delete_all(
...> %{
...> shipment: %{
...> id: "shipment-id",
...> wuunder_id: "WUUNDERID"
...> },
...> order_lines: [
...> %{id: "123", sku: "SKU01"},
...> %{id: "456", sku: "SKU02"},
...> %{id: "789", sku: "SKU03"}
...> ],
...> meta: %{
...> configuration_id: "nothing"
...> }
...> },
...> [:id, :configuration_id]
...> )
%{
meta: %{},
order_lines: [%{sku: "SKU01"}, %{sku: "SKU02"}, %{sku: "SKU03"}],
shipment: %{wuunder_id: "WUUNDERID"}
}
delete_field(params, key)
Removes a key from a map. Doesn't matter if the key is an atom or string
Examples
iex> WuunderUtils.Maps.delete_field(%{length: 255, weight: 100}, :length)
%{weight: 100}
iex> WuunderUtils.Maps.delete_field(%{length: 255, weight: 100}, "length")
%{weight: 100, length: 255}
iex> WuunderUtils.Maps.delete_field(%{"value" => 50, "currency" => "EUR"}, "currency")
%{"value" => 50}
iex> WuunderUtils.Maps.delete_field(%{"value" => 50, "currency" => "EUR"}, :currency)
%{"value" => 50}
flatten_map(map, options \\ [])
Flattens a map. This results in a map that just contains one level
Options
- key_separator (default .)
- underscore_key (default true)
- list_index_start (default 1)
Example
iex> WuunderUtils.Maps.flatten_map(%{
...> test: "123",
...> order_lines: [
...> %{sku: "123", description: "test"},
...> %{sku: "456", description: "test 2"}
...> ],
...> meta: %{
...> data: "test"
...> }
...> })
%{
"test" => "123",
"order_lines.1.sku" => "123",
"order_lines.1.description" => "test",
"order_lines.2.sku" => "456",
"order_lines.2.description" => "test 2",
"meta.data" => "test"
}
iex> WuunderUtils.Maps.flatten_map(
...> %{
...> test: "123",
...> order_lines: [
...> %{sku: "123", description: "test"},
...> %{sku: "456", description: "test 2"}
...> ],
...> meta: %{
...> data: "test"
...> }
...> },
...> key_separator: "_",
...> list_index_start: 0
...> )
%{
"test" => "123",
"order_lines_0_sku" => "123",
"order_lines_0_description" => "test",
"order_lines_1_sku" => "456",
"order_lines_1_description" => "test 2",
"meta_data" => "test"
}
flatten_map(map_or_list, initial_map, key_prefix, options)
from_struct(value)
Creates a clean map from a given struct.
This function deep structs, maps, lists etc. to a map
and uses a set of default transformers as defined in default_struct_fransform/0
.
It's also able to convert Ecto models to flat maps. It uses the defined Ecto fields for that.
There is also an option to omit the transform
option to add an extra set of transformers.
Examples
iex> WuunderUtils.Maps.from_struct(%TestStruct{
...> first_name: "Peter",
...> last_name: "Pan",
...> date_of_birth: ~D[1980-01-02],
...> weight: Decimal.new("81.5"),
...> country: %TestStruct2{code: "UK"},
...> time_of_death: ~T[13:37:37]
...> })
%{
address: nil,
date_of_birth: "1980-01-02",
first_name: "Peter",
last_name: "Pan",
time_of_death: "13:37:37",
weight: "81.5",
country: %{code: "UK"}
}
iex> WuunderUtils.Maps.from_struct(
...> %TestStruct{
...> first_name: "Peter",
...> last_name: "Pan",
...> date_of_birth: ~D[1980-01-02],
...> weight: Decimal.new("81.5"),
...> country: %TestStruct2{code: "UK"},
...> time_of_death: ~T[13:37:37]
...> },
...> transform: [{TestStruct2, fn x -> "COUNTRY:" <> x.code end}]
...> )
%{
address: nil,
date_of_birth: "1980-01-02",
first_name: "Peter",
last_name: "Pan",
time_of_death: "13:37:37",
weight: "81.5",
country: "COUNTRY:UK"
}
iex> WuunderUtils.Maps.from_struct(
...> %TestStruct{
...> address: %TestSchema{
...> street: "Straat",
...> number: 13,
...> zipcode: "1122AB"
...> },
...> first_name: "Peter",
...> last_name: "Pan",
...> date_of_birth: ~D[1980-01-02],
...> weight: Decimal.new("81.5"),
...> country: %TestStruct2{code: "UK"},
...> time_of_death: ~T[13:37:37]
...> }
...> )
%{
address: %{number: 13, street: "Straat", zipcode: "1122AB"},
date_of_birth: "1980-01-02",
first_name: "Peter",
last_name: "Pan",
time_of_death: "13:37:37",
weight: "81.5",
country: %{code: "UK"}
}
from_struct(value, transform)
get_field(params, key, default \\ nil)
Retrieves a key from a map regardless of the key type (atom/string) Note that this function does not try to convert a given string key to an atom to prevent an atom overload.
Examples
iex> WuunderUtils.Maps.get_field(%{value: 20}, :value)
20
iex> WuunderUtils.Maps.get_field(%{"value" => 20}, :value)
20
iex> WuunderUtils.Maps.get_field(%{value: 20}, "value")
nil
iex> WuunderUtils.Maps.get_field(%{value: 20}, "non-existent")
nil
iex> WuunderUtils.Maps.get_field(%{value: 20}, :weight)
nil
iex> WuunderUtils.Maps.get_field(%{value: 20}, :weight, 350)
350
iex> WuunderUtils.Maps.get_field(%{value: 20}, "currency", "EUR")
"EUR"
get_field_as_decimal(map, key)
Lazy helper that grabs the field of a map and tries to convert it to a decimal in one pass
Examples
iex> WuunderUtils.Maps.get_field_as_decimal(%{value: "50"}, :value)
Decimal.new("50")
iex> WuunderUtils.Maps.get_field_as_decimal(%{value: Decimal.new("1337.5")}, :value)
Decimal.new("1337.5")
iex> WuunderUtils.Maps.get_field_as_decimal(%{value: 50}, :value)
Decimal.new("50")
iex> WuunderUtils.Maps.get_field_as_decimal(%{value: 50}, :weight)
Decimal.new("0")
iex> WuunderUtils.Maps.get_field_as_decimal(%{value: nil}, :value)
Decimal.new("0")
has_only_atom_keys?(struct)
Tests if the given map only consists of atom keys
Examples
iex> WuunderUtils.Maps.has_only_atom_keys?(%{a: 1, b: 2})
true
iex> WuunderUtils.Maps.has_only_atom_keys?(%{:a => 1, "b" => 2})
false
iex> WuunderUtils.Maps.has_only_atom_keys?(%{"a" => 1, "b" => 2})
false
present?(value)
@spec present?(Ecto.Association.NotLoaded.t() | nil | map()) :: boolean()
Tests if the map or struct is present
Examples
iex> WuunderUtils.Maps.present?(nil)
false
iex> WuunderUtils.Maps.present?(%{})
false
iex> WuunderUtils.Maps.present?(%{a: 1})
true
iex> WuunderUtils.Maps.present?(%TestStruct{})
true
iex> WuunderUtils.Maps.present?(%Ecto.Association.NotLoaded{})
false
put_field(params, key, value)
Acts as an IndifferentMap. Put a key/value regardless of the key type. If the map contains keys as atoms, the value will be stored as atom: value. If the map contains strings as keys it will store the value as binary: value
Note that this will not try to convert the given string key to an atom if
the map contains only atom keys (the same reason as stated in helper function get_field
)
Examples
iex> WuunderUtils.Maps.put_field(%{value: 20}, :weight, 350)
%{value: 20, weight: 350}
iex> WuunderUtils.Maps.put_field(%{value: 20}, "weight", 350)
%{:value => 20, "weight" => 350}
iex> WuunderUtils.Maps.put_field(%{"weight" => 350}, :value, 25)
%{"weight" => 350, "value" => 25}
iex> WuunderUtils.Maps.put_field(%{"weight" => 350}, "value", 25)
%{"weight" => 350, "value" => 25}
put_if_not_nil(map, key, value)
Only puts value in map when value is actually nil (not the same as empty)
Examples
iex> WuunderUtils.Maps.put_if_not_nil(%{street: "Straat"}, :street, "Laan")
%{street: "Laan"}
iex> WuunderUtils.Maps.put_if_not_nil(%{street: "Straat"}, :street, nil)
%{street: "Straat"}
iex> WuunderUtils.Maps.put_if_not_nil(%{street: "Straat"}, :street, " ")
%{street: " "}
put_if_present(params, key, value)
Only puts value in map when the value is considered empty
Examples
iex> WuunderUtils.Maps.put_if_present(%{street: "Straat"}, :street, "Laan")
%{street: "Laan"}
iex> WuunderUtils.Maps.put_if_present(%{street: "Straat"}, :street, nil)
%{street: "Straat"}
iex> WuunderUtils.Maps.put_if_present(%{street: "Straat"}, :street, " ")
%{street: "Straat"}
put_when(params, condition, key, value)
Conditionally puts a value to a given map. Depending on the condition or the value, the key+value will be set to the map
Examples
iex> WuunderUtils.Maps.put_when(%{street: "Straat"}, 1 == 1, :number, 13)
%{number: 13, street: "Straat"}
iex> WuunderUtils.Maps.put_when(%{street: "Straat"}, fn -> "value" == "value" end, :number, 13)
%{number: 13, street: "Straat"}
iex> WuunderUtils.Maps.put_when(%{street: "Straat"}, 10 > 20, :number, 13)
%{street: "Straat"}