defmodule MishkaInstaller.Dependency do @moduledoc """ This module is for communication with `Dependencies` table and has essential functions such as adding, editing, deleting, and displaying. This module is related to module `MishkaInstaller.Database.DependencySchema`. """ alias MishkaInstaller.Database.DependencySchema alias MishkaInstaller.Installer.DepHandler import Ecto.Query use MishkaDeveloperTools.DB.CRUD, module: DependencySchema, error_atom: :dependency, repo: MishkaInstaller.repo() @behaviour MishkaDeveloperTools.DB.CRUD @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_add, 1} def create(attrs) do crud_add(attrs) |> notify_subscribers(:dependency) end @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_add, 1} def create(attrs, allowed_fields) do crud_add(attrs, allowed_fields) |> notify_subscribers(:dependency) end @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_edit, 1} def edit(attrs) do crud_edit(attrs) |> notify_subscribers(:dependency) end @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_edit, 1} def edit(attrs, allowed_fields) do crud_edit(attrs, allowed_fields) |> notify_subscribers(:dependency) end @doc delegate_to: {MishkaDeveloperTools.DB.CRUD, :crud_delete, 1} def delete(id) do crud_delete(id) |> notify_subscribers(:dependency) 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(app) do crud_get_by_field("app", app) end @doc """ This is an aggregation function that includes editing or adding. """ @spec create_or_update(map()) :: tuple() def create_or_update(data) do case show_by_name(data.app) do {:error, :get_record_by_field, :dependency} -> create(data) {:ok, :get_record_by_field, :dependency, record_info} -> if Version.compare(data.version, record_info.version) == :gt do update_app_version(record_info.id, data) else {:error, :update_app_version, :older_version} end end end @doc """ Show all dependencies. """ def dependencies() do from(dep in DependencySchema) |> fields() |> MishkaInstaller.repo().all() end def dependencies(:struct) do dependencies() |> Enum.map(&struct(DepHandler, &1)) end @doc """ This is an aggregation function that includes editing a type of app. """ @spec change_dependency_type_with_app(String.t(), String.t()) :: {:ok, :change_dependency_type_with_app, map()} | {:error, :change_dependency_type_with_app, :dependency, atom() | map()} def change_dependency_type_with_app(app, dependency_type) do with {:ok, :get_record_by_field, :dependency, record_info} <- MishkaInstaller.Dependency.show_by_name(app), {:ok, :edit, :dependency, repo_data} <- MishkaInstaller.Dependency.edit(%{ "id" => record_info.id, "dependency_type" => dependency_type }) do {:ok, :change_dependency_type_with_app, repo_data} else {:error, :get_record_by_field, :dependency} -> {:error, :change_dependency_type_with_app, :dependency, :not_found} {:error, :edit, action, :dependency} when action in [:uuid, :get_record_by_id] -> {:error, :change_dependency_type_with_app, :dependency, :not_found} {:error, :edit, :dependency, repo_error} -> {:error, :change_dependency_type_with_app, :dependency, repo_error} end end defp fields(query) do from([dep] in query, order_by: [desc: dep.inserted_at, desc: dep.id], select: %{ id: dep.id, app: dep.app, version: dep.version, type: dep.type, url: dep.url, git_tag: dep.git_tag, custom_command: dep.custom_command, dependency_type: dep.dependency_type, dependencies: dep.dependencies } ) end @doc """ If you want to get the latest changes from the `Dependencies` table of your database, this function can help you to be subscribed. """ def subscribe do Phoenix.PubSub.subscribe( MishkaInstaller.get_config(:pubsub) || MishkaInstaller.PubSub, "dependency" ) end if Mix.env() == :test do defp notify_subscribers(params, _type_send), do: params else defp notify_subscribers({:ok, action, :dependency, repo_data} = params, type_send) do Phoenix.PubSub.broadcast( MishkaInstaller.get_config(:pubsub) || MishkaInstaller.PubSub, "dependency", {:ok, type_send, action, repo_data} ) params end defp notify_subscribers(params, _), do: params end defp convert_map_from_atom_to_string(map) do for {key, val} <- map, into: %{} do {to_string(key), to_string(val)} end end defp update_app_version(id, data) do crud_edit( Map.merge(convert_map_from_atom_to_string(data), %{ "id" => id, "dependency_type" => "force_update" }) ) end end