ash/test/seed_test.exs

373 lines
9.1 KiB
Elixir

defmodule Ash.Test.SeedTest do
@moduledoc false
use ExUnit.Case, async: true
import Ash.Seed
require Ash.Query
alias Ash.Test.Domain, as: Domain
defmodule Tenant do
use Ash.Resource,
domain: Domain,
data_layer: Ash.DataLayer.Ets
ets do
private?(true)
end
actions do
default_accept :*
defaults [:read, :destroy, create: :*, update: :*]
end
attributes do
uuid_primary_key :id
attribute :name, :string, public?: true, allow_nil?: false
end
end
defmodule ContextUser do
use Ash.Resource,
domain: Domain,
data_layer: Ash.DataLayer.Ets
ets do
private?(true)
end
multitenancy do
strategy :context
end
actions do
default_accept :*
defaults [:read, :destroy, create: :*, update: :*]
end
attributes do
uuid_primary_key :id
attribute :name, :string, public?: true, allow_nil?: false
end
end
defmodule AttributeUser do
use Ash.Resource,
domain: Domain,
data_layer: Ash.DataLayer.Ets
ets do
private?(true)
end
multitenancy do
strategy :attribute
attribute :tenant_id
end
actions do
default_accept :*
defaults [:read, :destroy, create: :*, update: :*]
end
attributes do
uuid_primary_key :id
attribute :name, :string, public?: true, allow_nil?: false
end
relationships do
belongs_to :tenant, Ash.Test.SeedTest.Tenant
end
end
defmodule Author do
@moduledoc false
use Ash.Resource,
domain: Domain,
data_layer: Ash.DataLayer.Ets
ets do
private?(true)
end
actions do
default_accept :*
defaults [:read, :destroy, create: :*, update: :*]
end
attributes do
uuid_primary_key :id
attribute :name, :string, default: "Fred", public?: true
end
relationships do
has_many :posts, Ash.Test.SeedTest.Post, destination_attribute: :author_id, public?: true
has_one :latest_post, Ash.Test.SeedTest.Post,
destination_attribute: :author_id,
sort: [inserted_at: :desc],
public?: true
end
end
defmodule Post do
@moduledoc false
use Ash.Resource, domain: Domain, data_layer: Ash.DataLayer.Ets
ets do
private?(true)
end
actions do
default_accept :*
defaults [:read, :destroy, create: :*, update: :*]
end
attributes do
uuid_primary_key :id
attribute :title, :string do
public?(true)
end
attribute :contents, :string do
public?(true)
end
attribute :category, :string do
public?(true)
end
timestamps()
end
relationships do
belongs_to :author, Author, public?: true
has_many :ratings, Ash.Test.SeedTest.Rating do
public?(true)
domain(Ash.Test.SeedTest.Domain2)
end
many_to_many :categories, Ash.Test.SeedTest.Category,
public?: true,
through: Ash.Test.SeedTest.PostCategory,
destination_attribute_on_join_resource: :category_id,
source_attribute_on_join_resource: :post_id
end
end
defmodule PostCategory do
@moduledoc false
use Ash.Resource, domain: Domain, data_layer: Ash.DataLayer.Ets
ets do
private?(true)
end
actions do
default_accept :*
defaults [:read, :destroy, create: :*, update: :*]
end
relationships do
belongs_to :post, Post, primary_key?: true, allow_nil?: false, public?: true
belongs_to :category, Ash.Test.SeedTest.Category,
primary_key?: true,
allow_nil?: false,
public?: true
end
end
defmodule Category do
@moduledoc false
use Ash.Resource, domain: Domain, data_layer: Ash.DataLayer.Ets
ets do
private?(true)
end
actions do
default_accept :*
defaults [:read, :destroy, create: :*, update: :*]
end
attributes do
uuid_primary_key :id
attribute :name, :string do
public?(true)
end
end
relationships do
many_to_many :posts, Post,
public?: true,
through: PostCategory,
destination_attribute_on_join_resource: :post_id,
source_attribute_on_join_resource: :category_id
end
end
defmodule Rating do
use Ash.Resource,
domain: Ash.Test.SeedTest.Domain2,
data_layer: Ash.DataLayer.Ets
ets do
private? true
end
attributes do
uuid_primary_key :id
attribute :rating, :integer do
public?(true)
end
end
actions do
default_accept :*
defaults [:read, :destroy, create: :*, update: :*]
end
relationships do
belongs_to :post, Post do
public?(true)
domain(Domain)
end
end
end
defmodule Domain2 do
@moduledoc false
use Ash.Domain
resources do
resource(Rating)
end
end
describe "seed!/1" do
test "it creates a single record with resource and input" do
assert %Post{id: id, title: "seeded"} = seed!(Post, %{title: "seeded"})
assert post = Ash.get!(Post, id)
assert post.title == "seeded"
end
test "it creates a single record with a struct" do
assert %Post{id: id, title: "seeded"} = seed!(%Post{title: "seeded"})
assert post = Ash.get!(Post, id)
assert post.title == "seeded"
end
test "defaults are set when using a struct" do
assert %Author{name: "Fred"} = seed!(%Author{})
assert %Author{name: "Fred"} = seed!(%Author{})
end
test "it creates related entities" do
assert %Post{
id: id,
title: "seeded",
categories: [%Category{name: "foo"}, %Category{name: "bar"}],
author: %Author{name: "ted dansen"},
ratings: [%Rating{rating: 1}, %Rating{rating: 2}]
} =
seed!(%Post{
title: "seeded",
categories: [%Category{name: "foo"}, %Category{name: "bar"}],
author: %Author{name: "ted dansen"},
ratings: [%Rating{rating: 1}, %Rating{rating: 2}]
})
assert %Post{
id: ^id,
title: "seeded",
categories: categories,
author: %Author{name: "ted dansen"},
ratings: ratings
} = Post |> Ash.get!(id) |> Ash.load!([:categories, :author, :ratings])
assert categories |> Enum.map(& &1.name) |> Enum.sort() == ["bar", "foo"]
assert ratings |> Enum.map(& &1.rating) |> Enum.sort() == [1, 2]
end
test "it reuses entities that have been loaded (doesnt try to create a copy)" do
assert %Post{
id: id,
title: "seeded",
categories: [%Category{name: "foo"}, %Category{name: "bar"}],
author: %Author{name: "ted dansen"},
ratings: [%Rating{rating: 1}, %Rating{rating: 2}]
} =
seed!(%Post{
title: "seeded",
categories: [%Category{name: "foo"}, %Category{name: "bar"}],
author: %Author{name: "ted dansen"},
ratings: [%Rating{rating: 1}, %Rating{rating: 2}]
})
assert %Post{
id: ^id,
title: "seeded",
categories: categories,
author: author,
ratings: ratings
} = Post |> Ash.get!(id) |> Ash.load!([:categories, :author, :ratings])
assert %Post{id: id} =
seed!(%Post{
title: "seeded2",
categories: categories,
author: author,
ratings: ratings
})
assert %Post{
id: ^id,
title: "seeded2",
categories: categories,
author: author,
ratings: ratings
} = Post |> Ash.get!(id) |> Ash.load!([:categories, :author, :ratings])
assert categories |> Enum.map(& &1.name) |> Enum.sort() == ["bar", "foo"]
assert ratings |> Enum.map(& &1.rating) |> Enum.sort() == [1, 2]
assert author.name == "ted dansen"
assert Enum.count(Ash.read!(Category)) == 2
assert Enum.count(Ash.read!(Rating)) == 2
assert Enum.count(Ash.read!(Author)) == 1
end
test "context multitenancy works" do
tenant = seed!(%Tenant{name: "Tenant"})
tenant_id = tenant.id
user = seed!(ContextUser, %{name: "User"}, tenant: tenant_id)
user_id = user.id
assert {:ok, %ContextUser{id: ^user_id}} = Ash.get(ContextUser, user_id, tenant: tenant_id)
assert {:error, %{errors: [%Ash.Error.Query.NotFound{}]}} =
Ash.get(ContextUser, user_id, tenant: "random")
end
test "attribute multitenancy works" do
tenant = seed!(%Tenant{name: "Tenant"})
tenant_id = tenant.id
user = seed!(AttributeUser, %{name: "User"}, tenant: tenant_id)
user_id = user.id
assert {:ok, %AttributeUser{id: ^user_id}} =
Ash.get(AttributeUser, user_id, tenant: tenant_id)
assert {:error, %{errors: [%Ash.Error.Query.NotFound{}]}} =
Ash.get(AttributeUser, user_id, tenant: "random")
end
end
end