One of my teams with a .NET background has recently started working with Elixir. In c#, you have the concept of an extension method that allows you to extend an object’s methods without changing its code. I believe familiarity with this concept is causing the team to introduce a bunch of utility modules. Here are some examples:
defmodule EctoUtil do
import Ecto.Query
@doc """
Filters the id from the query if the id is not nil
"""
def maybe_exclude(query, nil), do: query
def maybe_exclude(query, %{id: nil}), do: query
def maybe_exclude(query, %{id: id}), do: query |> where([x], x.id != ^id)
end
defmodule MapUtil do
@doc """
Gets an element from a map by the key. Converts the key to or from an atom and tries again if no element is found.
"""
def get(map, key, default \\ nil)
def get(map, key, default) when is_map(map) and is_atom(key) do
Map.get(map, key, Map.get(map, to_string(key), default))
end
def get(map, key, default) when is_map(map) and is_binary(key) do
Map.get(map, key, Map.get(map, String.to_atom(key), default))
end
end
defmodule ChangesetUtil do
import Ecto.Changeset
def validate_unique(changeset, fields, constraint_name, message, query \\ nil) do
opts = [message: message, nulls_distinct: false]
opts = if query != nil, do: Keyword.put(opts, :query, query), else: opts
changeset
|> unsafe_validate_unique(fields, My.Repo, opts)
|> unique_constraint(:name,
name: constraint_name,
message: message
)
end
end
I have two questions really.
- What do we think about these specific utility functions?
- What is the general Elixir community consensus on utility modules?