Skip to content

Commit

Permalink
improvement: prompt for minimum pg version
Browse files Browse the repository at this point in the history
improvement: adjust mix task aliases to be used with `ash_postgres`

closes #391
  • Loading branch information
zachdaniel committed Sep 23, 2024
1 parent 6219e8b commit 0351f52
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 34 deletions.
60 changes: 56 additions & 4 deletions lib/igniter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ defmodule AshPostgres.Igniter do
@moduledoc "Codemods and utilities for working with AshPostgres & Igniter"

@doc false
def default_repo_contents(otp_app) do
def default_repo_contents(otp_app, name, opts \\ []) do
min_pg_version = get_min_pg_version(name, opts)

"""
use AshPostgres.Repo, otp_app: #{inspect(otp_app)}
def min_pg_version do
# Adjust this according to your postgres version
%Version{major: 16, minor: 0, patch: 0}
%Version{major: #{min_pg_version.major}, minor: #{min_pg_version.minor || 0}, patch: #{min_pg_version.patch || 0}}

Check warning on line 12 in lib/igniter.ex

View workflow job for this annotation

GitHub Actions / ash-ci (15) / mix dialyzer

guard_fail

The guard clause can never succeed.

Check warning on line 12 in lib/igniter.ex

View workflow job for this annotation

GitHub Actions / ash-ci (14) / mix dialyzer

guard_fail

The guard clause can never succeed.

Check warning on line 12 in lib/igniter.ex

View workflow job for this annotation

GitHub Actions / ash-ci (16) / mix dialyzer

guard_fail

The guard clause can never succeed.
end
def installed_extensions do
Expand Down Expand Up @@ -80,7 +81,12 @@ defmodule AshPostgres.Igniter do
otp_app = Igniter.Project.Application.app_name(igniter)

igniter =
Igniter.Code.Module.create_module(igniter, repo, default_repo_contents(otp_app))
Igniter.Code.Module.create_module(
igniter,
repo,
default_repo_contents(otp_app, repo),
opts
)

{igniter, repo}
else
Expand Down Expand Up @@ -110,4 +116,50 @@ defmodule AshPostgres.Igniter do
)
end)
end

@doc false
def get_min_pg_version(name, opts) do
if opts[:yes] do
%Version{major: 16, minor: 0, patch: 0}
else
lead_in = """
Generating #{inspect(name)}
What is the minimum postgres version you will be using?
AshPostgres uses this information when generating queries and migrations
to choose the best available features for your version of postgres.
"""

format_request =
"""
Please enter the version in the format major.minor.patch (e.g. 13.4.0)
Default: 16.0.0
"""

prompt =
if opts[:invalid_loop?] do
format_request
else
"#{lead_in}\n\n#{format_request}"
end

prompt
|> String.trim_trailing()
|> Mix.shell().prompt()
|> String.trim()
|> case do
"" -> "16.0.0"
input -> input
end
|> Version.parse()
|> case do
{:ok, version} -> version
:error -> get_min_pg_version(name, Keyword.put(opts, :invalid_loop?, true))
end
end
end
end
8 changes: 2 additions & 6 deletions lib/mix/helpers.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defmodule AshPostgres.Mix.Helpers do
@moduledoc false
def domains!(opts, args, error_on_no_domains? \\ true) do
def domains!(opts, args) do
apps =
if apps_paths = Mix.Project.apps_paths() do
apps_paths |> Map.keys() |> Enum.sort()
Expand Down Expand Up @@ -30,11 +30,7 @@ defmodule AshPostgres.Mix.Helpers do
|> Enum.map(&ensure_compiled(&1, args))
|> case do
[] ->
if error_on_no_domains? do
raise "must supply the --domains argument, or set `config :my_app, ash_domains: [...]` in config"
else
[]
end
[]

domains ->
domains
Expand Down
2 changes: 1 addition & 1 deletion lib/mix/tasks/ash_postgres.generate_migrations.ex
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ defmodule Mix.Tasks.AshPostgres.GenerateMigrations do
]
)

domains = AshPostgres.Mix.Helpers.domains!(opts, args, false)
domains = AshPostgres.Mix.Helpers.domains!(opts, args)

if Enum.empty?(domains) && !opts[:snapshots_only] do
IO.warn("""
Expand Down
110 changes: 90 additions & 20 deletions lib/mix/tasks/ash_postgres.install.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,29 @@ defmodule Mix.Tasks.AshPostgres.Install do
require Igniter.Code.Function
use Igniter.Mix.Task

def igniter(igniter, _argv) do
@impl true
def info(_argv, _source) do
%Igniter.Mix.Task.Info{
schema: [
yes: :boolean
],
aliases: [
y: :yes
]
}
end

@impl true
def igniter(igniter, argv) do
repo = Igniter.Code.Module.module_name(igniter, "Repo")
otp_app = Igniter.Project.Application.app_name(igniter)

opts = options!(argv)

igniter
|> Igniter.Project.Formatter.import_dep(:ash_postgres)
|> setup_repo_module(otp_app, repo)
|> setup_aliases()
|> setup_repo_module(otp_app, repo, opts)
|> configure_config(otp_app, repo)
|> configure_dev(otp_app, repo)
|> configure_runtime(otp_app, repo)
Expand All @@ -29,6 +45,47 @@ defmodule Mix.Tasks.AshPostgres.Install do
|> Ash.Igniter.codegen("initialize")
end

defp setup_aliases(igniter) do
is_ecto_setup = &Igniter.Code.Common.nodes_equal?(&1, "ecto.setup")

is_ecto_create_or_migrate =
fn zipper ->
Igniter.Code.Common.nodes_equal?(zipper, "ecto.create --quiet") or
Igniter.Code.Common.nodes_equal?(zipper, "ecto.create") or
Igniter.Code.Common.nodes_equal?(zipper, "ecto.migrate --quiet") or
Igniter.Code.Common.nodes_equal?(zipper, "ecto.migrate")
end

igniter
|> Igniter.Project.TaskAliases.modify_existing_alias(
"test",
&Igniter.Code.List.remove_from_list(&1, is_ecto_create_or_migrate)
)
|> Igniter.Project.TaskAliases.modify_existing_alias(
"test",
&Igniter.Code.List.replace_in_list(
&1,
is_ecto_setup,
"ash.setup"
)
)
|> Igniter.Project.TaskAliases.add_alias("test", ["ash.setup --quiet", "test"],
if_exists: {:prepend, "ash.setup --quiet"}
)
|> run_seeds_on_setup()
end

defp run_seeds_on_setup(igniter) do
if Igniter.exists?(igniter, "priv/repo/seeds.exs") do
Igniter.Project.TaskAliases.add_alias(igniter, "ash.setup", [
"ash.setup",
"run priv/repo/seeds.exs"
])
else
igniter
end
end

defp configure_config(igniter, otp_app, repo) do
Igniter.Project.Config.configure(
igniter,
Expand Down Expand Up @@ -256,26 +313,38 @@ defmodule Mix.Tasks.AshPostgres.Install do
)
end

defp setup_repo_module(igniter, otp_app, repo) do
Igniter.Code.Module.find_and_update_or_create_module(
igniter,
defp setup_repo_module(igniter, otp_app, repo, opts) do
{exists?, igniter} = Igniter.Project.Module.module_exists?(igniter, repo)

if exists? do
Igniter.Project.Module.find_and_update_module!(
igniter,
repo,
fn zipper ->
{:ok,
zipper
|> set_otp_app(otp_app)
|> Sourceror.Zipper.top()
|> use_ash_postgres_instead_of_ecto()
|> Sourceror.Zipper.top()
|> remove_adapter_option()}
end
)
else
Igniter.Project.Module.create_module(
igniter,
repo,
AshPostgres.Igniter.default_repo_contents(otp_app, repo, opts)
)
end
|> Igniter.Project.Module.find_and_update_module!(
repo,
AshPostgres.Igniter.default_repo_contents(otp_app),
fn zipper ->
{:ok,
zipper
|> set_otp_app(otp_app)
|> Sourceror.Zipper.top()
|> use_ash_postgres_instead_of_ecto()
|> Sourceror.Zipper.top()
|> remove_adapter_option()}
end
&configure_installed_extensions_function/1
)
|> Igniter.Code.Module.find_and_update_module!(
repo,
&configure_installed_extensions_function/1
&configure_min_pg_version_function(&1, repo, opts)
)
|> Igniter.Code.Module.find_and_update_module!(repo, &configure_min_pg_version_function/1)
end

defp use_ash_postgres_instead_of_ecto(zipper) do
Expand Down Expand Up @@ -347,17 +416,18 @@ defmodule Mix.Tasks.AshPostgres.Install do
end
end

defp configure_min_pg_version_function(zipper) do
defp configure_min_pg_version_function(zipper, repo, opts) do
case Igniter.Code.Function.move_to_def(zipper, :min_pg_version, 0) do
{:ok, zipper} ->
{:ok, zipper}

_ ->
min_pg_version = AshPostgres.Igniter.get_min_pg_version(repo, opts)

{:ok,
Igniter.Code.Common.add_code(zipper, """
def min_pg_version do
# Adjust this according to your postgres version
%Version{major: 16, minor: 0, patch: 0}
%Version{major: #{min_pg_version.major}, minor: #{min_pg_version.minor || 0}, patch: #{min_pg_version.patch || 0}}

Check warning on line 430 in lib/mix/tasks/ash_postgres.install.ex

View workflow job for this annotation

GitHub Actions / ash-ci (15) / mix dialyzer

guard_fail

The guard clause can never succeed.

Check warning on line 430 in lib/mix/tasks/ash_postgres.install.ex

View workflow job for this annotation

GitHub Actions / ash-ci (14) / mix dialyzer

guard_fail

The guard clause can never succeed.

Check warning on line 430 in lib/mix/tasks/ash_postgres.install.ex

View workflow job for this annotation

GitHub Actions / ash-ci (16) / mix dialyzer

guard_fail

The guard clause can never succeed.
end
""")}
end
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ defmodule AshPostgres.MixProject do
[
{:ash, ash_version("~> 3.4 and >= 3.4.9")},
{:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.30")},
{:igniter, "~> 0.3 and >= 0.3.36"},
{:igniter, "~> 0.3 and >= 0.3.42"},
{:ecto_sql, "~> 3.12"},
{:ecto, "~> 3.12 and >= 3.12.1"},
{:jason, "~> 1.0"},
Expand Down
2 changes: 1 addition & 1 deletion mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"},
"git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"},
"glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"},
"igniter": {:hex, :igniter, "0.3.39", "e59b56836b9b22c6b76b1b9661c60a996eca7bbb3b0a22f7a888cd1c77d43419", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "0e794a273b53442a6fb223a65cd9800648d6e2f8fdf8556bcf74d0af793f4bd4"},
"igniter": {:hex, :igniter, "0.3.42", "29ab08de9ba4316a6eb0ac73cd4481b3d2c4e799a647b667faafe5c988487e1b", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "d6bb222d7c6f29a9fb2461a93109da5787e4354928feea2b7a14827c27129115"},
"inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"},
"iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"},
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
Expand Down
2 changes: 1 addition & 1 deletion test/mix/tasks/ash_postgres.install_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ defmodule Mix.Tasks.AshPostgres.InstallTest do
# any errors. We should add better tests here, though.
test "installation does not fail" do
test_project()
|> Igniter.compose_task("ash_postgres.install")
|> Igniter.compose_task("ash_postgres.install", ["--yes"])
|> assert_creates("lib/test/repo.ex")
end
end

0 comments on commit 0351f52

Please sign in to comment.