View Source Bonfire.Common.Utils (Bonfire v0.9.10-classic-beta.169)
Various very commonly used utility functions for the Bonfire application.
This module should contain only a few generic and/or heavily-used functions, and any other functions should be in more specific modules (or in other extensions altogether) for e.g.:
Bonfire.Common.Enums
for functions around maps, structs, keyword lists, and the likeBonfire.Common.Types
for object typesBonfire.Common.URIs
andLinkify
for URI handlingBonfire.Common.DatesTimes
for date/time helpersBonfire.Common.E
to extract nested data from an objectBonfire.Common.Errors
andBonfire.Fail
for error handlingBonfire.Common.Extend
for functions around modularityBonfire.Common.Opts
for handling function optionsBonfire.Common.Config
for handling app-wide configBonfire.Common.Settings
for handling account/user/instance level settingsBonfire.Common.HTTP
for HTTP requestsBonfire.Common.Cache
for cachingBonfire.Common.Text
for plain or rich textBonfire.Common.Localise
for app localisationBonfire.Common.Media
andBonfire.Files
for avatars/images/videos/etcBonfire.Common.Repo
andNeedle
for database accessBonfire.Common.PubSub
for pub/sub
We may also want to consider reusing functions from existing utils libraries when possible and contributing missing ones there, for example:
Summary
Functions
Runs a function asynchronously in a Task. Simply a shorthand for calling functions in Task
and Task.Supervisor
but with support for multi-tenancy in the spawned process.
Runs a function asynchronously using Task.Supervisor
. This is similar to apply_task/3
but specifically uses Task.Supervisor
for supervision.
Returns the current account from socket, assigns, or options.
Returns a list of current account IDs and/or user IDs.
(Re)authenticates the current account using the provided password.
Returns the current account ID from socket, assigns, or options.
Returns the current user from socket, assigns, or options.
(Re)authenticates the current user using the provided password.
Returns the current user ID from socket, assigns, or options.
Ensures that the current user is present and raises an exception if not logged in.
Callback implementation for Bonfire.Common.ExtensionModule.declared_extension/0
.
Checks if the given value is nil
, an empty enumerable, or an empty string.
Applies the given function if the first parameter is not nil
.
Helper for calling hypothetical functions another modules.
Returns the value of a key from options keyword list or map, or a fallback if not present or empty.
Checks if the given value is nil
, false
, 0
, or an empty value (using empty?/1
).
Unwraps an {:ok, val}
tuple, returning the value. If not OK, returns a fallback value (default is nil
).
Rounds a number and uses Bonfire.Common.Localise.Cldr.Number.to_string/2
function to format into a human readable string.
Rounds a number to the nearest specified target.
Converts a map, user, socket, tuple, etc, to a keyword list for standardised use as function options.
Functions
Runs a function asynchronously in a Task. Simply a shorthand for calling functions in Task
and Task.Supervisor
but with support for multi-tenancy in the spawned process.
Task.async/1
the caller creates a new process links and monitors it. Once the task action finishes, a message is sent to the caller with the result.Task.await/2
is used to read the message sent by the task. When usingasync
, you mustawait
a reply as they are always sent.Task.start_link/1
is suggested instead if you are not expecting a reply. It starts a statically supervised task as part of a supervision tree, linked to the calling process (meaning it will be stopped when the caller stops).Task.start/1
can be used for fire-and-forget tasks, like side-effects, when you have no interest on its results nor if it completes successfully (because if the server is shut down it won't be restarted).
For more serious tasks, consider using Oban
or apply_task_supervised/3
for supervised tasks when possible:
Task.Supervisor.start_child/2
allows you to start a fire-and-forget task when you don't care about its results or if it completes successfully or not.Task.Supervisor.async/2
+Task.await/2
allows you to execute tasks concurrently and retrieve its result. If the task fails, the caller will also fail.
Parameters
function
: The type of task to start (e.g.:async
,:start_link
, or:start
).fun
: The function to execute async.opts
: Options for task execution, including::module
- The module to use for task execution (defaults toTask
).
Examples
> apply_task(:async, fn -> IO.puts("Async task") end)
# Output: "Async task"
> {apply_task(:start, fn -> IO.puts("Fire-and-forget task") end)
# Output: "Fire-and-forget task"
> apply_task(:start_link, fn -> IO.puts("Supervised task") end)
# Output: "Supervised task"
Runs a function asynchronously using Task.Supervisor
. This is similar to apply_task/3
but specifically uses Task.Supervisor
for supervision.
Parameters
module
: The supervisor module to use for task executionfun
: The function to execute asyncopts
: Options for task execution, including::function
- TheTask.Supervisor
function to use for task execution (defaults to:async
).
Examples
> apply_task_supervised(MySupervisor, fn -> IO.puts("Supervised async task") end)
** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
# because `MySupervisor` is not defined and/or started ^
current_account(current_account_or_socket_or_opts, recursing \\ false)
View SourceReturns the current account from socket, assigns, or options.
This function traverses various possible structures to find and return the current account.
Examples
iex> Bonfire.Common.Utils.current_account(%{current_account: %{id: "account1"}})
%{id: "account1"}
iex> Bonfire.Common.Utils.current_account(%{assigns: %{current_account: %{id: "account2"}}})
%{id: "account2"}
iex> Bonfire.Common.Utils.current_account(%{socket: %{assigns: %{current_account: %{id: "account3"}}}})
%{id: "account3"}
iex> Bonfire.Common.Utils.current_account([current_account: %{id: "account4"}])
%{id: "account4"}
Returns a list of current account IDs and/or user IDs.
This function returns a keyword list with the current account IDs and/or user IDs.
Examples
iex> Bonfire.Common.Utils.current_account_and_or_user_ids(%{current_account_id: "2CC0VNTSARE1S01AT10NGR0VPS", current_user_id: "5EVSER1S0STENS1B1YHVMAN01D"})
[account: "2CC0VNTSARE1S01AT10NGR0VPS", user: "5EVSER1S0STENS1B1YHVMAN01D"]
iex> Bonfire.Common.Utils.current_account_and_or_user_ids(%{current_account: %{id: "2CC0VNTSARE1S01AT10NGR0VPS"}, current_user: %{id: "5EVSER1S0STENS1B1YHVMAN01D"}})
[account: "2CC0VNTSARE1S01AT10NGR0VPS", user: "5EVSER1S0STENS1B1YHVMAN01D"]
iex> Bonfire.Common.Utils.current_account_and_or_user_ids(%{current_account_id: "2CC0VNTSARE1S01AT10NGR0VPS"})
[account: "2CC0VNTSARE1S01AT10NGR0VPS"]
iex> Bonfire.Common.Utils.current_account_and_or_user_ids(%{current_user_id: "5EVSER1S0STENS1B1YHVMAN01D"})
[user: "5EVSER1S0STENS1B1YHVMAN01D"]
iex> Bonfire.Common.Utils.current_account_and_or_user_ids(%{})
[]
(Re)authenticates the current account using the provided password.
Raises an exception if the credentials are invalid.
Examples
> Bonfire.Common.Utils.current_account_auth!(%{current_account: %{id: "2CC0VNTSARE1S01AT10NGR0VPS"}}, "wrong-password")
** (Bonfire.Fail.Auth) We couldn't find an account with the details you provided.
current_account_id(current_account_or_socket_or_opts, recursing \\ false)
View SourceReturns the current account ID from socket, assigns, or options.
This function traverses various possible structures to find and return the current account ID.
Examples
iex> Bonfire.Common.Utils.current_account_id(%{current_account_id: "2CC0VNTSARE1S01AT10NGR0VPS"})
"2CC0VNTSARE1S01AT10NGR0VPS"
iex> Bonfire.Common.Utils.current_account_id(%{assigns: %{current_account_id: "2CC0VNTSARE1S01AT10NGR0VPS"}})
"2CC0VNTSARE1S01AT10NGR0VPS"
iex> Bonfire.Common.Utils.current_account_id(%{socket: %{assigns: %{current_account_id: "2CC0VNTSARE1S01AT10NGR0VPS"}}})
"2CC0VNTSARE1S01AT10NGR0VPS"
iex> Bonfire.Common.Utils.current_account_id("2CC0VNTSARE1S01AT10NGR0VPS")
"2CC0VNTSARE1S01AT10NGR0VPS"
Returns the current user from socket, assigns, or options.
This function traverses various possible structures to find and return the current user (or current user ID if that's all that's available).
Examples
iex> Bonfire.Common.Utils.current_user(%{current_user: %{id: "user1"}})
%{id: "user1"}
iex> Bonfire.Common.Utils.current_user(%{assigns: %{current_user: %{id: "user2"}}})
%{id: "user2"}
iex> Bonfire.Common.Utils.current_user(%{socket: %{assigns: %{current_user: %{id: "user3"}}}})
%{id: "user3"}
iex> Bonfire.Common.Utils.current_user([current_user: %{id: "user4"}])
%{id: "user4"}
iex> Bonfire.Common.Utils.current_user(%{current_user_id: "5EVSER1S0STENS1B1YHVMAN01D"})
"5EVSER1S0STENS1B1YHVMAN01D"
(Re)authenticates the current user using the provided password.
Raises an exception if the credentials are invalid.
Examples
> Bonfire.Common.Utils.current_user_auth!(%{current_user: %{id: "user1"}}, "password123")
** (Bonfire.Fail.Auth) We couldn't find an account with the details you provided.
current_user_id(current_user_or_socket_or_opts, recursing \\ false)
View SourceReturns the current user ID from socket, assigns, or options.
This function traverses various possible structures to find and return the current user ID.
Examples
iex> Bonfire.Common.Utils.current_user_id(%{current_user_id: "5EVSER1S0STENS1B1YHVMAN01D"})
"5EVSER1S0STENS1B1YHVMAN01D"
iex> Bonfire.Common.Utils.current_user_id(%{assigns: %{current_user_id: "5EVSER1S0STENS1B1YHVMAN01D"}})
"5EVSER1S0STENS1B1YHVMAN01D"
iex> Bonfire.Common.Utils.current_user_id(%{assigns: %{__context__: %{current_user_id: "5EVSER1S0STENS1B1YHVMAN01D"}}})
"5EVSER1S0STENS1B1YHVMAN01D"
iex> Bonfire.Common.Utils.current_user_id("5EVSER1S0STENS1B1YHVMAN01D")
"5EVSER1S0STENS1B1YHVMAN01D"
iex> Bonfire.Common.Utils.current_user_id("invalid id")
nil
Ensures that the current user is present and raises an exception if not logged in.
Examples
iex> Bonfire.Common.Utils.current_user_required!(%{current_user: %{id: "user1"}})
%{id: "user1"}
> Bonfire.Common.Utils.current_user_required!(%{})
** (Bonfire.Fail.Auth) You need to log in first.
Callback implementation for Bonfire.Common.ExtensionModule.declared_extension/0
.
Checks if the given value is nil
, an empty enumerable, or an empty string.
Parameters
v
: The value to check.
Examples
iex> empty?(nil)
true
iex> empty?("")
true
iex> empty?([])
true
iex> empty?([1, 2, 3])
false
iex> empty?("hello")
false
Applies the given function if the first parameter is not nil
.
Parameters
val
: The value to check.change_fn
: A function to apply ifval
is notnil
.
Examples
iex> maybe(nil, fn x -> x * 2 end)
nil
iex> maybe(3, fn x -> x * 2 end)
6
Helper for calling hypothetical functions another modules.
Attempts to apply a function from a specified module with the given arguments and returns the result.
Returns an error if the function is not defined, unless a fallback function was provided to be invoked, or a fallback value to be returned.
Parameters
module
: The module to check for the function.funs
: A list of function names (atoms) to try.args
: Arguments to pass to the function.opts
: Options for error handling and fallback. Options include::fallback_fun
- A function to call if the primary function is not found.:fallback_return
- A default return value if the function cannot be applied.
Examples
iex> maybe_apply(Enum, :map, [[1, 2, 3], &(&1 * 2)])
[2, 4, 6]
iex> maybe_apply(Enum, [:nonexistent_fun], [])
{:error, "None of the functions [:nonexistent_fun] are defined at Elixir.Enum with arity 0"}
iex> maybe_apply(Enum, [:nonexistent_fun], [], fallback_fun: fn error, _args, _opts -> raise "Failed" end)
** (RuntimeError) Failed
iex> maybe_apply(SomeModule, [:some_fun], [1, 2, 3], fallback_return: "Failed")
# Output: [warning] maybe_apply: No such module (Elixir.SomeModule) could be loaded. - with args: ([1, 2, 3])
"Failed"
Returns the value of a key from options keyword list or map, or a fallback if not present or empty.
Checks if the given value is nil
, false
, 0
, or an empty value (using empty?/1
).
Parameters
v
: The value to check.
Examples
iex> nothing?(nil)
true
iex> nothing?(false)
true
iex> nothing?(0)
true
iex> nothing?("")
true
iex> nothing?([1, 2, 3])
false
iex> nothing?("hello")
false
Unwraps an {:ok, val}
tuple, returning the value. If not OK, returns a fallback value (default is nil
).
Parameters
val
: The value or tuple to unwrap.fallback
: The fallback value if the tuple is an error.
Examples
iex> ok_unwrap({:ok, 42})
42
iex> ok_unwrap({:error, "something went wrong"}, "default")
"default"
iex> ok_unwrap(:error, "default")
"default"
iex> ok_unwrap(nil, "default")
"default"
Rounds a number and uses Bonfire.Common.Localise.Cldr.Number.to_string/2
function to format into a human readable string.
Examples
iex> round_nearest(1234)
"1K"
iex> round_nearest(1600000)
"2M"
Rounds a number to the nearest specified target.
Parameters
num
: The number to round.target
: The target to round to (optional).
Examples
iex> round_nearest(1234, 10)
1230
iex> round_nearest(1234, 100)
1200
iex> round_nearest(1234, 1000)
1000
Converts a map, user, socket, tuple, etc, to a keyword list for standardised use as function options.