lib/plugin_manager/database/plugin.ex

defmodule MishkaInstaller.Plugin do

  alias MishkaInstaller.Database.PluginSchema
  alias MishkaInstaller.PluginState
  import Ecto.Query
  use MishkaDeveloperTools.DB.CRUD,
          module: PluginSchema,
          error_atom: :plugin,
          repo: MishkaInstaller.repo

  @type data_uuid() :: Ecto.UUID.t
  @type record_input() :: map()
  @type error_tag() :: :plugin
  @type repo_data() :: Ecto.Schema.t()
  @type repo_error() :: Ecto.Changeset.t()

  @behaviour MishkaDeveloperTools.DB.CRUD

  @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_add, 1}
  def create(attrs) do
    crud_add(attrs)
  end

  @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_add, 1}
  def create(attrs, allowed_fields) do
    crud_add(attrs, allowed_fields)
  end

  @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_edit, 1}
  def edit(attrs) do
    crud_edit(attrs)
  end

  @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_edit, 1}
  def edit(attrs, allowed_fields) do
    crud_edit(attrs, allowed_fields)
  end

  @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_delete, 1}
  def delete(id) do
    crud_delete(id)
  end

  @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_get_record, 1}
  def show_by_id(id) do
    crud_get_record(id)
  end

  @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_get_by_field, 2}
  def show_by_name(name) do
    crud_get_by_field("name", name)
  end

  def add_or_edit_by_name(state) do
    case show_by_name("#{state.name}") do
      {:ok, :get_record_by_field, :plugin, repo_data} -> edit(state |> Map.merge(%{id: repo_data.id}))
      _ -> create(state)
    end
  end

  def plugins(event: event) do
    from(plg in PluginSchema, where: plg.event == ^event)
    |> fields()
    |> MishkaInstaller.repo.all()
    |> Enum.map(&struct(PluginState, &1))
  end

  def plugins() do
    from(plg in PluginSchema)
    |> fields()
    |> MishkaInstaller.repo.all()
    |> Enum.map(&struct(PluginState, &1))
  end

  defp fields(query) do
    from [plg] in query,
    order_by: [desc: plg.inserted_at, desc: plg.id],
    select: %{
      name: plg.name,
      event: plg.event,
      priority: plg.priority,
      status: plg.status,
      depend_type: plg.depend_type,
      depends: plg.depends
    }
  end

  def delete_plugins(event) do
    stream = MishkaInstaller.repo.stream(from(plg in PluginSchema))
    MishkaInstaller.repo.transaction(fn() ->
      stream
      |> Stream.filter(&(event in &1.depends))
      |> Enum.to_list()
    end)
    |> case do
      {:ok, []} -> []
      {:ok, list} ->
        list
        |> Task.async_stream(&MishkaInstaller.Hook.unregister(module: &1.name), max_concurrency: 20)
        |> Stream.run
      error ->
        IO.inspect(error)
    end
  end
end