mirror of
https://github.com/ash-project/ash_postgres.git
synced 2024-09-20 05:23:18 +12:00
improvement: inform users about postgres incompatibility with multidimensional arrays
This commit is contained in:
parent
f088601cf9
commit
52fcba79ac
5 changed files with 80 additions and 37 deletions
|
@ -416,7 +416,8 @@ defmodule AshPostgres.DataLayer do
|
||||||
sections: @sections,
|
sections: @sections,
|
||||||
transformers: [
|
transformers: [
|
||||||
AshPostgres.Transformers.VerifyRepo,
|
AshPostgres.Transformers.VerifyRepo,
|
||||||
AshPostgres.Transformers.EnsureTableOrPolymorphic
|
AshPostgres.Transformers.EnsureTableOrPolymorphic,
|
||||||
|
AshPostgres.Transformers.PreventMultidimensionalArrayAggregates
|
||||||
]
|
]
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
defmodule AshPostgres.Transformers.PreventMultidimensionalArrayAggregates do
|
||||||
|
@moduledoc "Prevents at compile time certain aggregates that are unsupported by `AshPostgres`"
|
||||||
|
use Spark.Dsl.Transformer
|
||||||
|
alias Spark.Dsl.Transformer
|
||||||
|
|
||||||
|
def after_compile?, do: true
|
||||||
|
|
||||||
|
def transform(dsl) do
|
||||||
|
resource = Transformer.get_persisted(dsl, :module)
|
||||||
|
|
||||||
|
dsl
|
||||||
|
|> Ash.Resource.Info.aggregates()
|
||||||
|
|> Stream.filter(&(&1.kind in [:list, :first]))
|
||||||
|
|> Stream.filter(& &1.field)
|
||||||
|
|> Enum.each(fn aggregate ->
|
||||||
|
related = Ash.Resource.Info.related(resource, aggregate.relationship_path)
|
||||||
|
type = Ash.Resource.Info.attribute(related, aggregate.field).type
|
||||||
|
|
||||||
|
case type do
|
||||||
|
{:array, _} ->
|
||||||
|
raise Spark.Error.DslError,
|
||||||
|
module: resource,
|
||||||
|
path: [:aggregates, aggregate.name],
|
||||||
|
message: """
|
||||||
|
Aggregate not supported.
|
||||||
|
|
||||||
|
Aggregate #{inspect(resource)}.#{aggregate.name} is not supported, because its type is `#{aggregate.kind}`, and the destination attribute is an array.
|
||||||
|
|
||||||
|
Postgres does not support multidimensional arrays with differing lengths internally. In the future we may be able to remove this restriction
|
||||||
|
for the `:first` type aggregate, but likely never for `:list`. In the meantime, you will have to use a custom calculation to get this data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
repo = Transformer.get_option(dsl, [:postgres], :repo)
|
||||||
|
|
||||||
|
cond do
|
||||||
|
match?({:error, _}, Code.ensure_compiled(repo)) ->
|
||||||
|
{:error, "Could not find repo module #{repo}"}
|
||||||
|
|
||||||
|
repo.__adapter__() != Ecto.Adapters.Postgres ->
|
||||||
|
{:error, "Expected a repo using the postgres adapter `Ecto.Adapters.Postgres`"}
|
||||||
|
|
||||||
|
true ->
|
||||||
|
{:ok, dsl}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,6 +3,8 @@ defmodule AshPostgres.Transformers.VerifyRepo do
|
||||||
use Spark.Dsl.Transformer
|
use Spark.Dsl.Transformer
|
||||||
alias Spark.Dsl.Transformer
|
alias Spark.Dsl.Transformer
|
||||||
|
|
||||||
|
def after_compile?, do: true
|
||||||
|
|
||||||
def transform(dsl) do
|
def transform(dsl) do
|
||||||
repo = Transformer.get_option(dsl, [:postgres], :repo)
|
repo = Transformer.get_option(dsl, [:postgres], :repo)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
defmodule AshPostgres.AggregateTest do
|
defmodule AshPostgres.AggregateTest do
|
||||||
use AshPostgres.RepoCase, async: false
|
use AshPostgres.RepoCase, async: false
|
||||||
alias AshPostgres.Test.{Api, Comment, Post, Rating, Author, Profile}
|
alias AshPostgres.Test.{Api, Comment, Post, Rating}
|
||||||
|
|
||||||
require Ash.Query
|
require Ash.Query
|
||||||
|
|
||||||
|
@ -236,43 +236,36 @@ defmodule AshPostgres.AggregateTest do
|
||||||
|> Ash.Query.sort(:first_comment)
|
|> Ash.Query.sort(:first_comment)
|
||||||
|> Api.read_one!()
|
|> Api.read_one!()
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test "on an array composite type" do
|
test "can't define multidimensional array aggregate types" do
|
||||||
author =
|
assert_raise Spark.Error.DslError, ~r/Aggregate not supported/, fn ->
|
||||||
Author
|
defmodule Foo do
|
||||||
|> Ash.Changeset.for_create(:create, %{badges: [:author_of_the_year]})
|
@moduledoc false
|
||||||
|> Api.create!()
|
use Ash.Resource,
|
||||||
|
data_layer: AshPostgres.DataLayer
|
||||||
|
|
||||||
profile =
|
postgres do
|
||||||
Profile
|
table("profile")
|
||||||
|> Ash.Changeset.for_create(:create)
|
repo(AshPostgres.TestRepo)
|
||||||
|> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove)
|
end
|
||||||
|> Api.create!()
|
|
||||||
|
|
||||||
assert %{author_badges: [:author_of_the_year]} =
|
attributes do
|
||||||
Profile
|
uuid_primary_key(:id, writable?: true)
|
||||||
|> Ash.Query.filter(id == ^profile.id)
|
end
|
||||||
|> Ash.Query.load([:author_badges])
|
|
||||||
|> Api.read_one!()
|
|
||||||
end
|
|
||||||
|
|
||||||
test "on an empty array composite type" do
|
actions do
|
||||||
author =
|
defaults([:create, :read, :update, :destroy])
|
||||||
Author
|
end
|
||||||
|> Ash.Changeset.for_create(:create, %{badges: []})
|
|
||||||
|> Api.create!()
|
|
||||||
|
|
||||||
profile =
|
relationships do
|
||||||
Profile
|
belongs_to(:author, AshPostgres.Test.Author)
|
||||||
|> Ash.Changeset.for_create(:create)
|
end
|
||||||
|> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove)
|
|
||||||
|> Api.create!()
|
|
||||||
|
|
||||||
assert %{author_badges: []} =
|
aggregates do
|
||||||
Profile
|
first(:author_badges, :author, :badges)
|
||||||
|> Ash.Query.filter(id == ^profile.id)
|
end
|
||||||
|> Ash.Query.load([:author_badges])
|
end
|
||||||
|> Api.read_one!()
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,4 @@ defmodule AshPostgres.Test.Profile do
|
||||||
relationships do
|
relationships do
|
||||||
belongs_to(:author, AshPostgres.Test.Author)
|
belongs_to(:author, AshPostgres.Test.Author)
|
||||||
end
|
end
|
||||||
|
|
||||||
aggregates do
|
|
||||||
first(:author_badges, :author, :badges)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue