lib/archeometer/analysis/apps_xref.ex

defmodule Archeometer.Analysis.Apps.Xref do
  @moduledoc """
  Functions for generating a dependency graph from applications in an Elixir
  project.

  Accepted output formats are "dot" (graphviz), "png" and "mermaid".
  """

  alias Archeometer.Graphs.{Graphviz, Mermaid}
  alias Archeometer.Repo
  import Archeometer.Query

  @supported_formats ["png", "dot", "mermaid", "svg"]

  @doc """
  Creates a dependency graph between the applications of the current project.

  ## Parameters

  - 'format' can be one of "dot" (graphviz), "png", or "mermaid".
  - 'db' is the database path

  ## Returns

  - The binary representing the graph, if the operation was completed successfully.
  - `{:error, reason}` if not.

  """
  def gen_graph(format, db \\ Repo.default_db_name())

  def gen_graph(format, db) when format in @supported_formats do
    do_gen_graph(format, db)
  end

  def gen_graph(_format, _db) do
    {:error, :unsupported_format}
  end

  defp do_gen_graph(format, db) do
    Repo.all(
      from(xref in Archeometer.Schema.AppXRef,
        select: [caller: xref.caller.name, callee: xref.callee.name]
      ),
      [],
      db
    ).rows
    |> Enum.group_by(fn [caller, _] -> caller end, fn [_, callee] -> callee end)
    |> render(format)
  end

  defp render(refs, "dot") do
    Graphviz.render_dot(refs)
  end

  defp render(refs, format) when format in ["png", "svg"] do
    Graphviz.render_image(refs, format)
  end

  defp render(refs, "mermaid") do
    Mermaid.render(refs)
  end
end