From 09c6bc4e96e3a4da3db534a04af17245c5341bdc Mon Sep 17 00:00:00 2001 From: Mika Kalathil Date: Wed, 4 Oct 2023 12:10:29 -0700 Subject: [PATCH] Allow --repo option & --migration-dir for phx.gen.schema (#4905) * Allow --repo option for phx.gen.schema * Add tests for the repo and migration-dir options in schema generator The `repo` and `migration-dir` options change the location of the migrations directory, either to the specified directory or one that matches the repo name (underscored). The default is explicitly set to "repo" if neither option is set, to ensure backwards compatability even if the repo has a different name than the typical `MyApp.Repo`. --------- Co-authored-by: Gary Rennie --- lib/mix/tasks/phx.gen.schema.ex | 48 ++++++++++++++++++++++---- test/mix/tasks/phx.gen.schema_test.exs | 34 ++++++++++++++++++ 2 files changed, 76 insertions(+), 6 deletions(-) diff --git a/lib/mix/tasks/phx.gen.schema.ex b/lib/mix/tasks/phx.gen.schema.ex index c6f49051e9..7d2da6e631 100644 --- a/lib/mix/tasks/phx.gen.schema.ex +++ b/lib/mix/tasks/phx.gen.schema.ex @@ -86,6 +86,21 @@ defmodule Mix.Tasks.Phx.Gen.Schema do Generated migration can use `binary_id` for schema's primary key and its references with option `--binary-id`. + ## repo + + Generated migration can use `repo` to set the migration repository + folder with option `--repo`: + + $ mix phx.gen.schema Blog.Post posts --repo MyApp.Repo.Auth + + ## migration_dir + + Generated migrations can be added to a specific `--migration-dir` which sets + the migration folder path: + + $ mix phx.gen.schema Blog.Post posts --migration-dir /path/to/directory + + ## prefix By default migrations and schemas are generated without a prefix. @@ -130,8 +145,8 @@ defmodule Mix.Tasks.Phx.Gen.Schema do alias Mix.Phoenix.Schema - @switches [migration: :boolean, binary_id: :boolean, table: :string, - web: :string, context_app: :string, prefix: :string] + @switches [migration: :boolean, binary_id: :boolean, table: :string, web: :string, + context_app: :string, prefix: :string, repo: :string, migration_dir: :string] @doc false def run(args) do @@ -164,10 +179,17 @@ defmodule Mix.Tasks.Phx.Gen.Schema do parent_opts |> Keyword.merge(schema_opts) |> put_context_app(schema_opts[:context_app]) + |> maybe_update_repo_module() - schema = Schema.new(schema_name, plural, attrs, opts) + Schema.new(schema_name, plural, attrs, opts) + end - schema + defp maybe_update_repo_module(opts) do + if is_nil(opts[:repo]) do + opts + else + Keyword.update!(opts, :repo, &Module.concat([&1])) + end end defp put_context_app(opts, nil), do: opts @@ -181,12 +203,26 @@ defmodule Mix.Tasks.Phx.Gen.Schema do end @doc false - def copy_new_files(%Schema{context_app: ctx_app} = schema, paths, binding) do + def copy_new_files(%Schema{context_app: ctx_app, repo: repo, opts: opts} = schema, paths, binding) do files = files_to_be_generated(schema) Mix.Phoenix.copy_from(paths, "priv/templates/phx.gen.schema", binding, files) if schema.migration? do - migration_path = Mix.Phoenix.context_app_path(ctx_app, "priv/repo/migrations/#{timestamp()}_create_#{schema.table}.exs") + migration_dir = + cond do + migration_dir = opts[:migration_dir] -> + migration_dir + + opts[:repo] -> + repo_name = repo |> Module.split() |> List.last() |> Macro.underscore() + Mix.Phoenix.context_app_path(ctx_app, "priv/#{repo_name}/migrations/") + + true -> + Mix.Phoenix.context_app_path(ctx_app, "priv/repo/migrations/") + end + + migration_path = Path.join(migration_dir, "#{timestamp()}_create_#{schema.table}.exs") + Mix.Phoenix.copy_from paths, "priv/templates/phx.gen.schema", binding, [ {:eex, "migration.exs", migration_path}, ] diff --git a/test/mix/tasks/phx.gen.schema_test.exs b/test/mix/tasks/phx.gen.schema_test.exs index 85d39bef20..ea267f9274 100644 --- a/test/mix/tasks/phx.gen.schema_test.exs +++ b/test/mix/tasks/phx.gen.schema_test.exs @@ -113,6 +113,40 @@ defmodule Mix.Tasks.Phx.Gen.SchemaTest do end end + test "allows a custom repo", config do + in_tmp_project config.test, fn -> + Gen.Schema.run(~w(Blog.Post blog_posts title:string --repo MyApp.CustomRepo)) + + assert [migration] = Path.wildcard("priv/custom_repo/migrations/*_create_blog_posts.exs") + assert_file migration, fn file -> + assert file =~ "defmodule MyApp.CustomRepo.Migrations.CreateBlogPosts do" + end + end + end + + test "allows a custom migration dir", config do + in_tmp_project config.test, fn -> + Gen.Schema.run(~w(Blog.Post blog_posts title:string --migration-dir priv/custom_dir)) + + assert [migration] = Path.wildcard("priv/custom_dir/*_create_blog_posts.exs") + assert_file migration, fn file -> + assert file =~ "defmodule Phoenix.Repo.Migrations.CreateBlogPosts do" + end + end + end + + test "custom migration_dir takes precedence over custom repo name", config do + in_tmp_project config.test, fn -> + Gen.Schema.run(~w(Blog.Post blog_posts title:string \ + --repo MyApp.CustomRepo --migration-dir priv/custom_dir)) + + assert [migration] = Path.wildcard("priv/custom_dir/*_create_blog_posts.exs") + assert_file migration, fn file -> + assert file =~ "defmodule MyApp.CustomRepo.Migrations.CreateBlogPosts do" + end + end + end + test "does not add maps to the required list", config do in_tmp_project config.test, fn -> Gen.Schema.run(~w(Blog.Post blog_posts title:string tags:map published_at:naive_datetime))