2020-09-11 12:26:47 +12:00
|
|
|
defmodule AshPostgres.MigrationGeneratorTest do
|
|
|
|
use AshPostgres.RepoCase, async: false
|
2021-07-03 04:41:44 +12:00
|
|
|
@moduletag :migration
|
2020-09-11 12:26:47 +12:00
|
|
|
|
2022-05-25 04:11:32 +12:00
|
|
|
import ExUnit.CaptureLog
|
|
|
|
|
2020-09-11 12:26:47 +12:00
|
|
|
defmacrop defposts(mod \\ Post, do: body) do
|
|
|
|
quote do
|
|
|
|
Code.compiler_options(ignore_module_conflict: true)
|
|
|
|
|
|
|
|
defmodule unquote(mod) do
|
|
|
|
use Ash.Resource,
|
2024-03-28 09:52:28 +13:00
|
|
|
domain: nil,
|
2020-09-11 12:26:47 +12:00
|
|
|
data_layer: AshPostgres.DataLayer
|
|
|
|
|
|
|
|
postgres do
|
|
|
|
table "posts"
|
2022-08-19 06:56:36 +12:00
|
|
|
repo(AshPostgres.TestRepo)
|
2021-09-26 13:02:00 +13:00
|
|
|
|
|
|
|
custom_indexes do
|
|
|
|
# need one without any opts
|
2022-08-19 06:56:36 +12:00
|
|
|
index(["id"])
|
|
|
|
index(["id"], unique: true, name: "test_unique_index")
|
2021-09-26 13:02:00 +13:00
|
|
|
end
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
actions do
|
2022-04-20 03:08:28 +12:00
|
|
|
defaults([:create, :read, :update, :destroy])
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
unquote(body)
|
|
|
|
end
|
|
|
|
|
|
|
|
Code.compiler_options(ignore_module_conflict: false)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defmacrop defdomain(resources) do
|
2020-09-11 12:26:47 +12:00
|
|
|
quote do
|
|
|
|
Code.compiler_options(ignore_module_conflict: true)
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defmodule Domain do
|
|
|
|
use Ash.Domain
|
2021-10-26 11:53:34 +13:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
resources do
|
2021-10-26 11:53:34 +13:00
|
|
|
for resource <- unquote(resources) do
|
2024-03-28 09:52:28 +13:00
|
|
|
resource(resource)
|
2021-10-26 11:53:34 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-09-11 12:26:47 +12:00
|
|
|
Code.compiler_options(ignore_module_conflict: false)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-09-26 08:33:28 +13:00
|
|
|
defmacrop defresource(mod, table, do: body) do
|
|
|
|
quote do
|
|
|
|
Code.compiler_options(ignore_module_conflict: true)
|
|
|
|
|
|
|
|
defmodule unquote(mod) do
|
2024-03-28 09:52:28 +13:00
|
|
|
use Ash.Resource, data_layer: AshPostgres.DataLayer, domain: nil
|
2023-09-26 08:33:28 +13:00
|
|
|
|
|
|
|
postgres do
|
|
|
|
table unquote(table)
|
|
|
|
repo(AshPostgres.TestRepo)
|
|
|
|
end
|
|
|
|
|
|
|
|
actions do
|
|
|
|
defaults([:create, :read, :update, :destroy])
|
|
|
|
end
|
|
|
|
|
|
|
|
unquote(body)
|
|
|
|
end
|
|
|
|
|
|
|
|
Code.compiler_options(ignore_module_conflict: false)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-09-11 12:26:47 +12:00
|
|
|
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
|
2021-11-10 22:18:36 +13:00
|
|
|
postgres do
|
2022-08-19 06:56:36 +12:00
|
|
|
migration_types(second_title: {:varchar, 16})
|
2022-11-21 20:39:57 +13:00
|
|
|
migration_defaults(title_with_default: "\"fred\"")
|
2021-11-10 22:18:36 +13:00
|
|
|
end
|
|
|
|
|
2021-04-28 09:16:56 +12:00
|
|
|
identities do
|
|
|
|
identity(:title, [:title])
|
2022-09-10 17:41:25 +12:00
|
|
|
identity(:thing, [:title, :second_title])
|
2022-10-05 09:13:38 +13:00
|
|
|
identity(:thing_with_source, [:title, :title_with_source])
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
2021-01-13 14:22:28 +13:00
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:title, :string, public?: true)
|
|
|
|
attribute(:second_title, :string, public?: true)
|
|
|
|
attribute(:title_with_source, :string, source: :t_w_s, public?: true)
|
|
|
|
attribute(:title_with_default, :string, public?: true)
|
|
|
|
attribute(:email, Test.Support.Types.Email, public?: true)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
Mix.shell(Mix.Shell.Process)
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2020-09-11 12:26:47 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
|
2021-09-26 13:02:00 +13:00
|
|
|
test "the migration sets up resources correctly" do
|
|
|
|
# the snapshot exists and contains valid json
|
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!)
|
|
|
|
|
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
|
|
|
|
2021-09-26 13:02:00 +13:00
|
|
|
file_contents = File.read!(file)
|
2020-09-11 12:26:47 +12:00
|
|
|
|
2021-09-26 13:02:00 +13:00
|
|
|
# the migration creates the table
|
|
|
|
assert file_contents =~ "create table(:posts, primary_key: false) do"
|
2020-09-11 12:26:47 +12:00
|
|
|
|
2021-09-26 13:02:00 +13:00
|
|
|
# the migration sets up the custom_indexes
|
|
|
|
assert file_contents =~
|
|
|
|
~S{create index(:posts, ["id"], name: "test_unique_index", unique: true)}
|
2020-09-11 12:26:47 +12:00
|
|
|
|
2021-09-26 13:02:00 +13:00
|
|
|
assert file_contents =~ ~S{create index(:posts, ["id"]}
|
2020-09-11 12:26:47 +12:00
|
|
|
|
2021-09-26 13:02:00 +13:00
|
|
|
# the migration adds the id, with its default
|
|
|
|
assert file_contents =~
|
2024-03-28 10:28:28 +13:00
|
|
|
~S[add :id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true]
|
2020-09-11 12:26:47 +12:00
|
|
|
|
2022-11-21 20:39:57 +13:00
|
|
|
# the migration adds the id, with its default
|
|
|
|
assert file_contents =~
|
2022-11-21 20:45:09 +13:00
|
|
|
~S[add :title_with_default, :text, default: "fred"]
|
2022-11-21 20:39:57 +13:00
|
|
|
|
2021-09-26 13:02:00 +13:00
|
|
|
# the migration adds other attributes
|
|
|
|
assert file_contents =~ ~S[add :title, :text]
|
2020-09-11 12:26:47 +12:00
|
|
|
|
2023-04-08 02:56:06 +12:00
|
|
|
# the migration unwraps newtypes
|
|
|
|
assert file_contents =~ ~S[add :email, :citext]
|
|
|
|
|
2021-11-10 22:18:36 +13:00
|
|
|
# the migration adds custom attributes
|
|
|
|
assert file_contents =~ ~S[add :second_title, :varchar, size: 16]
|
|
|
|
|
2021-09-26 13:02:00 +13:00
|
|
|
# the migration creates unique_indexes based on the identities of the resource
|
|
|
|
assert file_contents =~ ~S{create unique_index(:posts, [:title], name: "posts_title_index")}
|
2022-09-10 17:41:25 +12:00
|
|
|
|
|
|
|
# the migration creates unique_indexes based on the identities of the resource
|
|
|
|
assert file_contents =~
|
|
|
|
~S{create unique_index(:posts, [:title, :second_title], name: "posts_thing_index")}
|
2022-10-05 09:13:38 +13:00
|
|
|
|
|
|
|
# the migration creates unique_indexes using the `source` on the attributes of the identity on the resource
|
|
|
|
assert file_contents =~
|
|
|
|
~S{create unique_index(:posts, [:title, :t_w_s], name: "posts_thing_with_source_index")}
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-05-14 09:41:30 +12:00
|
|
|
describe "creating initial snapshots for resources with a schema" do
|
|
|
|
setup do
|
|
|
|
on_exit(fn ->
|
|
|
|
File.rm_rf!("test_snapshots_path")
|
|
|
|
File.rm_rf!("test_migration_path")
|
|
|
|
end)
|
|
|
|
|
|
|
|
defposts do
|
|
|
|
postgres do
|
2022-08-19 06:56:36 +12:00
|
|
|
migration_types(second_title: {:varchar, 16})
|
2022-05-14 09:41:30 +12:00
|
|
|
schema("example")
|
|
|
|
end
|
|
|
|
|
|
|
|
identities do
|
|
|
|
identity(:title, [:title])
|
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:title, :string, public?: true)
|
|
|
|
attribute(:second_title, :string, public?: true)
|
2022-05-14 09:41:30 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2022-05-14 09:41:30 +12:00
|
|
|
|
|
|
|
Mix.shell(Mix.Shell.Process)
|
|
|
|
|
|
|
|
{:ok, _} =
|
|
|
|
Ecto.Adapters.SQL.query(
|
|
|
|
AshPostgres.TestRepo,
|
|
|
|
"""
|
|
|
|
CREATE SCHEMA IF NOT EXISTS example;
|
|
|
|
"""
|
|
|
|
)
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2022-05-14 09:41:30 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
|
|
|
|
test "the migration sets up resources correctly" do
|
|
|
|
# the snapshot exists and contains valid json
|
2024-01-17 17:44:49 +13:00
|
|
|
assert File.read!(Path.wildcard("test_snapshots_path/test_repo/example.posts/*.json"))
|
2022-05-14 09:41:30 +12:00
|
|
|
|> Jason.decode!(keys: :atoms!)
|
|
|
|
|
|
|
|
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
|
|
|
|
|
|
|
file_contents = File.read!(file)
|
|
|
|
|
|
|
|
# the migration creates the table
|
|
|
|
assert file_contents =~ "create table(:posts, primary_key: false, prefix: \"example\") do"
|
|
|
|
|
|
|
|
# the migration sets up the custom_indexes
|
|
|
|
assert file_contents =~
|
|
|
|
~S{create index(:posts, ["id"], name: "test_unique_index", unique: true, prefix: "example")}
|
|
|
|
|
|
|
|
assert file_contents =~ ~S{create index(:posts, ["id"]}
|
|
|
|
|
|
|
|
# the migration adds the id, with its default
|
|
|
|
assert file_contents =~
|
2024-03-28 10:28:28 +13:00
|
|
|
~S[add :id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true]
|
2022-05-14 09:41:30 +12:00
|
|
|
|
|
|
|
# the migration adds other attributes
|
|
|
|
assert file_contents =~ ~S[add :title, :text]
|
|
|
|
|
|
|
|
# the migration adds custom attributes
|
|
|
|
assert file_contents =~ ~S[add :second_title, :varchar, size: 16]
|
|
|
|
|
|
|
|
# the migration creates unique_indexes based on the identities of the resource
|
|
|
|
assert file_contents =~
|
|
|
|
~S{create unique_index(:posts, [:title], name: "posts_title_index", prefix: "example")}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-11-26 08:06:22 +13:00
|
|
|
describe "custom_indexes with `concurrently: true`" do
|
|
|
|
setup do
|
|
|
|
on_exit(fn ->
|
|
|
|
File.rm_rf!("test_snapshots_path")
|
|
|
|
File.rm_rf!("test_migration_path")
|
|
|
|
end)
|
|
|
|
|
|
|
|
defposts do
|
|
|
|
postgres do
|
|
|
|
custom_indexes do
|
|
|
|
# need one without any opts
|
|
|
|
index([:title], concurrently: true)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:title, :string, public?: true)
|
2022-11-26 08:06:22 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2022-11-26 08:06:22 +13:00
|
|
|
Mix.shell(Mix.Shell.Process)
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2022-11-26 08:06:22 +13:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
test "it creates multiple migration files" do
|
|
|
|
assert [_, custom_index_migration] =
|
|
|
|
Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
|
|
|
|
|
|
|
file = File.read!(custom_index_migration)
|
|
|
|
|
|
|
|
assert file =~ ~S[@disable_ddl_transaction true]
|
|
|
|
|
2024-01-23 05:32:34 +13:00
|
|
|
assert file =~ ~S<create index(:posts, [:title], concurrently: true)>
|
2022-11-26 08:06:22 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-21 05:01:53 +13:00
|
|
|
describe "custom_indexes with `null_distinct: false`" do
|
2024-03-13 13:22:34 +13:00
|
|
|
setup do
|
|
|
|
on_exit(fn ->
|
|
|
|
File.rm_rf!("test_snapshots_path")
|
|
|
|
File.rm_rf!("test_migration_path")
|
|
|
|
end)
|
|
|
|
|
|
|
|
defposts do
|
|
|
|
postgres do
|
|
|
|
custom_indexes do
|
|
|
|
index([:uniq_one], nulls_distinct: true)
|
|
|
|
index([:uniq_two], nulls_distinct: false)
|
|
|
|
index([:uniq_custom_one])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:title, :string, public?: true)
|
2024-03-13 13:22:34 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2024-03-13 13:22:34 +13:00
|
|
|
Mix.shell(Mix.Shell.Process)
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2024-03-13 13:22:34 +13:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
test "it adds nulls_distinct option to create index migration" do
|
|
|
|
assert [custom_index_migration] =
|
|
|
|
Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
|
|
|
|
|
|
|
file = File.read!(custom_index_migration)
|
|
|
|
|
2024-03-21 05:01:53 +13:00
|
|
|
assert file =~ ~S<create index(:posts, [:uniq_one])>
|
|
|
|
assert file =~ ~S<create index(:posts, [:uniq_two], nulls_distinct: false)>
|
2024-03-13 13:22:34 +13:00
|
|
|
assert file =~ ~S<create index(:posts, [:uniq_custom_one])>
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-08-10 08:37:20 +12:00
|
|
|
describe "creating follow up migrations with a schema" do
|
|
|
|
setup do
|
|
|
|
on_exit(fn ->
|
|
|
|
File.rm_rf!("test_snapshots_path")
|
|
|
|
File.rm_rf!("test_migration_path")
|
|
|
|
end)
|
|
|
|
|
|
|
|
defposts do
|
|
|
|
postgres do
|
|
|
|
schema("example")
|
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:title, :string, public?: true)
|
2022-08-10 08:37:20 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2022-08-10 08:37:20 +12:00
|
|
|
|
|
|
|
Mix.shell(Mix.Shell.Process)
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2022-08-10 08:37:20 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
|
|
|
|
test "when renaming a field, it asks if you are renaming it, and renames it if you are" do
|
|
|
|
defposts do
|
|
|
|
postgres do
|
|
|
|
schema("example")
|
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:name, :string, allow_nil?: false, public?: true)
|
2022-08-10 08:37:20 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2022-08-10 08:37:20 +12:00
|
|
|
|
|
|
|
send(self(), {:mix_shell_input, :yes?, true})
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2022-08-10 08:37:20 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [_file1, file2] =
|
|
|
|
Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
|
|
|
|
|
|
|
assert File.read!(file2) =~ ~S[rename table(:posts, prefix: "example"), :title, to: :name]
|
|
|
|
end
|
2024-02-16 03:23:48 +13:00
|
|
|
|
|
|
|
test "renaming a field honors additional changes" do
|
|
|
|
defposts do
|
|
|
|
postgres do
|
|
|
|
schema("example")
|
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:name, :string, allow_nil?: false, default: "fred", public?: true)
|
2024-02-16 03:23:48 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2024-02-16 03:23:48 +13:00
|
|
|
|
|
|
|
send(self(), {:mix_shell_input, :yes?, true})
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2024-02-16 03:23:48 +13:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [_file1, file2] =
|
|
|
|
Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
|
|
|
|
|
|
|
assert File.read!(file2) =~ ~S[rename table(:posts, prefix: "example"), :title, to: :name]
|
|
|
|
assert File.read!(file2) =~ ~S[modify :title, :text, null: true, default: nil]
|
|
|
|
end
|
2022-08-10 08:37:20 +12:00
|
|
|
end
|
|
|
|
|
2020-09-11 12:26:47 +12:00
|
|
|
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
|
2021-04-28 09:16:56 +12:00
|
|
|
identities do
|
|
|
|
identity(:title, [:title])
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
2021-01-13 14:22:28 +13:00
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:title, :string, public?: true)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
Mix.shell(Mix.Shell.Process)
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2020-09-11 12:26:47 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
|
2021-04-28 09:16:56 +12:00
|
|
|
test "when renaming an index, it is properly renamed" do
|
|
|
|
defposts do
|
|
|
|
postgres do
|
|
|
|
identity_index_names(title: "titles_r_unique_dawg")
|
|
|
|
end
|
|
|
|
|
|
|
|
identities do
|
|
|
|
identity(:title, [:title])
|
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:title, :string, public?: true)
|
2021-04-28 09:16:56 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2021-04-28 09:16:56 +12:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2021-04-28 09:16:56 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [_file1, file2] =
|
|
|
|
Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
|
|
|
|
|
|
|
assert File.read!(file2) =~
|
|
|
|
~S[ALTER INDEX posts_title_index RENAME TO titles_r_unique_dawg]
|
|
|
|
end
|
|
|
|
|
2020-09-11 12:26:47 +12:00
|
|
|
test "when adding a field, it adds the field" do
|
|
|
|
defposts do
|
2021-04-28 09:16:56 +12:00
|
|
|
identities do
|
|
|
|
identity(:title, [:title])
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
2021-01-13 14:22:28 +13:00
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:title, :string, public?: true)
|
|
|
|
attribute(:name, :string, allow_nil?: false, public?: true)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2020-09-11 12:26:47 +12:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2020-09-11 12:26:47 +12:00
|
|
|
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)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:name, :string, allow_nil?: false, public?: true)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
send(self(), {:mix_shell_input, :yes?, true})
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2020-09-11 12:26:47 +12:00
|
|
|
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)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:name, :string, allow_nil?: false, public?: true)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
send(self(), {:mix_shell_input, :yes?, false})
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2020-09-11 12:26:47 +12:00
|
|
|
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)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:name, :string, allow_nil?: false, public?: true)
|
|
|
|
attribute(:subject, :string, allow_nil?: false, public?: true)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
send(self(), {:mix_shell_input, :yes?, true})
|
|
|
|
send(self(), {:mix_shell_input, :prompt, "subject"})
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2020-09-11 12:26:47 +12:00
|
|
|
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
|
|
|
|
2022-06-01 04:14:05 +12:00
|
|
|
# Up migration
|
2020-09-11 12:26:47 +12:00
|
|
|
assert File.read!(file2) =~ ~S[rename table(:posts), :title, to: :subject]
|
2022-06-01 04:14:05 +12:00
|
|
|
|
|
|
|
# Down migration
|
|
|
|
assert File.read!(file2) =~ ~S[rename table(:posts), :subject, to: :title]
|
2020-09-11 12:26:47 +12:00
|
|
|
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)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:name, :string, allow_nil?: false, public?: true)
|
|
|
|
attribute(:subject, :string, allow_nil?: false, public?: true)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2020-09-11 12:26:47 +12:00
|
|
|
|
|
|
|
send(self(), {:mix_shell_input, :yes?, false})
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2020-09-11 12:26:47 +12:00
|
|
|
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 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)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:title, :string, public?: true)
|
|
|
|
attribute(:foobar, :string, public?: true)
|
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)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:name, :string, public?: true)
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post, Post2])
|
2020-09-11 12:26:47 +12:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2020-09-11 12:26:47 +12:00
|
|
|
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
|
2021-03-03 05:38:12 +13:00
|
|
|
|
2023-06-26 09:26:31 +12:00
|
|
|
test "when multiple schemas apply to the same table, all identities are added" do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:title, :string, public?: true)
|
2023-06-26 09:26:31 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
identities do
|
|
|
|
identity(:unique_title, [:title])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defposts Post2 do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:name, :string, public?: true)
|
2023-06-26 09:26:31 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
identities do
|
|
|
|
identity(:unique_name, [:name])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post, Post2])
|
2023-06-26 09:26:31 +12:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2023-06-26 09:26:31 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [file1, file2] =
|
|
|
|
Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
|
|
|
|
|
|
|
file1_content = File.read!(file1)
|
|
|
|
|
|
|
|
assert file1_content =~
|
|
|
|
"create unique_index(:posts, [:title], name: \"posts_title_index\")"
|
|
|
|
|
|
|
|
file2_content = File.read!(file2)
|
|
|
|
|
|
|
|
assert file2_content =~
|
|
|
|
"drop_if_exists unique_index(:posts, [:title], name: \"posts_title_index\")"
|
|
|
|
|
|
|
|
assert file2_content =~
|
|
|
|
"create unique_index(:posts, [:name], name: \"posts_unique_name_index\")"
|
|
|
|
|
|
|
|
assert file2_content =~
|
|
|
|
"create unique_index(:posts, [:title], name: \"posts_unique_title_index\")"
|
|
|
|
end
|
|
|
|
|
2021-03-03 05:38:12 +13:00
|
|
|
test "when an attribute exists only on some of the resources that use the same table, it isn't marked as null: false" do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:title, :string, public?: true)
|
|
|
|
attribute(:example, :string, allow_nil?: false, public?: true)
|
2021-03-03 05:38:12 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defposts Post2 do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post, Post2])
|
2021-03-03 05:38:12 +13:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2021-03-03 05:38:12 +13:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [_file1, file2] =
|
|
|
|
Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
|
|
|
|
|
|
|
assert File.read!(file2) =~
|
|
|
|
~S[add :example, :text] <> "\n"
|
|
|
|
|
|
|
|
refute File.read!(file2) =~ ~S[null: false]
|
|
|
|
end
|
2020-09-11 12:26:47 +12:00
|
|
|
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
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:id, :integer,
|
|
|
|
generated?: true,
|
|
|
|
allow_nil?: false,
|
|
|
|
primary_key?: true,
|
|
|
|
public?: true
|
|
|
|
)
|
|
|
|
|
|
|
|
attribute(:views, :integer, public?: true)
|
2021-01-08 16:53:16 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2021-01-08 16:53:16 +13:00
|
|
|
|
|
|
|
Mix.shell(Mix.Shell.Process)
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2021-01-08 16:53:16 +13:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
|
2021-04-13 04:30:30 +12:00
|
|
|
test "when an integer is generated and default nil, it is a bigserial" do
|
2021-01-08 16:53:16 +13:00
|
|
|
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
|
|
|
|
|
|
|
assert File.read!(file) =~
|
2021-04-13 04:30:30 +12:00
|
|
|
~S[add :id, :bigserial, null: false, primary_key: true]
|
2021-01-08 16:53:16 +13:00
|
|
|
|
|
|
|
assert File.read!(file) =~
|
2021-04-13 06:13:23 +12:00
|
|
|
~S[add :views, :bigint]
|
2021-01-08 16:53:16 +13:00
|
|
|
end
|
|
|
|
end
|
2021-01-13 14:47:17 +13:00
|
|
|
|
2022-05-19 05:21:58 +12:00
|
|
|
describe "--check option" do
|
2021-01-13 14:47:17 +13:00
|
|
|
setup do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
2021-01-13 14:53:06 +13:00
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:title, :string, public?: true)
|
2021-01-13 14:47:17 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2021-01-13 14:47:17 +13:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
[domain: Domain]
|
2021-01-13 14:47:17 +13:00
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
test "returns code(1) if snapshots and resources don't fit", %{domain: domain} do
|
2021-01-13 14:47:17 +13:00
|
|
|
assert catch_exit(
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(domain,
|
2021-01-13 14:47:17 +13:00
|
|
|
snapshot_path: "test_snapshot_path",
|
|
|
|
migration_path: "test_migration_path",
|
2022-05-19 05:21:58 +12:00
|
|
|
check: true
|
2021-01-13 14:47:17 +13:00
|
|
|
)
|
|
|
|
) == {: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
|
|
|
|
2021-04-14 04:31:14 +12:00
|
|
|
describe "references" do
|
|
|
|
setup do
|
|
|
|
on_exit(fn ->
|
|
|
|
File.rm_rf!("test_snapshots_path")
|
|
|
|
File.rm_rf!("test_migration_path")
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
test "references are inferred automatically" do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:title, :string, public?: true)
|
|
|
|
attribute(:foobar, :string, public?: true)
|
2021-04-14 04:31:14 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defposts Post2 do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:name, :string, public?: true)
|
2021-04-14 04:31:14 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
relationships do
|
2024-03-28 09:52:28 +13:00
|
|
|
belongs_to(:post, Post, public?: true)
|
2021-04-14 04:31:14 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post, Post2])
|
2021-04-14 04:31:14 +12:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2021-04-14 04:31:14 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
|
|
|
|
|
|
|
assert File.read!(file) =~
|
2022-05-14 09:41:30 +12:00
|
|
|
~S[references(:posts, column: :id, name: "posts_post_id_fkey", type: :uuid, prefix: "public")]
|
2021-04-14 04:31:14 +12:00
|
|
|
end
|
|
|
|
|
2022-06-29 08:01:07 +12:00
|
|
|
test "references are inferred automatically if the attribute has a different type" do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:id, :string, primary_key?: true, allow_nil?: false, public?: true)
|
|
|
|
attribute(:title, :string, public?: true)
|
|
|
|
attribute(:foobar, :string, public?: true)
|
2022-06-29 08:01:07 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defposts Post2 do
|
|
|
|
attributes do
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:id, :string, primary_key?: true, allow_nil?: false, public?: true)
|
|
|
|
attribute(:name, :string, public?: true)
|
2022-06-29 08:01:07 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
relationships do
|
2024-03-28 09:52:28 +13:00
|
|
|
belongs_to(:post, Post, attribute_type: :string, public?: true)
|
2022-06-29 08:01:07 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post, Post2])
|
2022-06-29 08:01:07 +12:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2022-06-29 08:01:07 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
|
|
|
|
|
|
|
assert File.read!(file) =~
|
|
|
|
~S[references(:posts, column: :id, name: "posts_post_id_fkey", type: :text, prefix: "public")]
|
|
|
|
end
|
|
|
|
|
2023-11-21 10:52:50 +13:00
|
|
|
test "references allow passing :match_with and :match_type" do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:key_id, :uuid, allow_nil?: false, public?: true)
|
|
|
|
attribute(:foobar, :string, public?: true)
|
2023-11-21 10:52:50 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defposts Post2 do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:name, :string, public?: true)
|
|
|
|
attribute(:related_key_id, :uuid, public?: true)
|
2023-11-21 10:52:50 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
relationships do
|
2024-03-28 09:52:28 +13:00
|
|
|
belongs_to(:post, Post) do
|
|
|
|
public?(true)
|
|
|
|
end
|
2023-11-21 10:52:50 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
postgres do
|
|
|
|
references do
|
|
|
|
reference(:post, match_with: [related_key_id: :key_id], match_type: :partial)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post, Post2])
|
2023-11-21 10:52:50 +13:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2023-11-21 10:52:50 +13:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
|
|
|
|
|
|
|
assert File.read!(file) =~
|
|
|
|
~S{references(:posts, column: :id, with: [related_key_id: :key_id], match: :partial, name: "posts_post_id_fkey", type: :uuid, prefix: "public")}
|
|
|
|
end
|
|
|
|
|
|
|
|
test "references merge :match_with and multitenancy attribute" do
|
|
|
|
defresource Org, "orgs" do
|
|
|
|
attributes do
|
2024-03-28 09:52:28 +13:00
|
|
|
uuid_primary_key(:id, writable?: true, public?: true)
|
|
|
|
attribute(:name, :string, public?: true)
|
2023-11-21 10:52:50 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
multitenancy do
|
|
|
|
strategy(:attribute)
|
|
|
|
attribute(:id)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defresource User, "users" do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id, writable?: true)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:secondary_id, :uuid, public?: true)
|
|
|
|
attribute(:name, :string, public?: true)
|
|
|
|
attribute(:org_id, :uuid, public?: true)
|
|
|
|
attribute(:key_id, :uuid, public?: true)
|
2023-11-21 10:52:50 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
multitenancy do
|
|
|
|
strategy(:attribute)
|
|
|
|
attribute(:org_id)
|
|
|
|
end
|
|
|
|
|
|
|
|
relationships do
|
2024-03-28 09:52:28 +13:00
|
|
|
belongs_to(:org, Org) do
|
|
|
|
public?(true)
|
|
|
|
end
|
2023-11-21 10:52:50 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defresource UserThing, "user_things" do
|
|
|
|
attributes do
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:id, :string, primary_key?: true, allow_nil?: false, public?: true)
|
|
|
|
attribute(:name, :string, public?: true)
|
|
|
|
attribute(:org_id, :uuid, public?: true)
|
|
|
|
attribute(:related_key_id, :uuid, public?: true)
|
2023-11-21 10:52:50 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
multitenancy do
|
|
|
|
strategy(:attribute)
|
|
|
|
attribute(:org_id)
|
|
|
|
end
|
|
|
|
|
|
|
|
relationships do
|
2024-03-28 09:52:28 +13:00
|
|
|
belongs_to(:org, Org) do
|
|
|
|
public?(true)
|
|
|
|
end
|
|
|
|
|
|
|
|
belongs_to(:user, User, destination_attribute: :secondary_id, public?: true)
|
2023-11-21 10:52:50 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
postgres do
|
|
|
|
references do
|
|
|
|
reference(:user, match_with: [related_key_id: :key_id], match_type: :full)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Org, User, UserThing])
|
2023-11-21 10:52:50 +13:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2023-11-21 10:52:50 +13:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
|
|
|
|
|
|
|
assert File.read!(file) =~
|
|
|
|
~S{references(:users, column: :secondary_id, with: [related_key_id: :key_id, org_id: :org_id], match: :full, name: "user_things_user_id_fkey", type: :uuid, prefix: "public")}
|
|
|
|
end
|
|
|
|
|
2024-01-13 04:11:16 +13:00
|
|
|
test "identities using `all_tenants?: true` will not have the condition on multitenancy attribtue added" do
|
|
|
|
defresource Org, "orgs" do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id, writable?: true)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:name, :string, public?: true)
|
2024-01-13 04:11:16 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
multitenancy do
|
|
|
|
strategy(:attribute)
|
|
|
|
attribute(:id)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defresource User, "users" do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id, writable?: true)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:secondary_id, :uuid, public?: true)
|
|
|
|
attribute(:name, :string, public?: true)
|
|
|
|
attribute(:org_id, :uuid, public?: true)
|
|
|
|
attribute(:key_id, :uuid, public?: true)
|
2024-01-13 04:11:16 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
multitenancy do
|
|
|
|
strategy(:attribute)
|
|
|
|
attribute(:org_id)
|
|
|
|
end
|
|
|
|
|
|
|
|
identities do
|
|
|
|
identity(:unique_name, [:name], all_tenants?: true)
|
|
|
|
end
|
|
|
|
|
|
|
|
relationships do
|
2024-03-28 09:52:28 +13:00
|
|
|
belongs_to(:org, Org) do
|
|
|
|
public?(true)
|
|
|
|
end
|
2024-01-13 04:11:16 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Org, User])
|
2024-01-13 04:11:16 +13:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2024-01-13 04:11:16 +13:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
|
|
|
|
|
|
|
assert File.read!(file) =~
|
|
|
|
~S{create unique_index(:users, [:name], name: "users_unique_name_index")}
|
|
|
|
end
|
|
|
|
|
2021-04-14 04:31:14 +12:00
|
|
|
test "when modified, the foreign key is dropped before modification" do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:title, :string, public?: true)
|
|
|
|
attribute(:foobar, :string, public?: true)
|
2021-04-14 04:31:14 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defposts Post2 do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:name, :string, public?: true)
|
2021-04-14 04:31:14 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
relationships do
|
2024-03-28 09:52:28 +13:00
|
|
|
belongs_to(:post, Post) do
|
|
|
|
public?(true)
|
|
|
|
end
|
2021-04-14 04:31:14 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post, Post2])
|
2021-04-14 04:31:14 +12:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2021-04-14 04:31:14 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
defposts Post2 do
|
|
|
|
postgres do
|
|
|
|
references do
|
2022-08-19 06:56:36 +12:00
|
|
|
reference(:post, name: "special_post_fkey", on_delete: :delete, on_update: :update)
|
2021-04-14 04:31:14 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:name, :string, public?: true)
|
2021-04-14 04:31:14 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
relationships do
|
2024-03-28 09:52:28 +13:00
|
|
|
belongs_to(:post, Post) do
|
|
|
|
public?(true)
|
|
|
|
end
|
2021-04-14 04:31:14 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2021-04-14 04:31:14 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert file =
|
|
|
|
"test_migration_path/**/*_migrate_resources*.exs"
|
|
|
|
|> Path.wildcard()
|
|
|
|
|> Enum.sort()
|
|
|
|
|> Enum.at(1)
|
2023-05-02 02:51:09 +12:00
|
|
|
|> File.read!()
|
2021-04-14 04:31:14 +12:00
|
|
|
|
2023-05-02 02:51:09 +12:00
|
|
|
assert file =~
|
|
|
|
~S[references(:posts, column: :id, name: "special_post_fkey", type: :uuid, prefix: "public", on_delete: :delete_all, on_update: :update_all)]
|
|
|
|
|
|
|
|
assert file =~ ~S[drop constraint(:posts, "posts_post_id_fkey")]
|
|
|
|
|
|
|
|
assert [_, down_code] = String.split(file, "def down do")
|
|
|
|
|
|
|
|
assert [_, after_drop] =
|
|
|
|
String.split(down_code, "drop constraint(:posts, \"special_post_fkey\")")
|
2021-04-14 04:31:14 +12:00
|
|
|
|
2023-05-02 02:51:09 +12:00
|
|
|
assert after_drop =~ ~S[references(:posts]
|
2021-04-14 04:31:14 +12:00
|
|
|
end
|
2023-09-26 08:33:28 +13:00
|
|
|
|
|
|
|
test "references with added only when needed on multitenant resources" do
|
|
|
|
defresource Org, "orgs" do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id, writable?: true)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:name, :string, public?: true)
|
2023-09-26 08:33:28 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
multitenancy do
|
|
|
|
strategy(:attribute)
|
|
|
|
attribute(:id)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defresource User, "users" do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id, writable?: true)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:secondary_id, :uuid, public?: true)
|
|
|
|
attribute(:name, :string, public?: true)
|
|
|
|
attribute(:org_id, :uuid, public?: true)
|
2023-09-26 08:33:28 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
multitenancy do
|
|
|
|
strategy(:attribute)
|
|
|
|
attribute(:org_id)
|
|
|
|
end
|
|
|
|
|
|
|
|
relationships do
|
2024-03-28 09:52:28 +13:00
|
|
|
belongs_to(:org, Org) do
|
|
|
|
public?(true)
|
|
|
|
end
|
2023-09-26 08:33:28 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defresource UserThing1, "user_things1" do
|
|
|
|
attributes do
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:id, :string, primary_key?: true, allow_nil?: false, public?: true)
|
|
|
|
attribute(:name, :string, public?: true)
|
|
|
|
attribute(:org_id, :uuid, public?: true)
|
2023-09-26 08:33:28 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
multitenancy do
|
|
|
|
strategy(:attribute)
|
|
|
|
attribute(:org_id)
|
|
|
|
end
|
|
|
|
|
|
|
|
relationships do
|
2024-03-28 09:52:28 +13:00
|
|
|
belongs_to(:org, Org) do
|
|
|
|
public?(true)
|
|
|
|
end
|
|
|
|
|
|
|
|
belongs_to(:user, User, destination_attribute: :secondary_id, public?: true)
|
2023-09-26 08:33:28 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defresource UserThing2, "user_things2" do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id, writable?: true)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:name, :string, public?: true)
|
2023-09-26 08:33:28 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
multitenancy do
|
|
|
|
strategy(:attribute)
|
|
|
|
attribute(:org_id)
|
|
|
|
end
|
|
|
|
|
|
|
|
relationships do
|
2024-03-28 09:52:28 +13:00
|
|
|
belongs_to(:org, Org) do
|
|
|
|
public?(true)
|
|
|
|
end
|
|
|
|
|
|
|
|
belongs_to(:user, User) do
|
|
|
|
public?(true)
|
|
|
|
end
|
2023-09-26 08:33:28 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Org, User, UserThing1, UserThing2])
|
2023-09-26 08:33:28 +13:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2023-09-26 08:33:28 +13:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
|
|
|
|
|
|
|
assert File.read!(file) =~
|
|
|
|
~S[references(:users, column: :secondary_id, with: [org_id: :org_id\], match: :full, name: "user_things1_user_id_fkey", type: :uuid, prefix: "public")]
|
|
|
|
|
|
|
|
assert File.read!(file) =~
|
|
|
|
~S[references(:users, column: :id, name: "user_things2_user_id_fkey", type: :uuid, prefix: "public")]
|
|
|
|
end
|
2024-05-17 12:18:17 +12:00
|
|
|
|
|
|
|
test "references on_delete: {:nilify, columns} works with multitenant resources" do
|
|
|
|
defresource Tenant, "tenants" do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
|
|
|
end
|
|
|
|
|
|
|
|
multitenancy do
|
|
|
|
strategy(:attribute)
|
|
|
|
attribute(:id)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defresource Group, "groups" do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
|
|
|
end
|
|
|
|
|
|
|
|
multitenancy do
|
|
|
|
strategy(:attribute)
|
|
|
|
attribute(:tenant_id)
|
|
|
|
end
|
|
|
|
|
|
|
|
relationships do
|
|
|
|
belongs_to(:tenant, Tenant)
|
|
|
|
end
|
|
|
|
|
|
|
|
postgres do
|
|
|
|
references do
|
|
|
|
reference(:tenant, on_delete: :delete)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defresource Item, "items" do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
|
|
|
end
|
|
|
|
|
|
|
|
multitenancy do
|
|
|
|
strategy(:attribute)
|
|
|
|
attribute(:tenant_id)
|
|
|
|
end
|
|
|
|
|
|
|
|
relationships do
|
|
|
|
belongs_to(:group, Group)
|
|
|
|
belongs_to(:tenant, Tenant)
|
|
|
|
end
|
|
|
|
|
|
|
|
postgres do
|
|
|
|
references do
|
|
|
|
reference(:group,
|
|
|
|
match_with: [tenant_id: :tenant_id],
|
|
|
|
on_delete: {:nilify, [:group_id]}
|
|
|
|
)
|
|
|
|
|
|
|
|
reference(:tenant, on_delete: :delete)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defdomain([Tenant, Group, Item])
|
|
|
|
|
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
|
|
|
|
|
|
|
assert File.read!(file) =~
|
|
|
|
~S<references(:groups, column: :id, with: [tenant_id: :tenant_id], name: "items_group_id_fkey", type: :uuid, prefix: "public", on_delete: {:nilify, [:group_id]}>
|
|
|
|
end
|
2021-04-14 04:31:14 +12:00
|
|
|
end
|
|
|
|
|
2021-04-20 06:26:41 +12:00
|
|
|
describe "check constraints" do
|
|
|
|
setup do
|
|
|
|
on_exit(fn ->
|
|
|
|
File.rm_rf!("test_snapshots_path")
|
|
|
|
File.rm_rf!("test_migration_path")
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
test "when added, the constraint is created" do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:price, :integer, public?: true)
|
2021-04-20 06:26:41 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
postgres do
|
|
|
|
check_constraints do
|
|
|
|
check_constraint(:price, "price_must_be_positive", check: "price > 0")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2021-04-20 06:26:41 +12:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2021-04-20 06:26:41 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert file =
|
|
|
|
"test_migration_path/**/*_migrate_resources*.exs"
|
|
|
|
|> Path.wildcard()
|
|
|
|
|> Enum.sort()
|
|
|
|
|> Enum.at(0)
|
2022-07-22 17:01:32 +12:00
|
|
|
|> File.read!()
|
2021-04-20 06:26:41 +12:00
|
|
|
|
2022-07-22 17:01:32 +12:00
|
|
|
assert file =~
|
|
|
|
~S[create constraint(:posts, :price_must_be_positive, check: "price > 0")]
|
|
|
|
|
|
|
|
defposts do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:price, :integer, public?: true)
|
2022-07-22 17:01:32 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
postgres do
|
|
|
|
check_constraints do
|
|
|
|
check_constraint(:price, "price_must_be_positive", check: "price > 1")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2022-07-22 17:01:32 +12:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2022-07-22 17:01:32 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert file =
|
|
|
|
"test_migration_path/**/*_migrate_resources*.exs"
|
|
|
|
|> Path.wildcard()
|
|
|
|
|> Enum.sort()
|
|
|
|
|> Enum.at(1)
|
|
|
|
|> File.read!()
|
|
|
|
|
|
|
|
assert [_, down] = String.split(file, "def down do")
|
|
|
|
|
|
|
|
assert [_, remaining] =
|
|
|
|
String.split(down, "drop_if_exists constraint(:posts, :price_must_be_positive)")
|
|
|
|
|
|
|
|
assert remaining =~
|
2021-04-20 06:26:41 +12:00
|
|
|
~S[create constraint(:posts, :price_must_be_positive, check: "price > 0")]
|
|
|
|
end
|
|
|
|
|
|
|
|
test "when removed, the constraint is dropped before modification" do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:price, :integer, public?: true)
|
2021-04-20 06:26:41 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
postgres do
|
|
|
|
check_constraints do
|
|
|
|
check_constraint(:price, "price_must_be_positive", check: "price > 0")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2021-04-20 06:26:41 +12:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2021-04-20 06:26:41 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
defposts do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:price, :integer, public?: true)
|
2021-04-20 06:26:41 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2021-04-20 06:26:41 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert file =
|
|
|
|
"test_migration_path/**/*_migrate_resources*.exs"
|
|
|
|
|> Path.wildcard()
|
|
|
|
|> Enum.sort()
|
|
|
|
|> Enum.at(1)
|
|
|
|
|
|
|
|
assert File.read!(file) =~
|
|
|
|
~S[drop_if_exists constraint(:posts, :price_must_be_positive)]
|
|
|
|
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,
|
2024-03-28 09:52:28 +13:00
|
|
|
domain: nil,
|
2021-02-07 09:05:37 +13:00
|
|
|
data_layer: AshPostgres.DataLayer
|
|
|
|
|
|
|
|
postgres do
|
2022-08-19 06:56:36 +12:00
|
|
|
polymorphic?(true)
|
|
|
|
repo(AshPostgres.TestRepo)
|
2021-02-07 09:05:37 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:resource_id, :uuid, public?: true)
|
2021-02-07 09:05:37 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
actions do
|
2022-04-20 03:08:28 +12:00
|
|
|
defaults([:create, :read, :update, :destroy])
|
2021-02-07 09:05:37 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defmodule Post do
|
|
|
|
use Ash.Resource,
|
2024-03-28 09:52:28 +13:00
|
|
|
domain: nil,
|
2021-02-07 09:05:37 +13:00
|
|
|
data_layer: AshPostgres.DataLayer
|
|
|
|
|
|
|
|
postgres do
|
|
|
|
table "posts"
|
2022-08-19 06:56:36 +12:00
|
|
|
repo(AshPostgres.TestRepo)
|
2021-02-07 09:05:37 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
actions do
|
2022-04-20 03:08:28 +12:00
|
|
|
defaults([:create, :read, :update, :destroy])
|
2021-02-07 09:05:37 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
|
|
|
end
|
|
|
|
|
|
|
|
relationships do
|
|
|
|
has_many(:comments, Comment,
|
2024-03-28 09:52:28 +13:00
|
|
|
public?: true,
|
2022-08-19 06:56:36 +12:00
|
|
|
destination_attribute: :resource_id,
|
2021-05-14 17:20:10 +12:00
|
|
|
relationship_context: %{data_layer: %{table: "post_comments"}}
|
2021-02-07 09:05:37 +13:00
|
|
|
)
|
2021-02-07 09:52:47 +13:00
|
|
|
|
|
|
|
belongs_to(:best_comment, Comment,
|
2024-03-28 09:52:28 +13:00
|
|
|
public?: true,
|
2022-08-19 06:56:36 +12:00
|
|
|
destination_attribute: :id,
|
2021-05-14 17:20:10 +12:00
|
|
|
relationship_context: %{data_layer: %{table: "post_comments"}}
|
2021-02-07 09:52:47 +13:00
|
|
|
)
|
2021-02-07 09:05:37 +13:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post, Comment])
|
2021-02-07 09:05:37 +13:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2021-02-07 09:05:37 +13:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
[domain: Domain]
|
2021-02-07 09:05:37 +13:00
|
|
|
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) =~
|
2023-04-22 04:43:58 +12:00
|
|
|
~S[references(:post_comments, column: :id, name: "posts_best_comment_id_fkey", type: :uuid, prefix: "public")]
|
2021-02-07 09:05:37 +13:00
|
|
|
end
|
|
|
|
end
|
2022-04-19 16:06:02 +12:00
|
|
|
|
|
|
|
describe "default values" do
|
|
|
|
setup do
|
|
|
|
on_exit(fn ->
|
|
|
|
File.rm_rf!("test_snapshots_path")
|
|
|
|
File.rm_rf!("test_migration_path")
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
test "when default value is specified that implements EctoMigrationDefault" do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:start_date, :date, default: ~D[2022-04-19], public?: true)
|
|
|
|
attribute(:start_time, :time, default: ~T[08:30:45], public?: true)
|
|
|
|
attribute(:timestamp, :utc_datetime, default: ~U[2022-02-02 08:30:30Z], public?: true)
|
|
|
|
|
|
|
|
attribute(:timestamp_naive, :naive_datetime,
|
|
|
|
default: ~N[2022-02-02 08:30:30],
|
|
|
|
public?: true
|
|
|
|
)
|
|
|
|
|
|
|
|
attribute(:number, :integer, default: 5, public?: true)
|
|
|
|
attribute(:fraction, :float, default: 0.25, public?: true)
|
|
|
|
|
|
|
|
attribute(:decimal, :decimal,
|
|
|
|
default: Decimal.new("123.4567890987654321987"),
|
|
|
|
public?: true
|
|
|
|
)
|
|
|
|
|
|
|
|
attribute(:name, :string, default: "Fred", public?: true)
|
|
|
|
attribute(:tag, :atom, default: :value, public?: true)
|
|
|
|
attribute(:enabled, :boolean, default: false, public?: true)
|
2022-04-19 16:06:02 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2022-04-19 16:06:02 +12:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2022-04-19 16:06:02 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [file1] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
|
|
|
|
2022-04-22 02:36:34 +12:00
|
|
|
file = File.read!(file1)
|
|
|
|
|
|
|
|
assert file =~
|
2022-04-19 16:06:02 +12:00
|
|
|
~S[add :start_date, :date, default: fragment("'2022-04-19'")]
|
|
|
|
|
2022-04-22 02:36:34 +12:00
|
|
|
assert file =~
|
2022-04-19 16:06:02 +12:00
|
|
|
~S[add :start_time, :time, default: fragment("'08:30:45'")]
|
|
|
|
|
2022-04-22 02:36:34 +12:00
|
|
|
assert file =~
|
2022-04-19 16:06:02 +12:00
|
|
|
~S[add :timestamp, :utc_datetime, default: fragment("'2022-02-02 08:30:30Z'")]
|
|
|
|
|
2022-04-22 02:36:34 +12:00
|
|
|
assert file =~
|
2022-04-19 16:06:02 +12:00
|
|
|
~S[add :timestamp_naive, :naive_datetime, default: fragment("'2022-02-02 08:30:30'")]
|
|
|
|
|
2022-04-22 02:36:34 +12:00
|
|
|
assert file =~
|
2022-04-19 16:06:02 +12:00
|
|
|
~S[add :number, :bigint, default: 5]
|
|
|
|
|
2022-04-28 09:10:51 +12:00
|
|
|
assert file =~
|
|
|
|
~S[add :fraction, :float, default: 0.25]
|
|
|
|
|
2022-04-29 02:48:44 +12:00
|
|
|
assert file =~
|
|
|
|
~S[add :decimal, :decimal, default: "123.4567890987654321987"]
|
|
|
|
|
2022-04-22 02:36:34 +12:00
|
|
|
assert file =~
|
2022-04-19 16:06:02 +12:00
|
|
|
~S[add :name, :text, default: "Fred"]
|
2022-04-22 02:36:34 +12:00
|
|
|
|
|
|
|
assert file =~
|
|
|
|
~S[add :tag, :text, default: "value"]
|
|
|
|
|
|
|
|
assert file =~
|
|
|
|
~S[add :enabled, :boolean, default: false]
|
2022-04-19 16:06:02 +12:00
|
|
|
end
|
2022-05-25 04:11:32 +12:00
|
|
|
|
|
|
|
test "when default value is specified that does not implement EctoMigrationDefault" do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:product_code, :term, default: {"xyz"}, public?: true)
|
2022-05-25 04:11:32 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post])
|
2022-05-25 04:11:32 +12:00
|
|
|
|
|
|
|
log =
|
|
|
|
capture_log(fn ->
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2022-05-25 04:11:32 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
end)
|
|
|
|
|
|
|
|
assert log =~ "`{\"xyz\"}`"
|
|
|
|
|
|
|
|
assert [file1] = Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
|
|
|
|
|
|
|
file = File.read!(file1)
|
|
|
|
|
|
|
|
assert file =~
|
2023-04-22 04:43:58 +12:00
|
|
|
~S[add :product_code, :binary]
|
2022-05-25 04:11:32 +12:00
|
|
|
end
|
2022-04-19 16:06:02 +12:00
|
|
|
end
|
2023-04-12 09:41:53 +12:00
|
|
|
|
|
|
|
describe "follow up with references" do
|
|
|
|
setup do
|
|
|
|
on_exit(fn ->
|
|
|
|
File.rm_rf!("test_snapshots_path")
|
|
|
|
File.rm_rf!("test_migration_path")
|
|
|
|
end)
|
|
|
|
|
|
|
|
defposts do
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:title, :string, public?: true)
|
2023-04-12 09:41:53 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defmodule Comment do
|
|
|
|
use Ash.Resource,
|
2024-03-28 09:52:28 +13:00
|
|
|
domain: nil,
|
2023-04-12 09:41:53 +12:00
|
|
|
data_layer: AshPostgres.DataLayer
|
|
|
|
|
|
|
|
postgres do
|
|
|
|
table "comments"
|
|
|
|
repo AshPostgres.TestRepo
|
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
|
|
|
end
|
|
|
|
|
|
|
|
relationships do
|
2024-03-28 09:52:28 +13:00
|
|
|
belongs_to(:post, Post) do
|
|
|
|
public?(true)
|
|
|
|
end
|
2023-04-12 09:41:53 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post, Comment])
|
2023-04-12 09:41:53 +12:00
|
|
|
|
|
|
|
Mix.shell(Mix.Shell.Process)
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2023-04-12 09:41:53 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
|
|
|
|
test "when changing the primary key, it changes properly" do
|
|
|
|
defposts do
|
|
|
|
attributes do
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:id, :uuid,
|
|
|
|
primary_key?: false,
|
|
|
|
default: &Ecto.UUID.generate/0,
|
|
|
|
public?: true
|
|
|
|
)
|
|
|
|
|
2023-04-12 09:41:53 +12:00
|
|
|
uuid_primary_key(:guid)
|
2024-03-28 09:52:28 +13:00
|
|
|
attribute(:title, :string, public?: true)
|
2023-04-12 09:41:53 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defmodule Comment do
|
|
|
|
use Ash.Resource,
|
2024-03-28 09:52:28 +13:00
|
|
|
domain: nil,
|
2023-04-12 09:41:53 +12:00
|
|
|
data_layer: AshPostgres.DataLayer
|
|
|
|
|
|
|
|
postgres do
|
|
|
|
table "comments"
|
|
|
|
repo AshPostgres.TestRepo
|
|
|
|
end
|
|
|
|
|
|
|
|
attributes do
|
|
|
|
uuid_primary_key(:id)
|
|
|
|
end
|
|
|
|
|
|
|
|
relationships do
|
2024-03-28 09:52:28 +13:00
|
|
|
belongs_to(:post, Post) do
|
|
|
|
public?(true)
|
|
|
|
end
|
2023-04-12 09:41:53 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
defdomain([Post, Comment])
|
2023-04-12 09:41:53 +12:00
|
|
|
|
2024-03-28 09:52:28 +13:00
|
|
|
AshPostgres.MigrationGenerator.generate(Domain,
|
2023-04-12 09:41:53 +12:00
|
|
|
snapshot_path: "test_snapshots_path",
|
|
|
|
migration_path: "test_migration_path",
|
|
|
|
quiet: true,
|
|
|
|
format: false
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [_file1, file2] =
|
|
|
|
Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
|
|
|
|
|
|
|
file = File.read!(file2)
|
|
|
|
|
|
|
|
assert [before_index_drop, after_index_drop] =
|
|
|
|
String.split(file, ~S[drop constraint("posts", "posts_pkey")], parts: 2)
|
|
|
|
|
|
|
|
assert before_index_drop =~ ~S[drop constraint(:comments, "comments_post_id_fkey")]
|
|
|
|
|
|
|
|
assert after_index_drop =~ ~S[modify :id, :uuid, null: true, primary_key: false]
|
|
|
|
|
|
|
|
assert after_index_drop =~
|
2023-05-02 02:51:09 +12:00
|
|
|
~S[modify :post_id, references(:posts, column: :id, name: "comments_post_id_fkey", type: :uuid, prefix: "public")]
|
2023-04-12 09:41:53 +12:00
|
|
|
end
|
|
|
|
end
|
2020-09-11 12:26:47 +12:00
|
|
|
end
|