defmodule Silmataivas.Release do @moduledoc """ Release tasks for Silmataivas application. This module provides functions to run Ecto migrations in a compiled release, supporting both SQLite and PostgreSQL backends. """ @app :silmataivas @doc """ Creates a new user with optional user ID and role. ## Parameters * `user_id` - An optional user ID to use. If not provided, a UUID will be generated. * `role` - An optional role, must be either "user" or "admin". Defaults to "user". ## Examples Silmataivas.Release.new_user() Silmataivas.Release.new_user("custom_user_id") Silmataivas.Release.new_user("custom_user_id", "admin") """ def new_user(user_id \\ nil, role \\ "user") do # Create the new user load_app() start_repos() # Validate role unless role in ["user", "admin"] do IO.puts("\n❌ Invalid role: #{role}. Role must be either \"user\" or \"admin\".") exit({:shutdown, 1}) end user_id = user_id || Ecto.UUID.generate() user_params = %{user_id: user_id, role: role} case Silmataivas.Users.create_user(user_params) do {:ok, user} -> IO.puts("\n✅ User created successfully!") IO.puts(" User ID (API token): #{user.user_id}") IO.puts(" Role: #{user.role}") {:error, changeset} -> IO.puts("\n❌ Failed to create user:") IO.inspect(changeset.errors) end end def migrate do load_app() for repo <- repos() do {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true)) end end def rollback(repo, version) do load_app() {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version)) end def create_db do load_app() for repo <- repos() do # Create the database if it doesn't exist adapter = get_repo_adapter(repo) case adapter.storage_up(repo.config()) do :ok -> IO.puts("Database for #{inspect(repo)} created successfully") {:error, :already_up} -> IO.puts("Database for #{inspect(repo)} already exists") {:error, reason} -> IO.warn("Database for #{inspect(repo)} failed to create: #{inspect(reason)}") end end end def setup do # Create the database and then run migrations create_db() migrate() end def db_info do load_app() for repo <- repos() do adapter = get_repo_adapter(repo) config = repo.config() IO.puts("Repository: #{inspect(repo)}") IO.puts("Adapter: #{inspect(adapter)}") case adapter do Ecto.Adapters.SQLite3 -> db_path = config[:database] || "default.db" IO.puts("Database path: #{db_path}") Ecto.Adapters.Postgres -> hostname = config[:hostname] || "localhost" database = config[:database] || "default" IO.puts("Host: #{hostname}, Database: #{database}") _ -> IO.puts("Config: #{inspect(config)}") end IO.puts("---") end end defp get_repo_adapter(repo) do repo.config()[:adapter] end defp start_repos do {:ok, _} = Application.ensure_all_started(:ecto_sql) for repo <- repos() do {:ok, _} = repo.start_link(pool_size: 2) end end defp repos do Application.fetch_env!(@app, :ecto_repos) end defp load_app do Application.load(@app) end end