2020-09-11 12:26:47 +12:00
|
|
|
defmodule AshPostgres.MigrationGeneratorTest do
|
|
|
|
use AshPostgres.RepoCase, async: false
|
|
|
|
|
|
|
|
defmacrop defposts(mod \\ Post, do: body) do
|
|
|
|
quote do
|
|
|
|
Code.compiler_options(ignore_module_conflict: true)
|
|
|
|
|
|
|
|
defmodule unquote(mod) do
|
|
|
|
use Ash.Resource,
|
|
|
|
data_layer: AshPostgres.DataLayer
|
|
|
|
|
|
|
|
postgres do
|
|
|
|
table "posts"
|
2021-01-13 14:16:48 +13:00
|
|
|
repo AshPostgres.TestRepo
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
actions do
|
2021-01-13 14:22:28 +13:00
|
|
|
read(:read)
|
|
|
|
create(:create)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
unquote(body)
|
|
|
|
end
|
|
|
|
|
|
|
|
Code.compiler_options(ignore_module_conflict: false)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defmacrop defapi(resources) do
|
|
|
|
quote do
|
|
|
|
Code.compiler_options(ignore_module_conflict: true)
|
|
|
|
|
|
|
|
defmodule Api do
|
|
|
|
use Ash.Api
|
|
|
|
|
|
|
|
resources do
|
|
|
|
for resource <- unquote(resources) do
|
|
|
|
resource(resource)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
Code.compiler_options(ignore_module_conflict: false)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "creating initial snapshots" do
|
|
|
|
setup do
|
|
|
|
on_exit(fn ->
|
2020-09-11 15:47:14 +12:00
|
|
|
File.rm_rf!("test_snapshots_path")
|
|
|
|
File.rm_rf!("test_migration_path")
|
2020-09-11 12:26:47 +12:00
|
|
|
end)
|
|
|
|
|
|
|
|
defposts do
|
|
|
|
resource do
|
|
|
|
identities do
|
2021-01-13 14:22:28 +13:00
|
|
|
identity(:title, [:title])
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
2021-01-13 14:22:28 +13:00
|
|
|
uuid_primary_key(:id)
|
|
|
|
attribute(:title, :string)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defapi([Post])
|
|
|
|
|
|
|
|
Mix.shell(Mix.Shell.Process)
|
|
|
|
|
|
|
|
AshPostgres.MigrationGenerator.generate(Api,
|
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
|
|
|
|
test "it creates a snapshot for each resource" do
|
2021-01-07 18:37:41 +13:00
|
|
|
assert File.exists?(Path.wildcard("test_snapshots_path/test_repo/posts/*.json"))
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
test "the snapshots can be loaded" do
|
2021-01-07 18:37:41 +13:00
|
|
|
assert File.exists?(Path.wildcard("test_snapshots_path/test_repo/posts/*.json"))
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
test "the snapshots contain valid json" do
|
2021-01-07 18:37:41 +13:00
|
|
|
assert File.read!(Path.wildcard("test_snapshots_path/test_repo/posts/*.json"))
|
2020-09-11 12:26:47 +12:00
|
|
|
|> Jason.decode!(keys: :atoms!)
|
|
|
|
end
|
|
|
|
|
|
|
|
test "the migration creates the table" do
|
2020-09-11 15:47:14 +12:00
|
|
|
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
assert File.read!(file) =~ "create table(:posts, primary_key: false) do"
|
|
|
|
end
|
|
|
|
|
|
|
|
test "the migration adds the id, with its default" do
|
2020-09-11 15:47:14 +12:00
|
|
|
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
assert File.read!(file) =~
|
2021-01-13 14:27:39 +13:00
|
|
|
~S[add :id, :binary_id, null: false, default: fragment("uuid_generate_v4()"), primary_key: true]
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
test "the migration adds other attributes" do
|
2020-09-11 15:47:14 +12:00
|
|
|
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
assert File.read!(file) =~
|
2021-01-10 13:52:19 +13:00
|
|
|
~S[add :title, :text]
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
test "the migration creates unique_indexes based on the identities of the resource" do
|
2020-09-11 15:47:14 +12:00
|
|
|
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
assert File.read!(file) =~
|
|
|
|
~S{create unique_index(:posts, [:title], name: "posts_title_unique_index")}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "creating follow up migrations" do
|
|
|
|
setup do
|
|
|
|
on_exit(fn ->
|
2020-09-11 15:47:14 +12:00
|
|
|
File.rm_rf!("test_snapshots_path")
|
|
|
|
File.rm_rf!("test_migration_path")
|
2020-09-11 12:26:47 +12:00
|
|
|
end)
|
|
|
|
|
|
|
|
defposts do
|
|
|
|
resource do
|
|
|
|
identities do
|
2021-01-13 14:22:28 +13:00
|
|
|
identity(:title, [:title])
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
2021-01-13 14:22:28 +13:00
|
|
|
uuid_primary_key(:id)
|
|
|
|
attribute(:title, :string)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defapi([Post])
|
|
|
|
|
|
|
|
Mix.shell(Mix.Shell.Process)
|
|
|
|
|
|
|
|
AshPostgres.MigrationGenerator.generate(Api,
|
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
|
|
|
|
test "when adding a field, it adds the field" do
|
|
|
|
defposts do
|
|
|
|
resource do
|
|
|
|
identities do
|
2021-01-13 14:22:28 +13:00
|
|
|
identity(:title, [:title])
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
2021-01-13 14:22:28 +13:00
|
|
|
uuid_primary_key(:id)
|
|
|
|
attribute(:title, :string)
|
|
|
|
attribute(:name, :string, allow_nil?: false)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defapi([Post])
|
|
|
|
|
|
|
|
AshPostgres.MigrationGenerator.generate(Api,
|
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [_file1, file2] =
|
2020-09-11 15:47:14 +12:00
|
|
|
Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
assert File.read!(file2) =~
|
2021-01-10 13:52:19 +13:00
|
|
|
~S[add :name, :text, null: false]
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
test "when renaming a field, it asks if you are renaming it, and renames it if you are" do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
2021-01-13 14:22:28 +13:00
|
|
|
uuid_primary_key(:id)
|
|
|
|
attribute(:name, :string, allow_nil?: false)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defapi([Post])
|
|
|
|
|
|
|
|
send(self(), {:mix_shell_input, :yes?, true})
|
|
|
|
|
|
|
|
AshPostgres.MigrationGenerator.generate(Api,
|
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [_file1, file2] =
|
2020-09-11 15:47:14 +12:00
|
|
|
Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
assert File.read!(file2) =~ ~S[rename table(:posts), :title, to: :name]
|
|
|
|
end
|
|
|
|
|
|
|
|
test "when renaming a field, it asks if you are renaming it, and adds it if you aren't" do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
2021-01-13 14:22:28 +13:00
|
|
|
uuid_primary_key(:id)
|
|
|
|
attribute(:name, :string, allow_nil?: false)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defapi([Post])
|
|
|
|
|
|
|
|
send(self(), {:mix_shell_input, :yes?, false})
|
|
|
|
|
|
|
|
AshPostgres.MigrationGenerator.generate(Api,
|
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [_file1, file2] =
|
2020-09-11 15:47:14 +12:00
|
|
|
Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
assert File.read!(file2) =~
|
2021-01-10 13:52:19 +13:00
|
|
|
~S[add :name, :text, null: false]
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
test "when renaming a field, it asks which field you are renaming it to, and renames it if you are" do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
2021-01-13 14:22:28 +13:00
|
|
|
uuid_primary_key(:id)
|
|
|
|
attribute(:name, :string, allow_nil?: false)
|
|
|
|
attribute(:subject, :string, allow_nil?: false)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defapi([Post])
|
|
|
|
|
|
|
|
send(self(), {:mix_shell_input, :yes?, true})
|
|
|
|
send(self(), {:mix_shell_input, :prompt, "subject"})
|
|
|
|
|
|
|
|
AshPostgres.MigrationGenerator.generate(Api,
|
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [_file1, file2] =
|
2020-09-11 15:47:14 +12:00
|
|
|
Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
assert File.read!(file2) =~ ~S[rename table(:posts), :title, to: :subject]
|
|
|
|
end
|
|
|
|
|
|
|
|
test "when renaming a field, it asks which field you are renaming it to, and adds it if you arent" do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
2021-01-13 14:22:28 +13:00
|
|
|
uuid_primary_key(:id)
|
|
|
|
attribute(:name, :string, allow_nil?: false)
|
|
|
|
attribute(:subject, :string, allow_nil?: false)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defapi([Post])
|
|
|
|
|
|
|
|
send(self(), {:mix_shell_input, :yes?, false})
|
|
|
|
|
|
|
|
AshPostgres.MigrationGenerator.generate(Api,
|
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [_file1, file2] =
|
2020-09-11 15:47:14 +12:00
|
|
|
Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
assert File.read!(file2) =~
|
2021-01-10 13:52:19 +13:00
|
|
|
~S[add :subject, :text, null: false]
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
test "when changing the primary key, it changes properly" do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
2021-01-13 14:22:28 +13:00
|
|
|
attribute(:id, :uuid, primary_key?: false, default: &Ecto.UUID.generate/0)
|
|
|
|
uuid_primary_key(:guid)
|
|
|
|
attribute(:title, :string)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defapi([Post])
|
|
|
|
|
|
|
|
AshPostgres.MigrationGenerator.generate(Api,
|
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [_file1, file2] =
|
2020-09-11 15:47:14 +12:00
|
|
|
Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
assert File.read!(file2) =~
|
2021-01-13 14:27:39 +13:00
|
|
|
~S[add :guid, :binary_id, null: false, default: fragment("uuid_generate_v4()"), primary_key: true]
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
test "when multiple schemas apply to the same table, all attributes are added" do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
2021-01-13 14:22:28 +13:00
|
|
|
uuid_primary_key(:id)
|
|
|
|
attribute(:title, :string)
|
|
|
|
attribute(:foobar, :string)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defposts Post2 do
|
|
|
|
attributes do
|
2021-01-13 14:22:28 +13:00
|
|
|
uuid_primary_key(:id)
|
|
|
|
attribute(:name, :string)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defapi([Post, Post2])
|
|
|
|
|
|
|
|
AshPostgres.MigrationGenerator.generate(Api,
|
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [_file1, file2] =
|
2020-09-11 15:47:14 +12:00
|
|
|
Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
assert File.read!(file2) =~
|
2021-01-10 13:52:19 +13:00
|
|
|
~S[add :foobar, :text]
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
assert File.read!(file2) =~
|
2021-01-10 13:52:19 +13:00
|
|
|
~S[add :foobar, :text]
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
2021-01-08 16:53:16 +13:00
|
|
|
|
|
|
|
describe "auto incrementing integer, when generated" do
|
|
|
|
setup do
|
|
|
|
on_exit(fn ->
|
|
|
|
File.rm_rf!("test_snapshots_path")
|
|
|
|
File.rm_rf!("test_migration_path")
|
|
|
|
end)
|
|
|
|
|
|
|
|
defposts do
|
|
|
|
attributes do
|
2021-01-13 14:22:28 +13:00
|
|
|
attribute(:id, :integer, generated?: true, allow_nil?: false, primary_key?: true)
|
|
|
|
attribute(:views, :integer)
|
2021-01-08 16:53:16 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defapi([Post])
|
|
|
|
|
|
|
|
Mix.shell(Mix.Shell.Process)
|
|
|
|
|
|
|
|
AshPostgres.MigrationGenerator.generate(Api,
|
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
|
|
|
|
test "when an integer is generated and default nil, it is a serial" do
|
|
|
|
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
|
|
|
|
|
|
|
assert File.read!(file) =~
|
|
|
|
~S[add :id, :serial, null: false, primary_key: true]
|
|
|
|
|
|
|
|
assert File.read!(file) =~
|
2021-01-10 13:52:19 +13:00
|
|
|
~S[add :views, :integer]
|
2021-01-08 16:53:16 +13:00
|
|
|
end
|
|
|
|
end
|
2021-01-13 14:47:17 +13:00
|
|
|
|
|
|
|
describe "--check_migrated option" do
|
|
|
|
setup do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
2021-01-13 14:53:06 +13:00
|
|
|
uuid_primary_key(:id)
|
2021-01-13 14:47:17 +13:00
|
|
|
attribute(:title, :string)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defapi([Post])
|
|
|
|
|
|
|
|
[api: Api]
|
|
|
|
end
|
|
|
|
|
|
|
|
test "returns code(1) if snapshots and resources don't fit", %{api: api} do
|
|
|
|
assert catch_exit(
|
|
|
|
AshPostgres.MigrationGenerator.generate(api,
|
|
|
|
snapshot_path: "test_snapshot_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
check_generated: true
|
|
|
|
)
|
|
|
|
) == {:shutdown, 1}
|
|
|
|
|
|
|
|
refute File.exists?(Path.wildcard("test_migration_path2/**/*_migrate_resources*.exs"))
|
|
|
|
refute File.exists?(Path.wildcard("test_snapshots_path2/test_repo/posts/*.json"))
|
|
|
|
end
|
|
|
|
end
|
2021-02-07 09:05:37 +13:00
|
|
|
|
|
|
|
describe "polymorphic resources" do
|
|
|
|
setup do
|
|
|
|
on_exit(fn ->
|
|
|
|
File.rm_rf!("test_snapshots_path")
|
|
|
|
File.rm_rf!("test_migration_path")
|
|
|
|
end)
|
|
|
|
|
|
|
|
defmodule Comment do
|
|
|
|
use Ash.Resource,
|
|
|
|
data_layer: AshPostgres.DataLayer
|
|
|
|
|
|
|
|
postgres do
|
|
|
|
polymorphic? true
|
|
|
|
repo AshPostgres.TestRepo
|
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2021-02-07 09:21:52 +13:00
|
|
|
attribute(:resource_id, :uuid)
|
2021-02-07 09:05:37 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
actions do
|
|
|
|
read(:read)
|
|
|
|
create(:create)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defmodule Post do
|
|
|
|
use Ash.Resource,
|
|
|
|
data_layer: AshPostgres.DataLayer
|
|
|
|
|
|
|
|
postgres do
|
|
|
|
table "posts"
|
|
|
|
repo AshPostgres.TestRepo
|
|
|
|
end
|
|
|
|
|
|
|
|
actions do
|
|
|
|
read(:read)
|
|
|
|
create(:create)
|
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
|
|
|
end
|
|
|
|
|
|
|
|
relationships do
|
|
|
|
has_many(:comments, Comment,
|
|
|
|
destination_field: :resource_id,
|
|
|
|
context: %{data_layer: %{table: "post_comments"}}
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defapi([Post, Comment])
|
|
|
|
|
|
|
|
AshPostgres.MigrationGenerator.generate(Api,
|
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
[api: Api]
|
|
|
|
end
|
|
|
|
|
|
|
|
test "it uses the relationship's table context if it is set" do
|
|
|
|
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
|
|
|
|
|
|
|
assert File.read!(file) =~
|
|
|
|
~S[references(:post_comments]
|
|
|
|
end
|
|
|
|
end
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|