View Source Bonfire.Common.Enums (Bonfire v0.9.11-social-beta.6)

Extra functions to manipulate enumerables, basically an extension of Enum

Summary

Functions

Checks if all tuples in the enumerable are :ok.

Filters the given value or enumerable and if it contains any :error tuple, return an :error tuple with a list of error values, other return an :ok tuple with a list of values.

Gets the value of a key in a map and returns the ID of that value (i.e. either the :id field of that association, or the value itself).

Counts the number of items in an enumerable that satisfy the given function.

Recursively merges two data structures (left and right), which can be structs, maps or lists. If left and right are Ecto.Changesets, merge_changesets/2 is called on them. If left is a struct, a similar struct is returned with the merged values. If left and right are lists, they are concatenated unless :replace_lists option is set to true.

Deep merges a list of maps into a single map.

Attempt getting a value out of a map by atom key, or try with string key, or return a fallback

Takes a value and a fallback value. If the value is empty (e.g. an empty map, a non-loaded association, an empty list, an empty string, or nil), the fallback value is returned.

Takes a list and recursively flattens it by recursively flattening the head and tail of the list

Applies a function from one of Elixir's Map, Keyword, List, Tuple modules depending on the type of the given enumerable, or using a function in Enum if no specific one is defined.

Like Enum.group_by/3, except children are required to be unique (will throw otherwise!) and the resulting map does not wrap each item in a list.

Groups an enumerable by a function that returns key-value pairs, ensuring that keys are unique.

Checks if the given list contains any duplicates. Takes an optional function that can be used to extract and/or compute the value to compare for each element in the list.

Checks if there are any :error tuples in the enumerable.

Checks if there are any :ok tuples in the enumerable.

Checks if there are any tuples with the given key in the enumerable.

Extracts a binary ID from various data structures, such as a map containing the key :id or "id", a changeset, or a tuple containing the atom :id.

Extracts the IDs from a list of maps, changesets, or other data structures and returns a list of these IDs.

Takes a data structure and converts any keys in maps to (previously defined) atoms, recursively. By default any unknown string keys will be discarded. It can optionally also convert string values to known atoms as well.

Converts input to value based on the provided options.

Recursively filters nil values from a map

Renames a key in a map. Optionally changes the value as well.

Renames a key in a map, only if the key exists in the map. Optionally changes the value as well.

Takes an enumerable object and converts it to a map. If it is not an enumerable, a map is created with the data under a fallback key (:data by default).

Checks a map for a value with provided key. If it already exists, the existing value is retained, but if not set or nil, then it is set to the provided default.

Updates a nested map using a list of keys and a value to set. It returns a new map with the updated value at the specified location.

Appends a value to a list, but only if the value is not nil or an empty list.

Takes any element, an index and a fallback value. If the element is a Tuple it returns either the tuple value at that index, otherwise it returns the fallback. If the tuple doesn't contain such an index, it raises ArgumentError.

Flattens the list if provided a list, otherwise just return the input

Attempts to retrieve a value from a map by its key, and otherwise returns the provided fallback value.

Updates a Map or Keyword with the given key and value, but only if the value is not nil, an empty list or an empty string.

Returns a keyword list representation of the input object. If the second argument is true, the function will recursively convert nested data structures to keyword lists as well. Note: make sure that all keys are atoms, i.e. using input_to_atoms first, otherwise the enumerable(s) containing a string key won't be converted.

Returns a map representation of the input object. If the second argument is true, the function will recursively convert nested data structures to maps as well.

Takes a data structure and tries to convert it to a struct, using the optional type provided or some hints in the data (eg. __type or index_type fields).

Takes a data structure and recursively converts any known keys to atoms and then tries to recursively convert any maps to structs, using hints in the data (eg. __type or index_type fields) or related schemas (eg. mixins).

Merges two maps or lists into a single map

Merges two Ecto changesets. If both changesets have a prepare field, the function concatenates the values of the prepare fields. Either way it also calls Ecto.Changeset.merge/2 operation.

Merges two maps while keeping only the keys that exist in the first map.

Recursively converts all nested structs to maps.

This function is used to insert a new value into a nested map data structure, where the path to the location of the value is specified as a list of keys.

Infer the struct or schema type from a map

Takes a map or keyword list, and returns a map with any atom keys converted to string keys. It can optionally do so recursively.

If given a struct, returns a map representation of it

Takes a list of maps that have an id field and returns a list with only the unique maps. Uniqueness is determined based on the id field and not the full contents of the maps.

Unwraps tuples from a list of responses based on the specified key.

Functions

access_keys(keys, last_fallback \\ nil)

all_ok?(enum)

Checks if all tuples in the enumerable are :ok.

Examples

iex> Bonfire.Common.Enums.all_ok?([{:ok, 1}, {:ok, 2}])
true

iex> Bonfire.Common.Enums.all_ok?([{:ok, 1}, {:error, "failed"}])
false

all_oks_or_error(enum)

Filters the given value or enumerable and if it contains any :error tuple, return an :error tuple with a list of error values, other return an :ok tuple with a list of values.

Examples

iex> Bonfire.Common.Enums.all_oks_or_error([{:ok, 1}, {:error, "failed"}])
{:error, ["failed"]}

iex> Bonfire.Common.Enums.all_oks_or_error([{:ok, 2}, {:ok, 3}])
{:ok, [2, 3]}

iex> Bonfire.Common.Enums.all_oks_or_error({:error, "failed"})
{:error, ["failed"]}

iex> Bonfire.Common.Enums.all_oks_or_error({:ok, 1})
{:ok, [1]}

attr_get_id(attrs, field_name)

Gets the value of a key in a map and returns the ID of that value (i.e. either the :id field of that association, or the value itself).

count_where(collection, function \\ &is_nil/1)

Counts the number of items in an enumerable that satisfy the given function.

Examples

iex> Bonfire.Common.Enums.count_where([1, 2, 3, 4, 5], fn x -> rem(x, 2) == 0 end)
2

iex> Bonfire.Common.Enums.count_where([:ok, :error, :ok], &(&1 == :ok))
2

deep_merge(left, right, opts \\ [])

Recursively merges two data structures (left and right), which can be structs, maps or lists. If left and right are Ecto.Changesets, merge_changesets/2 is called on them. If left is a struct, a similar struct is returned with the merged values. If left and right are lists, they are concatenated unless :replace_lists option is set to true.

deep_merge_reduce(list_or_map, opts \\ [])

Deep merges a list of maps into a single map.

enum_get(map, key, fallback \\ nil)

Attempt getting a value out of a map by atom key, or try with string key, or return a fallback

filter_empty(val, fallback)

Takes a value and a fallback value. If the value is empty (e.g. an empty map, a non-loaded association, an empty list, an empty string, or nil), the fallback value is returned.

filter_empty(enum, fallback, key)

first!(list)

flatter(list)

Takes a list and recursively flattens it by recursively flattening the head and tail of the list

fun(map, fun, args \\ [])

Applies a function from one of Elixir's Map, Keyword, List, Tuple modules depending on the type of the given enumerable, or using a function in Enum if no specific one is defined.

Examples

> Bonfire.Common.Enums.fun(%{a: 1, b: 2}, :values)
# runs `Map.values/1`
[2, 1]

iex> Bonfire.Common.Enums.fun([a: 1, b: 2], :values)
# runs `Keyword.values/1`
[1, 2]

iex> Bonfire.Common.Enums.fun([1, 2, 3], :first)
# runs `List.first/1`
1

iex> Bonfire.Common.Enums.fun({1, 2}, :sum)
# runs `Tuple.sum/1`
3

iex> Bonfire.Common.Enums.fun({1, 2}, :last)
# runs `List.last/1` after converting the tuple to a list
2

iex> Bonfire.Common.Enums.fun([1, 2, 3], :sum)
# runs `Enum.sum/1` because there's no `List.sum/1`
6

get_in_access_keys(map, keys, last_fallback)

get_in_access_keys!(map, keys, last_fallback)

group(list, fun)

Like Enum.group_by/3, except children are required to be unique (will throw otherwise!) and the resulting map does not wrap each item in a list.

Examples

iex> Bonfire.Common.Enums.group([1, 2, 3], fn x -> x end)
%{1 => 1, 2 => 2, 3 => 3}

> Bonfire.Common.Enums.group([:a, :b, :b, :c], fn x -> x end)
** (throw) "Expected a unique value"

group_map(list, fun)

Groups an enumerable by a function that returns key-value pairs, ensuring that keys are unique.

Examples

iex> Bonfire.Common.Enums.group_map([:a, :b, :c], fn x -> {x, to_string(x)} end)
%{a: "a", b: "b", c: "c"}

> Bonfire.Common.Enums.group_map([1, 2, 2, 3], fn x -> {x, x * 2} end)
** (throw) "Expected a unique value"

has_duplicates?(list, fun \\ nil)

Checks if the given list contains any duplicates. Takes an optional function that can be used to extract and/or compute the value to compare for each element in the list.

has_error?(enum)

Checks if there are any :error tuples in the enumerable.

Examples

iex> Bonfire.Common.Enums.has_error?([{:ok, 1}, {:error, "failed"}])
true

iex> Bonfire.Common.Enums.has_error?([{:ok, 1}])
false

has_ok?(enum)

Checks if there are any :ok tuples in the enumerable.

Examples

iex> Bonfire.Common.Enums.has_ok?([{:ok, 1}, {:error, "failed"}])
true

iex> Bonfire.Common.Enums.has_ok?([{:error, "failed"}])
false

has_tuple_key?(enum, key)

Checks if there are any tuples with the given key in the enumerable.

Examples

iex> Bonfire.Common.Enums.has_tuple_key?([{:ok, 1}, {:error, "failed"}], :ok)
true

iex> Bonfire.Common.Enums.has_tuple_key?([{:ok, 1}], :error)
false

id(id)

Extracts a binary ID from various data structures, such as a map containing the key :id or "id", a changeset, or a tuple containing the atom :id.

ids(objects)

Extracts the IDs from a list of maps, changesets, or other data structures and returns a list of these IDs.

  iex> ids([%{id: 1, name: "Alice"}, %{id: 2, name: "Bob"}])
  [1, 2]

  iex> ids(%{id: 3})
  [3]

input_to_atoms(data, opts \\ [])

Takes a data structure and converts any keys in maps to (previously defined) atoms, recursively. By default any unknown string keys will be discarded. It can optionally also convert string values to known atoms as well.

input_to_value(v, _, including_values, _, force, arg6, values_to_integers)

Converts input to value based on the provided options.

Examples

iex> input_to_value("42", false, true, nil, true, nil, true)
42

iex> input_to_value("Bonfire.Common", false, true, nil, true, nil, false)
Bonfire.Common

iex> input_to_value("bonfire_common", false, true, nil, true, nil, false)
:bonfire_common

iex> input_to_value("unknown_example_string", false, true, nil, true, nil, false)
"unknown_example_string"

map_filter_empty(data)

Recursively filters nil values from a map

map_key_replace(map, key, new_key, new_value \\ nil)

Renames a key in a map. Optionally changes the value as well.

map_key_replace_existing(map, key, new_key, new_value \\ nil)

Renames a key in a map, only if the key exists in the map. Optionally changes the value as well.

map_new(data, fallback_key \\ :data)

Takes an enumerable object and converts it to a map. If it is not an enumerable, a map is created with the data under a fallback key (:data by default).

map_put_default(map, key, default)

Checks a map for a value with provided key. If it already exists, the existing value is retained, but if not set or nil, then it is set to the provided default.

map_put_in(root \\ %{}, keys, value)

Updates a nested map using a list of keys and a value to set. It returns a new map with the updated value at the specified location.

Examples

iex> map_put_in(%{}, [:a, :b, :c], 3)
%{a: %{b: %{c: 3}}}

Parameters

  • root - The initial map (can be an empty map or a populated one).
  • keys - A list of keys specifying the path to the value.
  • value - The value to set at the specified location.

maybe_append(list, value)

@spec maybe_append([any()], any()) :: [any()]

Appends a value to a list, but only if the value is not nil or an empty list.

maybe_elem(tuple, index, fallback \\ nil)

Takes any element, an index and a fallback value. If the element is a Tuple it returns either the tuple value at that index, otherwise it returns the fallback. If the tuple doesn't contain such an index, it raises ArgumentError.

maybe_flatten(list)

Flattens the list if provided a list, otherwise just return the input

maybe_get(map, key, fallback \\ nil)

Attempts to retrieve a value from a map by its key, and otherwise returns the provided fallback value.

maybe_list(val, change_fn)

maybe_merge_to_struct(first, precedence)

maybe_put(map, key, value)

Updates a Map or Keyword with the given key and value, but only if the value is not nil, an empty list or an empty string.

maybe_to_keyword_list(obj, recursive \\ false, force_top_level \\ true)

Returns a keyword list representation of the input object. If the second argument is true, the function will recursively convert nested data structures to keyword lists as well. Note: make sure that all keys are atoms, i.e. using input_to_atoms first, otherwise the enumerable(s) containing a string key won't be converted.

maybe_to_map(obj, recursive \\ false)

Returns a map representation of the input object. If the second argument is true, the function will recursively convert nested data structures to maps as well.

maybe_to_struct(obj, type \\ nil)

Takes a data structure and tries to convert it to a struct, using the optional type provided or some hints in the data (eg. __type or index_type fields).

NOTE: you may want to call input_to_atoms/2 on the data first if it contains string keys instead of atoms.

Examples

iex> # Convert map with `index_type` to struct (and leave nested map alone, hint: use `maybe_to_structs/1` to also process nested data)
iex> maybe_to_struct(%{
...>   index_type: "Bonfire.Data.Identity.User",
...>   id: "01JB4E8T1H928QC6E1MP1XDZD8",
...>   character: %{
...>     id: "01JB4E8T1H928QC6E1MP1XDZD8",
...>     username: "test"
...>   }
...> })
%Bonfire.Data.Identity.User{
  id: "01JB4E8T1H928QC6E1MP1XDZD8",
  character: %{
    id: "01JB4E8T1H928QC6E1MP1XDZD8",
    username: "test"
  }
}

iex> # Map to a specific struct (ignores hints in data)
iex> maybe_to_struct(%{
...>   index_type: "Bonfire.Data.Identity.User",
...>   id: "01JB4E8T1H928QC6E1MP1XDZD8"
...> }, Bonfire.Data.Identity.Character)
%Bonfire.Data.Identity.Character{
  id: "01JB4E8T1H928QC6E1MP1XDZD8"
}

iex> # Struct to a different struct
iex> maybe_to_struct(%Bonfire.Data.Identity.User{
...>   id: "01JB4E8T1H928QC6E1MP1XDZD8"
...> }, Bonfire.Data.Identity.Character)
%Bonfire.Data.Identity.Character{
  id: "01JB4E8T1H928QC6E1MP1XDZD8"
}

maybe_to_structs(data, top_level_type \\ nil, parent_schema_throuple \\ nil)

Takes a data structure and recursively converts any known keys to atoms and then tries to recursively convert any maps to structs, using hints in the data (eg. __type or index_type fields) or related schemas (eg. mixins).

NOTE: you may want to call input_to_atoms/2 on the data first if it contains string keys instead of atoms.

Examples

iex> # Nested maps with `index_type` or `__typename`
iex> maybe_to_structs(%{
...>   index_type: "Bonfire.Data.Identity.User",
...>   id: "01JB4E8T1H928QC6E1MP1XDZD8",
...>   character: %{
...>     __typename: Bonfire.Data.Identity.Character,
...>     id: "01JB4E8T1H928QC6E1MP1XDZD8",
...>     username: "test"
...>   }
...> })
%Bonfire.Data.Identity.User{
  id: "01JB4E8T1H928QC6E1MP1XDZD8",
  character: %Bonfire.Data.Identity.Character{
    id: "01JB4E8T1H928QC6E1MP1XDZD8",
    username: "test"
  }
}
iex> # Nested maps with `index_type` on top-level and nested mixin with no hint of type (gets inferred from the parent schema)
iex> maybe_to_structs(%{
...>   index_type: "Bonfire.Data.Identity.User",
...>   id: "01JB4E8T1H928QC6E1MP1XDZD8",
...>   character: %{
...>     id: "01JB4E8T1H928QC6E1MP1XDZD8",
...>     username: "test"
...>   }
...> })
%Bonfire.Data.Identity.User{
  id: "01JB4E8T1H928QC6E1MP1XDZD8",
  character: %Bonfire.Data.Identity.Character{
    id: "01JB4E8T1H928QC6E1MP1XDZD8",
    username: "test"
  }
}

iex> # Nested maps with `index_type` on top-level and nested mixin with no ID (gets inferred from the parent schema)
iex> maybe_to_structs(%{
...>   index_type: "Bonfire.Data.Identity.User",
...>   id: "01JB4E8T1H928QC6E1MP1XDZD8",
...>   character: %{
...>     __typename: Bonfire.Data.Identity.Character,
...>     username: "test"
...>   }
...> })
%Bonfire.Data.Identity.User{
  id: "01JB4E8T1H928QC6E1MP1XDZD8",
  character: %Bonfire.Data.Identity.Character{
    id: "01JB4E8T1H928QC6E1MP1XDZD8",
    username: "test"
  }
}

iex> # Nested maps with `index_type` on top-level and nested mixin with no hint of type or ID (both get inferred from the parent schema)
iex> maybe_to_structs(%{
...>   index_type: "Bonfire.Data.Identity.User",
...>   id: "01JB4E8T1H928QC6E1MP1XDZD8",
...>   character: %{
...>     username: "test"
...>   }
...> })
%Bonfire.Data.Identity.User{
  id: "01JB4E8T1H928QC6E1MP1XDZD8",
  character: %Bonfire.Data.Identity.Character{
    id: "01JB4E8T1H928QC6E1MP1XDZD8",
    username: "test"
  }
}

iex> # Nested maps with type override for the top level 
iex> maybe_to_structs(%{
...>   index_type: "Bonfire.Data.Identity.User",
...>   id: "01JB4E8T1H928QC6E1MP1XDZD8",
...>   character: %{
...>     __typename: Bonfire.Data.Identity.Character,
...>     id: "01JB4E8T1H928QC6E1MP1XDZD8",
...>     username: "test"
...>   }
...> }, Needle.Pointer)
%Needle.Pointer{
  id: "01JB4E8T1H928QC6E1MP1XDZD8",
  character: %Bonfire.Data.Identity.Character{
    id: "01JB4E8T1H928QC6E1MP1XDZD8",
    username: "test"
  }
}

iex> # Struct with nested map with `__typename`
iex> maybe_to_structs(%Bonfire.Data.Identity.User{
...>   id: "01JB4E8T1H928QC6E1MP1XDZD8",
...>   character: %{
...>     __typename: Bonfire.Data.Identity.Character,
...>     id: "01JB4E8T1H928QC6E1MP1XDZD8",
...>     username: "test"
...>   }
...> })
%Bonfire.Data.Identity.User{
  id: "01JB4E8T1H928QC6E1MP1XDZD8",
  character: %Bonfire.Data.Identity.Character{
    id: "01JB4E8T1H928QC6E1MP1XDZD8",
    username: "test"
  }
}

merge_as_map(left, right, opts \\ [])

Merges two maps or lists into a single map

merge_changesets(cs1, cs2)

Merges two Ecto changesets. If both changesets have a prepare field, the function concatenates the values of the prepare fields. Either way it also calls Ecto.Changeset.merge/2 operation.

merge_keeping_only_first_keys(map_1, map_2)

Merges two maps while keeping only the keys that exist in the first map.

merge_structs_as_map(target, merge)

merge_to_struct(module \\ nil, first, precedence)

merge_uniq(left, right)

naughty_to_atoms!(data, opts \\ [])

nested_structs_to_maps(struct)

Recursively converts all nested structs to maps.

put_new_in(map, list, val)

This function is used to insert a new value into a nested map data structure, where the path to the location of the value is specified as a list of keys.

When the path is a single-element list, if the key already exists in the map, it returns the original map; otherwise, it inserts the key-value pair.

When the path is a list of more than one key, the first element of the list (key) represents the key for the current level of the nested map, and the remaining elements (path) represent the keys for the nested map at the next level. The function starts by retrieving the value at the current level of the map (if it exists) and updates the map with the new value.

schema_type(arg1)

Infer the struct or schema type from a map

stringify_keys(map, recursive \\ false)

Takes a map or keyword list, and returns a map with any atom keys converted to string keys. It can optionally do so recursively.

struct_to_map(other, recursive \\ false)

If given a struct, returns a map representation of it

uniq_by_id(list)

Takes a list of maps that have an id field and returns a list with only the unique maps. Uniqueness is determined based on the id field and not the full contents of the maps.

unwrap_tuples(enum, key)

Unwraps tuples from a list of responses based on the specified key.

Examples

iex> Bonfire.Common.Enums.unwrap_tuples([{:ok, 1}, {:error, "failed"}, {:ok, 2}], :ok)
[1, 2]

iex> Bonfire.Common.Enums.unwrap_tuples([{:ok, 1}, {:error, "failed"}], :error)
["failed"]