Function with default arguments and explicitly declared clauses

Updated Solution

I think I have a better understanding on how Keywords can be passed in as function arguments and the benefits. In my original post I was rigid in having my function arguments be in a specific order and named.

But the new solution I think is more idiomatic. I am much happier and learned quite a lot in this thread.

New Approach

defmodule Example do

  @doc """
  Does a lookup

  ## Example

    iex> Example.lookup("a")

    iex> Example.lookup("a", date: "20230131")

    iex> Example.lookup("a", date: "20230131", place_id: "b")

    iex> Example.lookup("a", date: "20230131", place_id: "b", direction_id: :internal)

  """

  def lookup(id, opts \\ []) do
    defaults = [date: today_string()]
    opts = Keywords.merge(defaults, opts)

    results = QuerySomeDB.get(id, opts[:date]) # some querying would happen
    do_lookup(results, opts)
  end

  defp do_lookup(results, opts) do
    place_id   = opts[:place_id]
    company_id = opts[:company_id]

    results = if place_id, do: filter_by_place_id(results, place_id), else: results
    results = if company_id, do: filter_by_company_id(results, place_id), else: results

    results
end

 defp filter_by_place_id(results, place_id) do
    # ... do some filtering and return the new results
    results
 end

 defp filter_by_company_id(results, company_id) when company_id in [:internal, :external] do
    # ... do some filtering and return the new results
    results
  end

 defp today_string() do
    #... returns a date string
 end

end