View Source Dx.Result (dx v0.3.1)

Result types and helpers to work with them.

A result is either:

  • {:error, e} if an error occurred
  • {:not_loaded, data_reqs} if the result could not be determined without loading more data
  • {:ok, boolean, binds} otherwise, in contexts where a boolean is expected (type t:b())
  • {:ok, result, binds} otherwise, where result can be any value (type t:v())

Data loading

In general, {:not_loaded, all_reqs} only ever returns data requirements that are really needed.

Example using all

For example, using all?/1 with 3 conditions A, B and C, where

iex> [
...>   {:ok, true, %{}},   # A
...>   {:not_loaded, [1]}, # B
...>   {:ok, false, %{}},  # C
...> ]
...> |> Dx.Result.all?()
{:ok, false, %{}}

The overall result is {:ok, false, %{}}. While B would need more data to be loaded, C can already determined and is false, so and any additional data loaded will not change that.

Example using find

Another example, using find/1 with 5 conditions A, B, C, D and E, where

iex> [
...>   {:ok, false, %{}},  # A
...>   {:not_loaded, [1]}, # B
...>   {:not_loaded, [2]}, # C
...>   {:ok, true, %{}},   # D
...>   {:not_loaded, [3]}, # E
...> ]
...> |> Dx.Result.find()
{:not_loaded, [1, 2]}

The overall result is {:not_loaded, data_reqs1 + data_reqs2}. While D can already be determined and is {:ok, true, %{}}, B and C come first and need more data to be loaded, so they can be determined and returned if either is {:ok, true, %{}} first. All data requirements that might be needed are returned together in the result (those of B and C), while those of E can be ruled out, as D already returns {:ok, true, %{}} and comes first.

Summary

Types

b()

Possible return values from conditions.

v()

Possible return values from resolving predicates.

Functions

Returns {:ok, true} if fun evaluates to {:ok, true} for all elements in enum. Otherwise, returns {:not_loaded, data_reqs} if any yield that. Otherwise, returns {:ok, false}.

Returns {:ok, true, binds} if fun evaluates to {:ok, true, binds} for any element in enum. Otherwise, returns {:not_loaded, data_reqs} if any yields that. Otherwise, returns {:ok, false, %{}}.

If ok, binds the result to the given key and returns the updated tuple. Otherwise, returns first argument as is.

Returns the number of elements for which fun evaluates to {:ok, true}. If any elements return {:not_loaded, data_reqs}, returns all of them combined as {:not_loaded, ...}. Otherwise, returns {:ok, default}.

Returns the number of elements before fun evaluates to {:ok, false} or an element is nil. Elements are skipped (not counted) whenever fun evaluates to {:ok, :skip}. If any elements before that return {:not_loaded, data_reqs}, returns all of them combined as {:not_loaded, ...}. Otherwise, returns {:ok, default}.

Returns {:ok, elem} for the first elem for which fun evaluates to {:ok, true}. If any elements before that return {:not_loaded, data_reqs}, returns all of them combined as {:not_loaded, ...}. Otherwise, returns {:ok, default}.

Converts 2-tuples to the internal 3-tuple result format (type t:v() or t:b()).

Returns {:ok, mapped_results, binds} if all elements map to {:ok, result, binds}. Otherwise, returns {:error, e} on error, or {:not_loaded, data_reqs} with all data requirements.

Returns {:ok, new_keyword_list, binds} with new values if all values map to {:ok, new_value, binds}. Otherwise, returns {:error, e} on error, or {:not_loaded, data_reqs} with all data requirements.

Returns {:ok, new_map, binds} with new values if all values map to {:ok, new_value, binds}. Otherwise, returns {:error, e} on error, or {:not_loaded, data_reqs} with all data requirements.

Wraps a value in an :ok result.

When given {:ok, value, binds}, runs fun on value and returns the result. Otherwise, returns first argument as is.

Converts the internal 3-tuple result format (type t:v() or t:b()) to a 2-tuple format.

When given {:ok, value, binds}, runs fun on value and returns {:ok, new_value, binds}. Otherwise, returns first argument as is.

When given {:ok, value, binds} or {:ok, value}, returns value. Otherwise, raises an exception.

Wraps a value in a compatible tuple for use with this module, if it's not wrapped already.

Types

@type b() :: {:ok, boolean(), binds()} | {:not_loaded, any()} | {:error, any()}

Possible return values from conditions.

@type binds() :: %{required(atom()) => any()}
@type v() :: {:ok, any(), binds()} | {:not_loaded, any()} | {:error, any()}

Possible return values from resolving predicates.

Functions

Link to this function

all?(enum, mapper \\ &identity/1)

View Source
@spec all?(Enum.t(), (any() -> b())) :: b()

Returns {:ok, true} if fun evaluates to {:ok, true} for all elements in enum. Otherwise, returns {:not_loaded, data_reqs} if any yield that. Otherwise, returns {:ok, false}.

Examples

iex> [
...>   {:ok, true, %{}},
...>   {:not_loaded, []},
...>   {:ok, false, %{}},
...> ]
...> |> Dx.Result.all?()
{:ok, false, %{}}

iex> [
...>   {:ok, true, %{}},
...>   {:not_loaded, []},
...>   {:ok, true, %{}},
...> ]
...> |> Dx.Result.all?()
{:not_loaded, []}

iex> [
...>   {:ok, true, %{}},
...>   {:ok, true, %{}},
...> ]
...> |> Dx.Result.all?()
{:ok, true, %{}}
Link to this function

any?(enum, mapper \\ &identity/1)

View Source
@spec any?(Enum.t(), (any() -> b())) :: b()

Returns {:ok, true, binds} if fun evaluates to {:ok, true, binds} for any element in enum. Otherwise, returns {:not_loaded, data_reqs} if any yields that. Otherwise, returns {:ok, false, %{}}.

Examples

iex> [
...>   {:ok, true, %{a: 1}},
...>   {:not_loaded, []},
...>   {:ok, false, %{}},
...> ]
...> |> Dx.Result.any?()
{:ok, true, %{a: 1}}

iex> [
...>   {:ok, false, %{}},
...>   {:not_loaded, []},
...>   {:ok, false, %{}},
...> ]
...> |> Dx.Result.any?()
{:not_loaded, []}

iex> [
...>   {:ok, false, %{}},
...>   {:ok, false, %{}},
...> ]
...> |> Dx.Result.any?()
{:ok, false, %{}}

If ok, binds the result to the given key and returns the updated tuple. Otherwise, returns first argument as is.

Link to this function

count(enum, fun \\ &identity/1)

View Source
@spec count(Enum.t(), (any() -> v())) :: v()

Returns the number of elements for which fun evaluates to {:ok, true}. If any elements return {:not_loaded, data_reqs}, returns all of them combined as {:not_loaded, ...}. Otherwise, returns {:ok, default}.

Examples

iex> [
...>   {:ok, true, %{}},
...>   {:ok, false, %{}},
...>   {:ok, true, %{}},
...> ]
...> |> Dx.Result.count()
{:ok, 2, %{}}

iex> [
...>   {:ok, false, %{}},
...>   {:not_loaded, [1]},
...>   {:not_loaded, [2]},
...>   {:ok, true, %{}},
...>   {:not_loaded, [3]},
...> ]
...> |> Dx.Result.count()
{:not_loaded, [1, 2, 3]}

iex> [
...>   {:ok, true, %{}},
...>   {:ok, :skip, %{}},
...>   {:ok, false, %{}},
...>   {:ok, false, %{}},
...> ]
...> |> Dx.Result.count()
{:ok, 1, %{}}

iex> [
...>   false,
...>   false,
...> ]
...> |> Dx.Result.count(&{:ok, not &1, %{}})
{:ok, 2, %{}}
Link to this function

count_while(enum, fun \\ &identity/1)

View Source
@spec count_while(Enum.t(), (any() -> v())) :: v()

Returns the number of elements before fun evaluates to {:ok, false} or an element is nil. Elements are skipped (not counted) whenever fun evaluates to {:ok, :skip}. If any elements before that return {:not_loaded, data_reqs}, returns all of them combined as {:not_loaded, ...}. Otherwise, returns {:ok, default}.

Examples

iex> [
...>   {:ok, true, %{}},
...>   {:not_loaded, []},
...>   {:ok, false, %{}},
...> ]
...> |> Dx.Result.count_while()
{:not_loaded, []}

iex> [
...>   {:ok, false, %{}},
...>   {:not_loaded, [1]},
...>   {:not_loaded, [2]},
...>   {:ok, true, %{}},
...>   {:not_loaded, [3]},
...> ]
...> |> Dx.Result.count_while()
{:ok, 0, %{}}

iex> [
...>   {:ok, true, %{}},
...>   {:ok, :skip, %{}},
...>   {:ok, false, %{}},
...>   {:ok, false, %{}},
...> ]
...> |> Dx.Result.count_while()
{:ok, 1, %{}}

iex> [
...>   false,
...>   false,
...> ]
...> |> Dx.Result.count_while(&{:ok, not &1, %{}})
{:ok, 2, %{}}
Link to this function

filter_map(enum, fun \\ &identity/1, result_mapper \\ &ok/2)

View Source
Link to this function

find(enum, fun \\ &identity/1, result_mapper \\ &ok/2, default \\ ok(nil))

View Source
@spec find(Enum.t(), (any() -> b()), (any() -> any()), any()) :: v()

Returns {:ok, elem} for the first elem for which fun evaluates to {:ok, true}. If any elements before that return {:not_loaded, data_reqs}, returns all of them combined as {:not_loaded, ...}. Otherwise, returns {:ok, default}.

Examples

iex> [
...>   {:ok, true, %{}},
...>   {:not_loaded, []},
...>   {:ok, false, %{}},
...> ]
...> |> Dx.Result.find()
{:ok, {:ok, true, %{}}, %{}}

iex> [
...>   {:ok, false, %{}},
...>   {:not_loaded, [1]},
...>   {:not_loaded, [2]},
...>   {:ok, true, %{}},
...>   {:not_loaded, [3]},
...> ]
...> |> Dx.Result.find()
{:not_loaded, [1, 2]}

iex> [
...>   {:ok, false, %{}},
...>   {:ok, false, %{}},
...> ]
...> |> Dx.Result.find()
{:ok, nil, %{}}

iex> [
...>   false,
...>   false,
...> ]
...> |> Dx.Result.find(&{:ok, not &1, %{}})
{:ok, false, %{}}

Converts 2-tuples to the internal 3-tuple result format (type t:v() or t:b()).

Examples

iex> {:ok, 5}
...> |>Dx.Result.from_simple()
{:ok, 5, %{}}

iex> {:error, :err}
...> |>Dx.Result.from_simple()
{:error, :err}
Link to this function

map(enum, mapper \\ &identity/1)

View Source
@spec map(Enum.t(), (any() -> v())) :: v()

Returns {:ok, mapped_results, binds} if all elements map to {:ok, result, binds}. Otherwise, returns {:error, e} on error, or {:not_loaded, data_reqs} with all data requirements.

Examples

iex> [
...>   {:ok, 1, %{}},
...>   {:ok, 2, %{}},
...>   {:ok, 3, %{}},
...> ]
...> |> Dx.Result.map()
{:ok, [1, 2, 3], %{}}

iex> [
...>   {:ok, 1, %{}},
...>   {:not_loaded, [:x]},
...>   {:ok, 3, %{}},
...>   {:not_loaded, [:y]},
...> ]
...> |> Dx.Result.map()
{:not_loaded, [:x, :y]}

iex> [
...>   {:ok, 1, %{}},
...>   {:error, :x},
...>   {:ok, 3, %{}},
...>   {:not_loaded, [:y]},
...> ]
...> |> Dx.Result.map()
{:error, :x}
Link to this function

map_keyword_values(enum, mapper \\ &identity/1)

View Source

Returns {:ok, new_keyword_list, binds} with new values if all values map to {:ok, new_value, binds}. Otherwise, returns {:error, e} on error, or {:not_loaded, data_reqs} with all data requirements.

Examples

iex> [
...>   a: {:ok, 1, %{}},
...>   b: {:ok, 2, %{}},
...>   c: {:ok, 3, %{}},
...> ]
...> |> Dx.Result.map_keyword_values()
{:ok, [a: 1, b: 2, c: 3], %{}}

iex> [
...>   a: {:ok, 1, %{}},
...>   b: {:not_loaded, MapSet.new([:x])},
...>   c: {:ok, 3, %{}},
...>   d: {:not_loaded, MapSet.new([:y])},
...> ]
...> |> Dx.Result.map_keyword_values()
{:not_loaded, MapSet.new([:x, :y])}

iex> [
...>   a: {:ok, 1, %{}},
...>   b: {:error, :x},
...>   c: {:ok, 3, %{}},
...>   d: {:not_loaded, [:y]},
...> ]
...> |> Dx.Result.map_keyword_values()
{:error, :x}
Link to this function

map_values(enum, mapper \\ &identity/1)

View Source

Returns {:ok, new_map, binds} with new values if all values map to {:ok, new_value, binds}. Otherwise, returns {:error, e} on error, or {:not_loaded, data_reqs} with all data requirements.

Examples

iex> %{
...>   a: {:ok, 1, %{}},
...>   b: {:ok, 2, %{}},
...>   c: {:ok, 3, %{}},
...> }
...> |> Dx.Result.map_values()
{:ok, %{a: 1, b: 2, c: 3}, %{}}

iex> %{
...>   a: {:ok, 1, %{}},
...>   b: {:not_loaded, MapSet.new([:x])},
...>   c: {:ok, 3, %{}},
...>   d: {:not_loaded, MapSet.new([:y])},
...> }
...> |> Dx.Result.map_values()
{:not_loaded, MapSet.new([:x, :y])}

iex> %{
...>   a: {:ok, 1, %{}},
...>   b: {:error, :x},
...>   c: {:ok, 3, %{}},
...>   d: {:not_loaded, [:y]},
...> }
...> |> Dx.Result.map_values()
{:error, :x}

Wraps a value in an :ok result.

When given {:ok, value, binds}, runs fun on value and returns the result. Otherwise, returns first argument as is.

Converts the internal 3-tuple result format (type t:v() or t:b()) to a 2-tuple format.

Examples

iex> {:ok, 5, %{}}
...> |>Dx.Result.to_simple()
{:ok, 5}

iex> {:error, :err}
...> |>Dx.Result.to_simple()
{:error, :err}
Link to this function

to_simple_if(other, arg2)

View Source

When given {:ok, value, binds}, runs fun on value and returns {:ok, new_value, binds}. Otherwise, returns first argument as is.

When given {:ok, value, binds} or {:ok, value}, returns value. Otherwise, raises an exception.

Examples

iex> Dx.Result.unwrap!({:error, %ArgumentError{}})
** (ArgumentError) argument error

iex> Dx.Result.unwrap!({:error, :not_an_exception})
** (Dx.Error.Generic) Error occurred: :not_an_exception

Wraps a value in a compatible tuple for use with this module, if it's not wrapped already.