fix: use a subquery if any exists aggregates are in play

improvement: update ash_sql dependencies for bug fixes
This commit is contained in:
Zach Daniel 2024-07-23 07:57:57 -04:00
parent 306dc84ac2
commit cb397e9387
3 changed files with 43 additions and 81 deletions

View file

@ -1465,9 +1465,20 @@ defmodule AshPostgres.DataLayer do
end)
end
has_exists? =
Enum.any?(atomics, fn {_key, expr} ->
Ash.Filter.find(expr, fn
%Ash.Query.Exists{} ->
true
_ ->
false
end)
end)
needs_to_join? =
requires_adding_inner_join? ||
query.limit || query.offset
query.limit || query.offset || has_exists?
query =
if needs_to_join? do
@ -1481,7 +1492,7 @@ defmodule AshPostgres.DataLayer do
{:ok, from(row in Ecto.Query.subquery(root_query), []), atomics != []}
end
!Enum.empty?(query.joins) ->
!Enum.empty?(query.joins) || has_exists? ->
with root_query <- Ecto.Query.exclude(root_query, :order_by),
{:ok, root_query} <-
AshSql.Atomics.select_atomics(resource, root_query, atomics) do
@ -2011,7 +2022,7 @@ defmodule AshPostgres.DataLayer do
)
end
defp ecto_changeset(record, changeset, type, table_error? \\ true) do
defp ecto_changeset(record, changeset, type, table_error?) do
attributes =
changeset.resource
|> Ash.Resource.Info.attributes()
@ -2673,11 +2684,6 @@ defmodule AshPostgres.DataLayer do
@impl true
def update(resource, changeset) do
ecto_changeset =
changeset.data
|> Map.update!(:__meta__, &Map.put(&1, :source, table(resource, changeset)))
|> ecto_changeset(changeset, :update)
source = resolve_source(resource, changeset)
query =
@ -2689,78 +2695,34 @@ defmodule AshPostgres.DataLayer do
)
|> pkey_filter(changeset.data)
case bulk_updatable_query(query, resource, changeset.atomics, [], changeset.context) do
changeset =
Ash.Changeset.set_context(changeset, %{
data_layer: %{
use_atomic_update_data?: true
}
})
case update_query(query, changeset, resource, %{
return_records?: true,
calculations: []
}) do
{:ok, []} ->
{:error,
Ash.Error.Changes.StaleRecord.exception(
resource: resource,
filter: changeset.filter
)}
{:ok, [record]} ->
maybe_update_tenant(resource, changeset, record)
{:ok, record}
{:error, error} ->
{:error, error}
{:ok, query} ->
modifying =
Map.keys(changeset.attributes) ++
Keyword.keys(changeset.atomics) ++ Ash.Resource.Info.primary_key(resource)
query = Ecto.Query.select(query, ^modifying)
try do
case AshSql.Atomics.query_with_atomics(
resource,
query,
changeset.filter,
changeset.atomics,
ecto_changeset.changes,
[]
) do
:empty ->
{:ok, changeset.data}
{:ok, query} ->
repo = AshSql.dynamic_repo(resource, AshPostgres.SqlImplementation, changeset)
repo_opts =
AshSql.repo_opts(
repo,
AshPostgres.SqlImplementation,
changeset.timeout,
changeset.tenant,
changeset.resource
)
repo_opts =
Keyword.put(repo_opts, :returning, Keyword.keys(changeset.atomics))
result =
with_savepoint(repo, query, fn ->
repo.update_all(
query,
[],
repo_opts
)
end)
case result do
{0, []} ->
{:error,
Ash.Error.Changes.StaleRecord.exception(
resource: resource,
filter: changeset.filter
)}
{1, [result]} ->
record =
changeset.data
|> Map.merge(Map.take(result, modifying))
maybe_update_tenant(resource, changeset, record)
{:ok, record}
end
{:error, error} ->
{:error, error}
end
rescue
e ->
handle_raised_error(e, __STACKTRACE__, ecto_changeset, resource)
end
{:error, :no_rollback, error} ->
{:error, :no_rollback, error}
end
end

View file

@ -163,7 +163,7 @@ defmodule AshPostgres.MixProject do
defp deps do
[
{:ash, ash_version("~> 3.1 and >= 3.2.5")},
{:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.25")},
{:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.26")},
{:igniter, "~> 0.3 and >= 0.3.6"},
{:ecto_sql, "~> 3.11 and >= 3.11.3"},
{:ecto, "~> 3.11 and >= 3.11.2"},

View file

@ -1,6 +1,6 @@
%{
"ash": {:hex, :ash, "3.2.5", "15702f44075cd34e0bd2756d1e286298c2c6b7b30990794940199885f43d8a44", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:ets, "~> 0.8", [hex: :ets, repo: "hexpm", optional: false]}, {:igniter, ">= 0.2.12 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: true]}, {:plug, ">= 0.0.0", [hex: :plug, repo: "hexpm", optional: true]}, {:reactor, "~> 0.9", [hex: :reactor, repo: "hexpm", optional: false]}, {:simple_sat, ">= 0.1.1 and < 1.0.0-0", [hex: :simple_sat, repo: "hexpm", optional: true]}, {:spark, ">= 2.2.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:stream_data, "~> 1.0", [hex: :stream_data, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.1", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f7790ca7a77ec53d06f9b25820c5219e8ea0e7d05e3c477d783cf9d11428dc9a"},
"ash_sql": {:hex, :ash_sql, "0.2.25", "a9489f5bd54a3a91e161f59b0c95385d62ca239fad6d4851011f532832f0f5ca", [:mix], [{:ash, ">= 3.1.7 and < 4.0.0-0", [hex: :ash, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.9", [hex: :ecto_sql, repo: "hexpm", optional: false]}], "hexpm", "caeb8c5ea277aca8e9add5583bf9603bf7517c896a6e9d5eb4327a51f1209051"},
"ash": {:hex, :ash, "3.2.6", "a09042b76c5b573831fcdf004d1109592f9b63fdebc5b464a750289cfaecad83", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:ets, "~> 0.8", [hex: :ets, repo: "hexpm", optional: false]}, {:igniter, ">= 0.2.12 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: true]}, {:plug, ">= 0.0.0", [hex: :plug, repo: "hexpm", optional: true]}, {:reactor, "~> 0.9", [hex: :reactor, repo: "hexpm", optional: false]}, {:simple_sat, ">= 0.1.1 and < 1.0.0-0", [hex: :simple_sat, repo: "hexpm", optional: true]}, {:spark, ">= 2.2.8 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:stream_data, "~> 1.0", [hex: :stream_data, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.1", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ee850c1e77f987ac094199175610e86558087469a930762e3cd8f6d91ef9da8d"},
"ash_sql": {:hex, :ash_sql, "0.2.26", "79158f0ec945c83a4403eaa75f7349dde573c4115ef477f57c22624f27607f21", [:mix], [{:ash, ">= 3.1.7 and < 4.0.0-0", [hex: :ash, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.9", [hex: :ecto_sql, repo: "hexpm", optional: false]}], "hexpm", "a19b591df382cbc30131e5724514b3737c10a2ab7baf497f5229d1b3557d1244"},
"benchee": {:hex, :benchee, "1.3.1", "c786e6a76321121a44229dde3988fc772bca73ea75170a73fd5f4ddf1af95ccf", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "76224c58ea1d0391c8309a8ecbfe27d71062878f59bd41a390266bf4ac1cc56d"},
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
"comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"},
@ -21,7 +21,7 @@
"git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"},
"git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"},
"glob_ex": {:hex, :glob_ex, "0.1.7", "eae6b6377147fb712ac45b360e6dbba00346689a87f996672fe07e97d70597b1", [:mix], [], "hexpm", "decc1c21c0c73df3c9c994412716345c1692477b9470e337f628a7e08da0da6a"},
"igniter": {:hex, :igniter, "0.3.8", "e6f423170e90a4547f3aca6b4e1879d742787bf7a577db9beee835c6b3890cc2", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:inflex, "~> 2.0", [hex: :inflex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "0850066244fead51ac7f749482889878db550c23c3c8addaf5b0d87956a44c91"},
"igniter": {:hex, :igniter, "0.3.9", "2a3c80e3d5a0f3758670eaa7658fe6334633dab3fd9bca9aae69802f8282a0b3", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:inflex, "~> 2.0", [hex: :inflex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "2a5b8618a0aef8e5a545d05d389ba20fc5b0b4b8a6c45cf4f900890c263c7fdc"},
"inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"},
"iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"},
"jason": {:hex, :jason, "1.4.3", "d3f984eeb96fe53b85d20e0b049f03e57d075b5acda3ac8d465c969a2536c17b", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "9a90e868927f7c777689baa16d86f4d0e086d968db5c05d917ccff6d443e58a3"},