Skip to content

Commit

Permalink
improvement: support to-one references in calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
zachdaniel committed Oct 9, 2023
1 parent 5fdc81b commit 270d868
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 3 deletions.
10 changes: 10 additions & 0 deletions lib/calculation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ defmodule AshPostgres.Calculation do
def add_calculations(query, calculations, resource, source_binding) do
query = AshPostgres.DataLayer.default_bindings(query, resource)

{:ok, query} =
AshPostgres.Join.join_all_relationships(
query,
%Ash.Filter{
resource: resource,
expression: Enum.map(calculations, &elem(&1, 1))
},
left_only?: true
)

aggregates =
calculations
|> Enum.flat_map(fn {_calculation, expression} ->
Expand Down
8 changes: 8 additions & 0 deletions lib/expr.ex
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,14 @@ defmodule AshPostgres.Expr do
end
end)

if is_nil(binding_to_replace) do
raise """
Error building calculation reference: #{inspect(relationship_path)} is not available in bindings.
In reference: #{ref}
"""
end

temp_bindings =
bindings.bindings
|> Map.delete(0)
Expand Down
1 change: 0 additions & 1 deletion lib/join.ex
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ defmodule AshPostgres.Join do
filter
|> Ash.Filter.map(fn
%Ash.Query.Parent{} ->
# Removing any `This` from the filter
nil

other ->
Expand Down
19 changes: 19 additions & 0 deletions lib/sort.ex
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,25 @@ defmodule AshPostgres.Sort do
[]
end)

calcs =
Enum.flat_map(sort, fn
{%Ash.Query.Calculation{} = calculation, _} ->
[calculation]

_ ->
[]
end)

{:ok, query} =
AshPostgres.Join.join_all_relationships(
query,
%Ash.Filter{
resource: resource,
expression: calcs
},
left_only?: true
)

case AshPostgres.Aggregate.add_aggregates(query, used_aggregates, resource, false, 0) do
{:error, error} ->
{:error, error}
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ defmodule AshPostgres.MixProject do
{:jason, "~> 1.0"},
{:postgrex, ">= 0.0.0"},
{:spark, "~> 1.1"},
{:ash, ash_version("~> 2.14 and >= 2.14.18")},
{:ash, ash_version("~> 2.15 and >= 2.15.10")},
{:git_ops, "~> 2.5", only: [:dev, :test]},
{:ex_doc, github: "elixir-lang/ex_doc", only: [:dev, :test], runtime: false},
{:ex_check, "~> 0.14", only: [:dev, :test]},
Expand Down
3 changes: 2 additions & 1 deletion mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"db_connection": {:hex, :db_connection, "2.5.0", "bb6d4f30d35ded97b29fe80d8bd6f928a1912ca1ff110831edcd238a1973652c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c92d5ba26cd69ead1ff7582dbb860adeedfff39774105a4f1c92cbb654b55aa2"},
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
"dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"},
"earmark": {:hex, :earmark, "1.4.46", "8c7287bd3137e99d26ae4643e5b7ef2129a260e3dcf41f251750cb4563c8fb81", [:mix], [], "hexpm", "798d86db3d79964e759ddc0c077d5eb254968ed426399fbf5a62de2b5ff8910a"},
"earmark_parser": {:hex, :earmark_parser, "1.4.36", "487ea8ef9bdc659f085e6e654f3c3feea1d36ac3943edf9d2ef6c98de9174c13", [:mix], [], "hexpm", "a524e395634bdcf60a616efe77fd79561bec2e930d8b82745df06ab4e844400a"},
"ecto": {:hex, :ecto, "3.10.3", "eb2ae2eecd210b4eb8bece1217b297ad4ff824b4384c0e3fdd28aaf96edd6135", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "44bec74e2364d491d70f7e42cd0d690922659d329f6465e89feb8a34e8cd3433"},
"ecto_sql": {:hex, :ecto_sql, "3.10.2", "6b98b46534b5c2f8b8b5f03f126e75e2a73c64f3c071149d32987a5378b0fdbd", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "68c018debca57cb9235e3889affdaec7a10616a4e3a80c99fa1d01fdafaa9007"},
Expand Down Expand Up @@ -34,7 +35,7 @@
"postgrex": {:hex, :postgrex, "0.17.2", "a3ec9e3239d9b33f1e5841565c4eb200055c52cc0757a22b63ca2d529bbe764c", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "80a918a9e9531d39f7bd70621422f3ebc93c01618c645f2d91306f50041ed90c"},
"sobelow": {:hex, :sobelow, "0.11.1", "23438964486f8112b41e743bbfd402da3e5b296fdc9eacab29914b79c48916dd", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9897363a7eff96f4809304a90aad819e2ad5e5d24db547af502885146746a53c"},
"sourceror": {:hex, :sourceror, "0.14.0", "b6b8552d0240400d66b6f107c1bab7ac1726e998efc797f178b7b517e928e314", [:mix], [], "hexpm", "809c71270ad48092d40bbe251a133e49ae229433ce103f762a2373b7a10a8d8b"},
"spark": {:hex, :spark, "1.1.40", "b61438fece40eb0ffed7c4c9e5f1c2c817209902ed853b0008b7681b1994c29c", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.5 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:sourceror, "~> 0.1", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "40d0f803f1090249ef6a76cb2bf40466c57f4995326dc97996e0b8b4f365ad17"},
"spark": {:hex, :spark, "1.1.43", "5817cefa41c6f7105989fa40c044c05bf2cab7b81c8ecbd963bdbdf6eeabc85a", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.5 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:sourceror, "~> 0.1", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "29e42b900f3a7666e67fba270ff10d7b9fc693c8c2179b6bd65aa6b8426d30ca"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"stream_data": {:hex, :stream_data, "0.6.0", "e87a9a79d7ec23d10ff83eb025141ef4915eeb09d4491f79e52f2562b73e5f47", [:mix], [], "hexpm", "b92b5031b650ca480ced047578f1d57ea6dd563f5b57464ad274718c9c29501c"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
Expand Down
42 changes: 42 additions & 0 deletions test/calculation_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,48 @@ defmodule AshPostgres.CalculationTest do
|> Api.read!()
end

test "calculations can refer to to_one path attributes in filters" do
author =
Author
|> Ash.Changeset.for_create(:create, %{
first_name: "Foo",
bio: %{title: "Mr.", bio: "Bones"}
})
|> Api.create!()

Post
|> Ash.Changeset.new(%{title: "match"})
|> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove)
|> Api.create!()

assert [%{author_first_name_calc: "Foo"}] =
Post
|> Ash.Query.filter(author_first_name_calc == "Foo")
|> Ash.Query.load(:author_first_name_calc)
|> Api.read!()
end

test "calculations can refer to to_one path attributes in sorts" do
author =
Author
|> Ash.Changeset.for_create(:create, %{
first_name: "Foo",
bio: %{title: "Mr.", bio: "Bones"}
})
|> Api.create!()

Post
|> Ash.Changeset.new(%{title: "match"})
|> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove)
|> Api.create!()

assert [%{author_first_name_calc: "Foo"}] =
Post
|> Ash.Query.sort(:author_first_name_calc)
|> Ash.Query.load(:author_first_name_calc)
|> Api.read!()
end

test "calculations can refer to embedded attributes" do
author =
Author
Expand Down
2 changes: 2 additions & 0 deletions test/support/resources/post.ex
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,8 @@ defmodule AshPostgres.Test.Post do
:string,
CalculatePostPriceStringWithSymbol
)

calculate(:author_first_name_calc, :string, expr(author.first_name))
end

aggregates do
Expand Down

0 comments on commit 270d868

Please sign in to comment.