Skip to content

Commit 3205706

Browse files
authored
improvement: support unions (#543)
1 parent c9269f6 commit 3205706

File tree

5 files changed

+470
-13
lines changed

5 files changed

+470
-13
lines changed

lib/data_layer.ex

+40-8
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,8 @@ defmodule AshPostgres.DataLayer do
615615

616616
@impl true
617617
def can?(_, :async_engine), do: true
618+
def can?(_, :combine), do: true
619+
def can?(_, {:combine, _}), do: true
618620
def can?(_, :bulk_create), do: true
619621

620622
def can?(_, :action_select), do: true
@@ -781,12 +783,24 @@ defmodule AshPostgres.DataLayer do
781783
repo = AshSql.dynamic_repo(resource, AshPostgres.SqlImplementation, query)
782784

783785
with_savepoint(repo, query, fn ->
784-
{:ok,
785-
repo.all(
786-
query,
787-
AshSql.repo_opts(repo, AshPostgres.SqlImplementation, nil, nil, resource)
788-
)
789-
|> AshSql.Query.remap_mapped_fields(query)}
786+
repo.all(
787+
query,
788+
AshSql.repo_opts(repo, AshPostgres.SqlImplementation, nil, nil, resource)
789+
)
790+
|> AshSql.Query.remap_mapped_fields(query)
791+
|> then(fn results ->
792+
if query.__ash_bindings__.context[:data_layer][:combination_of_queries?] do
793+
Enum.map(results, fn result ->
794+
struct(resource, result)
795+
|> Map.put(:__meta__, %Ecto.Schema.Metadata{
796+
state: :loaded
797+
})
798+
end)
799+
else
800+
results
801+
end
802+
end)
803+
|> then(&{:ok, &1})
790804
end)
791805
end
792806
rescue
@@ -1423,6 +1437,11 @@ defmodule AshPostgres.DataLayer do
14231437
AshSql.Query.resource_to_query(resource, AshPostgres.SqlImplementation, domain)
14241438
end
14251439

1440+
@impl true
1441+
def combination_of(combination_of, resource, domain) do
1442+
AshSql.Query.combination_of(combination_of, resource, domain, AshPostgres.SqlImplementation)
1443+
end
1444+
14261445
@impl true
14271446
def update_query(query, changeset, resource, options) do
14281447
repo = AshSql.dynamic_repo(resource, AshPostgres.SqlImplementation, changeset)
@@ -1627,7 +1646,7 @@ defmodule AshPostgres.DataLayer do
16271646

16281647
needs_to_join? =
16291648
requires_adding_inner_join? || query.distinct ||
1630-
query.limit || query.offset || has_exists?
1649+
query.limit || query.offset || has_exists? || query.combinations != []
16311650

16321651
query =
16331652
if needs_to_join? do
@@ -3253,7 +3272,20 @@ defmodule AshPostgres.DataLayer do
32533272

32543273
@impl true
32553274
def select(query, select, _resource) do
3256-
{:ok, from(row in query, select: struct(row, ^Enum.uniq(select)))}
3275+
if query.__ash_bindings__.context[:data_layer][:combination_query?] ||
3276+
query.__ash_bindings__.context[:data_layer][:combination_of_queries?] do
3277+
binding = query.__ash_bindings__.root_binding
3278+
3279+
query =
3280+
from(row in Ecto.Query.exclude(query, :select), select: %{})
3281+
3282+
Enum.reduce(select, query, fn field, query ->
3283+
from(row in query, select_merge: %{^field => field(as(^binding), ^field)})
3284+
end)
3285+
|> then(&{:ok, &1})
3286+
else
3287+
{:ok, from(row in query, select: struct(row, ^Enum.uniq(select)))}
3288+
end
32573289
end
32583290

32593291
@impl true

mix.exs

+4-2
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,10 @@ defmodule AshPostgres.MixProject do
166166
# Run "mix help deps" to learn about dependencies.
167167
defp deps do
168168
[
169-
{:ash, ash_version("~> 3.4 and >= 3.4.69")},
170-
{:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.72")},
169+
# {:ash, ash_version("~> 3.4 and >= 3.4.69")},
170+
# {:ash_sql, ash_sql_version("~> 0.2 and >= 0.2.72")},
171+
{:ash, ash_version(github: "ash-project/ash")},
172+
{:ash_sql, ash_sql_version(github: "ash-project/ash_sql")},
171173
{:igniter, "~> 0.5 and >= 0.5.16", optional: true},
172174
{:ecto_sql, "~> 3.12"},
173175
{:ecto, "~> 3.12 and >= 3.12.1"},

mix.lock

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
%{
2-
"ash": {:hex, :ash, "3.5.8", "8c9fbc72b9739cd4659595f87685039a3ee373d87933399a6c14596962898989", [:mix], [{: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.5.24 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, 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.11", [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.29 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, ">= 0.2.6 and < 1.0.0-0", [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", "f9a5196152b526795b1650972621b50c3ee0b45d10d6b200dd70e50e7407eb31"},
3-
"ash_sql": {:hex, :ash_sql, "0.2.74", "f1e1effeb402c2e27680b9629b7ac5f6639474b4f8c074402209bd76ff07f56e", [:mix], [{:ash, "~> 3.5", [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", "16a1e57cc0a6616229630f2dae5be1f4e54d05ef87ad29d073174f15bbcf0edf"},
2+
"ash": {:git, "https://github.com/ash-project/ash.git", "ef0a5193d142e004bb5af27c11c8a4e352cff478", []},
3+
"ash_sql": {:git, "https://github.com/ash-project/ash_sql.git", "4cc9f2af6385300d14b51a5b104cd1ec64bed6ae", []},
44
"benchee": {:hex, :benchee, "1.4.0", "9f1f96a30ac80bab94faad644b39a9031d5632e517416a8ab0a6b0ac4df124ce", [: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", "299cd10dd8ce51c9ea3ddb74bb150f93d25e968f93e4c1fa31698a8e4fa5d715"},
55
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
66
"credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"},
@@ -23,7 +23,7 @@
2323
"git_ops": {:hex, :git_ops, "2.7.2", "2d3c164a8bcaf13f129ab339e8e9f0a99c80ffa8f85dd0b344d7515275236dbc", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:igniter, ">= 0.5.27 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "1dcd68b3f5bcd0999d69274cd21e74e652a90452e683b54d490fa5b26152945f"},
2424
"glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"},
2525
"hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"},
26-
"igniter": {:hex, :igniter, "0.5.49", "625bfd1cb8886a3fb729ea67515618e06fc890ef438baca56e5f3a12449510f0", [: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]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [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]}], "hexpm", "a332d5700116d12517d4c2ddce225f0337429fd8cb2cb857dd530a720fa5df3b"},
26+
"igniter": {:hex, :igniter, "0.5.50", "2f6f3a50e02835e961b6228bfcdebe96cd6e9371042939e7f080c83049057e57", [: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]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [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]}], "hexpm", "2e992df458c044f3a18ff6347275743b21092d6677368fdb8dfded321b85cc7b"},
2727
"inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"},
2828
"iterex": {:hex, :iterex, "0.1.2", "58f9b9b9a22a55cbfc7b5234a9c9c63eaac26d276b3db80936c0e1c60355a5a6", [:mix], [], "hexpm", "2e103b8bcc81757a9af121f6dc0df312c9a17220f302b1193ef720460d03029d"},
2929
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},

0 commit comments

Comments
 (0)