Skip to main content

lib/mix/tasks/continuum.partitions.list.ex

defmodule Mix.Tasks.Continuum.Partitions.List do
  @moduledoc """
  Lists managed `continuum_events` partitions and their row counts.

      mix continuum.partitions.list
      mix continuum.partitions.list --repo MyApp.Repo
  """
  use Mix.Task

  @shortdoc "Lists continuum_events partitions"

  @impl true
  def run(args) do
    {opts, _, _} = OptionParser.parse(args, switches: [repo: :string])
    Mix.Task.run("app.start")

    repo = parse_repo(opts)

    repo
    |> partitions()
    |> Enum.each(fn partition ->
      %{rows: [[count]]} = repo.query!("SELECT count(*) FROM #{quote_ident(partition)}")
      Mix.shell().info("#{partition}\t#{count}")
    end)
  end

  defp partitions(repo) do
    %{rows: rows} =
      repo.query!("""
      SELECT c.relname
      FROM pg_inherits i
      JOIN pg_class c ON c.oid = i.inhrelid
      JOIN pg_class p ON p.oid = i.inhparent
      WHERE p.relname = 'continuum_events'
      ORDER BY c.relname
      """)

    Enum.map(rows, fn [name] -> name end)
  end

  defp parse_repo(opts) do
    case opts[:repo] do
      nil ->
        Application.get_env(:continuum, :repo) ||
          Mix.raise("no repo configured. Pass --repo MyApp.Repo or set :continuum, :repo")

      repo ->
        Module.concat([repo])
    end
  end

  defp quote_ident(name), do: ~s("#{String.replace(name, ~s("), ~s(""))}")
end