diff --git a/lib/expr.ex b/lib/expr.ex index 874ecc9..de0590f 100644 --- a/lib/expr.ex +++ b/lib/expr.ex @@ -19,7 +19,9 @@ defmodule AshPostgres.Expr do Length, Now, StringJoin, + StringLength, StringSplit, + StringTrim, Today, Type } @@ -564,6 +566,52 @@ defmodule AshPostgres.Expr do ) end + defp do_dynamic_expr( + query, + %StringLength{arguments: [value], embedded?: pred_embedded?}, + bindings, + embedded?, + acc, + type + ) do + do_dynamic_expr( + query, + %Fragment{ + embedded?: pred_embedded?, + arguments: [raw: "length(", expr: value, raw: ")"] + }, + bindings, + embedded?, + acc, + type + ) + end + + defp do_dynamic_expr( + query, + %StringTrim{arguments: [value], embedded?: pred_embedded?}, + bindings, + embedded?, + acc, + type + ) do + do_dynamic_expr( + query, + %Fragment{ + embedded?: pred_embedded?, + arguments: [ + raw: "REGEXP_REPLACE(REGEXP_REPLACE(", + expr: value, + raw: ", '\s+$', ''), '^\s+', '')" + ] + }, + bindings, + embedded?, + acc, + type + ) + end + # Sorry :( # This is bad to do, but is the only reasonable way I could find. defp do_dynamic_expr( diff --git a/mix.exs b/mix.exs index d9ad9b6..10ee82a 100644 --- a/mix.exs +++ b/mix.exs @@ -204,7 +204,7 @@ defmodule AshPostgres.MixProject do {:ecto, "~> 3.9"}, {:jason, "~> 1.0"}, {:postgrex, ">= 0.0.0"}, - {:ash, ash_version("~> 2.17 and >= 2.17.13")}, + {:ash, ash_version("~> 2.17 and >= 2.17.14")}, {:benchee, "~> 1.1", only: [:dev, :test]}, {:git_ops, "~> 2.5", only: [:dev, :test]}, {:ex_doc, github: "elixir-lang/ex_doc", only: [:dev, :test], runtime: false}, diff --git a/mix.lock b/mix.lock index 9e72318..a75eec5 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "2.17.14", "ccb68a0eacd7d4f4652a01baa3ceda510d793ab769c82958d644638905f08f7d", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:ets, "~> 0.8", [hex: :ets, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: false]}, {:plug, ">= 0.0.0", [hex: :plug, repo: "hexpm", optional: true]}, {:spark, ">= 1.1.50 and < 2.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:stream_data, "~> 0.6", [hex: :stream_data, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.1", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b09a585924f222a1d353ebd13ec8691c4b9c5e37a8be271ee8960c34feb3fad0"}, + "ash": {:hex, :ash, "2.17.15", "5a71025ad4878c0522408032e5f6253b43dee19de50d0ef23ff57555f05ea646", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:ets, "~> 0.8", [hex: :ets, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: false]}, {:plug, ">= 0.0.0", [hex: :plug, repo: "hexpm", optional: true]}, {:spark, ">= 1.1.50 and < 2.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:stream_data, "~> 0.6", [hex: :stream_data, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.1", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "44082e414ee43dc2c15f31ec26121a626855587413eee2f5325e5e783a04f59b"}, "benchee": {:hex, :benchee, "1.1.0", "f3a43817209a92a1fade36ef36b86e1052627fd8934a8b937ac9ab3a76c43062", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}], "hexpm", "7da57d545003165a012b587077f6ba90b89210fd88074ce3c60ce239eb5e6d93"}, "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, diff --git a/test/calculation_test.exs b/test/calculation_test.exs index 1a5cb57..e4b5554 100644 --- a/test/calculation_test.exs +++ b/test/calculation_test.exs @@ -618,63 +618,22 @@ defmodule AshPostgres.CalculationTest do |> Enum.map(&Map.get(&1, :calc_returning_json)) end - # test "calculation passes actor to aggregate from calculation on aggregate" do - # org = - # Organization - # |> Ash.Changeset.new(%{name: "The Org"}) - # |> Api.create!() + test "string_length and string_trim work" do + Author + |> Ash.Changeset.for_create(:create, %{ + first_name: "Bill", + last_name: "Jones", + bio: %{title: "Mr.", bio: "Bones"} + }) + |> Api.create!() - # user = - # User - # |> Ash.Changeset.for_create(:create, %{is_active: true}) - # |> Ash.Changeset.manage_relationship(:organization, org, type: :append_and_remove) - # |> Api.create!() - - # profile = - # Profile - # |> Ash.Changeset.for_create(:create, %{description: "Prolific describer of worlds..."}) - # |> Api.create!() - - # author = - # Author - # |> Ash.Changeset.for_create(:create, %{ - # first_name: "Foo", - # bio: %{title: "Mr.", bio: "Bones"} - # }) - # |> Ash.Changeset.manage_relationship(:profile, profile, type: :append) - # |> Api.create!() - - # created_post = - # Post - # |> Ash.Changeset.new(%{title: "match"}) - # |> Ash.Changeset.manage_relationship(:organization, org, type: :append_and_remove) - # |> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove) - # |> Api.create!() - - # can_get_author_description_post = - # Post - # |> Ash.Query.filter(id == ^created_post.id) - # |> Ash.Query.load(author: :description) - # |> Api.read_one!(actor: user) - - # assert can_get_author_description_post.author.description == "Prolific describer of worlds..." - - # can_get_author_description_from_aggregate_post = - # Post - # |> Ash.Query.filter(id == ^created_post.id) - # |> Ash.Query.load(:author_profile_description) - # |> Api.read_one!(actor: user) - - # assert can_get_author_description_from_aggregate_post.author_profile_description == - # "Prolific describer of worlds..." - - # can_get_author_description_from_calculation_of_aggregate_post = - # Post - # |> Ash.Query.filter(id == ^created_post.id) - # |> Ash.Query.load(:author_profile_description_from_agg) - # |> Api.read_one!(actor: user) - - # assert can_get_author_description_from_calculation_of_aggregate_post.author_profile_description_from_agg == - # "Prolific describer of worlds..." - # end + assert %{calculations: %{length: 9}} = + Author + |> Ash.Query.calculate( + :length, + expr(string_length(string_trim(first_name <> last_name <> " "))), + :integer + ) + |> Api.read_one!() + end end