ElixirLS Dialyzer says that default value in create_group/1 (i.e. empty map %{}) does not match pattern match in maybe_put_products/2 (i.e. empty list []), so if nothing else is calling maybe_put-products/2 then such clause will never be called.
Here you are trying to catch attrs - not products.
def create_group(attrs \\ %{}) do
%Group{}
|> Group.create_changeset(attrs)
# returns nil if key "products" does not exists in map
|> maybe_put_products(attrs["products"])
|> Repo.insert()
end
# matches when products are not set or when empty list
defp maybe_put_products(changeset, products) when products in [nil, []], do: changeset
# otherwise
defp maybe_put_products(changeset, products) do
products = Products.get_products(products)
Ecto.Changeset.put_assoc(changeset, :products, products)
end
I would rather go with an explicit pattern match on products:
# matches when products are the expected non-empty list
defp maybe_put_products(changeset, %{"products" => products})
when length(products) > 0 do
products = Products.get_products(products)
Ecto.Changeset.put_assoc(changeset, :products, products)
end
# otherwise
defp maybe_put_products(changeset, _), do: changeset
and call it as |> maybe_put_products(attrs) from change_group/1. This is surely a matter of preference, but the latter reads cleaner IMHO.