ash_postgres/test/aggregate_test.exs
Alan Heywood 09092cc051 test: demonstrate issue loading aggregate
Calling Api.load! to load an aggregate on an existing record, where
the aggregated record has a relates_to_actor_via policy on it causes
the following error. Note that this error was recently fixed when
loading the aggregate as part of the query.

1) test relates to actor via has_many and with an aggregate (AshPostgres.AggregateTest)
     test/aggregate_test.exs:8
     ** (RuntimeError) Could not determined related for `exists/2` expression.

     Context Resource: %{aggregates: %{}, calculations: %{}, data_layer: AshPostgres.DataLayer, public?: false, relationship_path: [], resource: AshPostgres.Test.Comment, root_resource: AshPostgres.Test.Comment}
     Context Relationship Path: []
     At Path: []
     Path: [:organization, :users]
     Related: nil
     Expression: exists(organization.users, [id: "df84db36-b8de-485b-8e47-a86307588f79"])

     code: |> Api.load!(:count_of_comments, actor: user)
     stacktrace:
       (ash 2.5.13) lib/ash/filter/filter.ex:2121: Ash.Filter.add_expression_part/3
       (ash 2.5.13) lib/ash/filter/filter.ex:2037: anonymous fn/3 in Ash.Filter.parse_expression/2
       (elixir 1.14.2) lib/enum.ex:4751: Enumerable.List.reduce/3
       (elixir 1.14.2) lib/enum.ex:2514: Enum.reduce_while/3
       (ash 2.5.13) lib/ash/filter/filter.ex:295: Ash.Filter.parse/5
       (ash 2.5.13) lib/ash/query/query.ex:1803: Ash.Query.do_filter/2
       (elixir 1.14.2) lib/map.ex:883: Map.update!/3
       (ash 2.5.13) lib/ash/engine/request.ex:654: Ash.Engine.Request.apply_filter/4
       (ash 2.5.13) lib/ash/engine/request.ex:561: Ash.Engine.Request.do_strict_check/3
       (ash 2.5.13) lib/ash/engine/request.ex:522: anonymous fn/2 in Ash.Engine.Request.strict_check/2
       (elixir 1.14.2) lib/enum.ex:4751: Enumerable.List.reduce/3
       (elixir 1.14.2) lib/enum.ex:2514: Enum.reduce_while/3
       (ash 2.5.13) lib/ash/engine/request.ex:255: Ash.Engine.Request.do_next/1
       (ash 2.5.13) lib/ash/engine/request.ex:211: Ash.Engine.Request.next/1
       (ash 2.5.13) lib/ash/engine/engine.ex:650: Ash.Engine.advance_request/2
       (ash 2.5.13) lib/ash/engine/engine.ex:556: Ash.Engine.fully_advance_request/2
       (ash 2.5.13) lib/ash/engine/engine.ex:497: Ash.Engine.do_run_iteration/2
       (elixir 1.14.2) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
       (ash 2.5.13) lib/ash/engine/engine.ex:440: Ash.Engine.run_iteration/1
       (ash 2.5.13) lib/ash/engine/engine.ex:257: Ash.Engine.run_to_completion/1
       (ash 2.5.13) lib/ash/engine/engine.ex:202: Ash.Engine.do_run/2
       (ash 2.5.13) lib/ash/engine/engine.ex:141: Ash.Engine.run/2
       (ash 2.5.13) lib/ash/actions/read.ex:170: Ash.Actions.Read.do_run/3
       (ash 2.5.13) lib/ash/actions/read.ex:90: Ash.Actions.Read.run/3
       (ash 2.5.13) lib/ash/api/api.ex:928: Ash.Api.load/4
       (ash 2.5.13) lib/ash/api/api.ex:902: Ash.Api.load!/4
       test/aggregate_test.exs:48: (test)
2023-01-31 10:35:33 +10:00

878 lines
27 KiB
Elixir

defmodule AshPostgres.AggregateTest do
use AshPostgres.RepoCase, async: false
alias AshPostgres.Test.{Api, Comment, Organization, Post, Rating, User}
require Ash.Query
test "relates to actor via has_many and with an aggregate" do
org =
Organization
|> Ash.Changeset.new(%{name: "The Org"})
|> Api.create!()
post =
Post
|> Ash.Changeset.for_create(:create, %{title: "title"})
|> Ash.Changeset.manage_relationship(:organization, org, type: :append_and_remove)
|> Api.create!()
user =
User
|> Ash.Changeset.for_create(:create, %{})
|> Ash.Changeset.manage_relationship(:organization, org, type: :append_and_remove)
|> Api.create!()
Comment
|> Ash.Changeset.new(%{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
read_post =
Post
|> Ash.Query.filter(id == ^post.id)
|> Api.read_one!(actor: user)
assert read_post.id == post.id
read_post =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:count_of_comments)
|> Api.read_one!(actor: user)
assert read_post.count_of_comments == 1
read_post =
post
|> Api.load!(:count_of_comments, actor: user)
assert read_post.count_of_comments == 1
end
describe "count" do
test "with no related data it returns 0" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
assert %{count_of_comments: 0} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:count_of_comments)
|> Api.read_one!()
end
test "with data and a custom aggregate, it returns the count" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
Comment
|> Ash.Changeset.new(%{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
import Ash.Query
assert %{aggregates: %{custom_count_of_comments: 1}} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.aggregate(
:custom_count_of_comments,
:count,
:comments,
filter: expr(not is_nil(title))
)
|> Api.read_one!()
Comment
|> Ash.Changeset.new(%{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %{aggregates: %{custom_count_of_comments: 2}} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.aggregate(
:custom_count_of_comments,
:count,
:comments,
filter: expr(not is_nil(title))
)
|> Api.read_one!()
end
test "with data for a many_to_many, it returns the count" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
post2 =
Post
|> Ash.Changeset.new(%{title: "title2"})
|> Api.create!()
post3 =
Post
|> Ash.Changeset.new(%{title: "title3"})
|> Api.create!()
post
|> Ash.Changeset.new()
|> Ash.Changeset.manage_relationship(:linked_posts, [post2, post3], type: :append_and_remove)
|> Api.update!()
post2
|> Ash.Changeset.new()
|> Ash.Changeset.manage_relationship(:linked_posts, [post3], type: :append_and_remove)
|> Api.update!()
assert [
%{count_of_linked_posts: 2, title: "title"},
%{count_of_linked_posts: 1, title: "title2"}
] =
Post
|> Ash.Query.load(:count_of_linked_posts)
|> Ash.Query.filter(count_of_linked_posts >= 1)
|> Ash.Query.sort(count_of_linked_posts: :desc)
|> Api.read!()
end
test "with data and a filter, it returns the count" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
Comment
|> Ash.Changeset.new(%{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %{count_of_comments_called_match: 1} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:count_of_comments_called_match)
|> Api.read_one!()
Comment
|> Ash.Changeset.new(%{title: "not_match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %{count_of_comments_called_match: 1} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:count_of_comments_called_match)
|> Api.read_one!()
end
end
describe "list" do
test "with no related data it returns an empty list" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
assert %{comment_titles: []} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:comment_titles)
|> Api.read_one!()
end
test "with related data, it returns the value" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
Comment
|> Ash.Changeset.new(%{title: "bbb"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
Comment
|> Ash.Changeset.new(%{title: "ccc"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %{comment_titles: ["bbb", "ccc"]} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:comment_titles)
|> Api.read_one!()
Comment
|> Ash.Changeset.new(%{title: "aaa"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %{comment_titles: ["aaa", "bbb", "ccc"]} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:comment_titles)
|> Api.read_one!()
end
end
describe "first" do
test "with no related data it returns nil" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
assert %{first_comment: nil} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:first_comment)
|> Api.read_one!()
end
test "with related data, it returns the value" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
Comment
|> Ash.Changeset.new(%{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %{first_comment: "match"} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:first_comment)
|> Api.read_one!()
Comment
|> Ash.Changeset.new(%{title: "early match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %{first_comment: "early match"} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:first_comment)
|> Api.read_one!()
end
test "it can be sorted on" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
Comment
|> Ash.Changeset.new(%{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %{first_comment: "match"} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:first_comment)
|> Ash.Query.sort(:first_comment)
|> Api.read_one!()
end
end
test "sum aggregates show the same value with filters on the sum vs filters on relationships" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
for i <- 1..5 do
ratings =
for i <- [3, 5, 7, 9] do
%{score: i}
end
Comment
|> Ash.Changeset.new(%{title: "title#{i}"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Ash.Changeset.manage_relationship(:ratings, ratings, type: :create)
|> Api.create!()
end
values =
post
|> Api.load!([
:sum_of_popular_comment_rating_scores,
:sum_of_popular_comment_rating_scores_2
])
|> Map.take([:sum_of_popular_comment_rating_scores, :sum_of_popular_comment_rating_scores_2])
|> Map.values()
assert [80, 80] = values
end
test "can't define multidimensional array aggregate types" do
assert_raise Spark.Error.DslError, ~r/Aggregate not supported/, fn ->
defmodule Foo do
@moduledoc false
use Ash.Resource,
data_layer: AshPostgres.DataLayer
postgres do
table("profile")
repo(AshPostgres.TestRepo)
end
attributes do
uuid_primary_key(:id, writable?: true)
end
actions do
defaults([:create, :read, :update, :destroy])
end
relationships do
belongs_to(:author, AshPostgres.Test.Author)
end
aggregates do
first(:author_badges, :author, :badges)
end
end
end
end
test "related aggregates can be filtered on" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
post2 =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
Comment
|> Ash.Changeset.new(%{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
Comment
|> Ash.Changeset.new(%{title: "non_match"})
|> Ash.Changeset.manage_relationship(:post, post2, type: :append_and_remove)
|> Api.create!()
Comment
|> Ash.Changeset.new(%{title: "non_match2"})
|> Ash.Changeset.manage_relationship(:post, post2, type: :append_and_remove)
|> Api.create!()
assert %{title: "match"} =
Comment
|> Ash.Query.filter(post.count_of_comments == 1)
|> Api.read_one!()
end
describe "sum" do
test "with no related data it returns nil" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
assert %{sum_of_comment_likes: nil} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:sum_of_comment_likes)
|> Api.read_one!()
end
test "with no related data and a default it returns the default" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
assert %{sum_of_comment_likes_with_default: 0} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:sum_of_comment_likes_with_default)
|> Api.read_one!()
end
test "with data, it returns the sum" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
Comment
|> Ash.Changeset.new(%{title: "match", likes: 2})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %{sum_of_comment_likes: 2} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:sum_of_comment_likes)
|> Api.read_one!()
Comment
|> Ash.Changeset.new(%{title: "match", likes: 3})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %{sum_of_comment_likes: 5} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:sum_of_comment_likes)
|> Api.read_one!()
end
test "with data and a filter, it returns the sum" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
Comment
|> Ash.Changeset.new(%{title: "match", likes: 2})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %{sum_of_comment_likes_called_match: 2} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:sum_of_comment_likes_called_match)
|> Api.read_one!()
Comment
|> Ash.Changeset.new(%{title: "not_match", likes: 3})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %{sum_of_comment_likes_called_match: 2} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:sum_of_comment_likes_called_match)
|> Api.read_one!()
end
test "filtering on a nested aggregate works" do
Post
|> Ash.Query.filter(count_of_comment_ratings == 0)
|> Api.read!()
end
test "nested aggregates show the proper values" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
author =
AshPostgres.Test.Author
|> Ash.Changeset.new(%{"first_name" => "ted"})
|> Api.create!()
comment1 =
Comment
|> Ash.Changeset.new(%{title: "match", likes: 2})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove)
|> Api.create!()
comment2 =
Comment
|> Ash.Changeset.new(%{title: "match", likes: 2})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Ash.Changeset.manage_relationship(:author, author, type: :append_and_remove)
|> Api.create!()
Rating
|> Ash.Changeset.new(%{score: 5, resource_id: comment1.id})
|> Ash.Changeset.set_context(%{data_layer: %{table: "comment_ratings"}})
|> Api.create!()
Rating
|> Ash.Changeset.new(%{score: 10, resource_id: comment2.id})
|> Ash.Changeset.set_context(%{data_layer: %{table: "comment_ratings"}})
|> Api.create!()
assert [%{count_of_comment_ratings: 2}] =
Post |> Ash.Query.load(:count_of_comment_ratings) |> Api.read!()
assert [%{highest_comment_rating: 10}] =
Post |> Ash.Query.load(:highest_comment_rating) |> Api.read!()
assert [%{lowest_comment_rating: 5}] =
Post |> Ash.Query.load(:lowest_comment_rating) |> Api.read!()
assert [%{avg_comment_rating: 7.5}] =
Post |> Ash.Query.load(:avg_comment_rating) |> Api.read!()
# TODO: want to add an option for `unique` here at some point
assert [%{comment_authors: "ted,ted"}] =
Post |> Ash.Query.load(:comment_authors) |> Api.read!()
end
test "nested filtered aggregates show the proper values" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
comment1 =
Comment
|> Ash.Changeset.new(%{title: "match", likes: 2})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
comment2 =
Comment
|> Ash.Changeset.new(%{title: "match", likes: 2})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
Rating
|> Ash.Changeset.new(%{score: 20, resource_id: comment1.id})
|> Ash.Changeset.set_context(%{data_layer: %{table: "comment_ratings"}})
|> Api.create!()
Rating
|> Ash.Changeset.new(%{score: 1, resource_id: comment2.id})
|> Ash.Changeset.set_context(%{data_layer: %{table: "comment_ratings"}})
|> Api.create!()
assert [%{count_of_comment_ratings: 2, count_of_popular_comment_ratings: 1}] =
Post
|> Ash.Query.load([:count_of_comment_ratings, :count_of_popular_comment_ratings])
|> Api.read!()
assert [%{count_of_comment_ratings: 2}] =
Post
|> Ash.Query.load([:count_of_comment_ratings])
|> Api.read!()
assert [%{count_of_popular_comment_ratings: 1}] =
Post
|> Ash.Query.load([:count_of_popular_comment_ratings])
|> Api.read!()
end
test "nested filtered and sorted aggregates show the proper values" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
comment1 =
Comment
|> Ash.Changeset.new(%{title: "match", likes: 2})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
comment2 =
Comment
|> Ash.Changeset.new(%{title: "match", likes: 2})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
Rating
|> Ash.Changeset.new(%{score: 20, resource_id: comment1.id})
|> Ash.Changeset.set_context(%{data_layer: %{table: "comment_ratings"}})
|> Api.create!()
Rating
|> Ash.Changeset.new(%{score: 1, resource_id: comment2.id})
|> Ash.Changeset.set_context(%{data_layer: %{table: "comment_ratings"}})
|> Api.create!()
assert [%{count_of_comment_ratings: 2, count_of_popular_comment_ratings: 1}] =
Post
|> Ash.Query.load([:count_of_comment_ratings, :count_of_popular_comment_ratings])
|> Api.read!()
end
test "nested first aggregate works" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
comment =
Comment
|> Ash.Changeset.new(%{title: "title", likes: 2})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
Rating
|> Ash.Changeset.new(%{score: 10, resource_id: comment.id})
|> Ash.Changeset.set_context(%{data_layer: %{table: "comment_ratings"}})
|> Api.create!()
post =
Post
|> Ash.Query.load(:highest_rating)
|> Api.read!()
|> Enum.at(0)
assert post.highest_rating == 10
end
test "loading a nested aggregate works" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
Comment
|> Ash.Changeset.new(%{title: "title", likes: 2})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
Post
|> Ash.Query.load(:count_of_comment_ratings)
|> Api.read!()
|> Enum.map(fn post ->
assert post.count_of_comment_ratings == 0
end)
end
test "the sum can be filtered on when paginating" do
post =
Post
|> Ash.Changeset.new(%{title: "title"})
|> Api.create!()
Comment
|> Ash.Changeset.new(%{title: "match", likes: 2})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %{sum_of_comment_likes_called_match: 2} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:sum_of_comment_likes_called_match)
|> Api.read_one!()
Comment
|> Ash.Changeset.new(%{title: "not_match", likes: 3})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %Ash.Page.Offset{results: [%{sum_of_comment_likes_called_match: 2}]} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:sum_of_comment_likes_called_match)
|> Ash.Query.filter(sum_of_comment_likes_called_match == 2)
|> Api.read!(action: :paginated, page: [limit: 1, count: true])
assert %Ash.Page.Offset{results: []} =
Post
|> Ash.Query.filter(id == ^post.id)
|> Ash.Query.load(:sum_of_comment_likes_called_match)
|> Ash.Query.filter(sum_of_comment_likes_called_match == 3)
|> Api.read!(action: :paginated, page: [limit: 1, count: true])
end
test "an aggregate on relationships with a filter returns the proper value" do
post =
Post
|> Ash.Changeset.new(%{title: "title", category: "foo"})
|> Api.create!()
Comment
|> Ash.Changeset.for_create(:create, %{title: "match", likes: 20})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
Comment
|> Ash.Changeset.for_create(:create, %{title: "match", likes: 17})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
Comment
|> Ash.Changeset.for_create(:create, %{title: "match", likes: 50})
|> Ash.Changeset.force_change_attribute(
:created_at,
DateTime.add(DateTime.utc_now(), :timer.hours(24) * -20, :second)
)
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %Post{sum_of_recent_popular_comment_likes: 37} =
Post
|> Ash.Query.load(:sum_of_recent_popular_comment_likes)
|> Api.read_one!()
end
test "a count aggregate on relationships with a filter returns the proper value" do
post =
Post
|> Ash.Changeset.new(%{title: "title", category: "foo"})
|> Api.create!()
Comment
|> Ash.Changeset.for_create(:create, %{title: "match", likes: 20})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
Comment
|> Ash.Changeset.for_create(:create, %{title: "match", likes: 17})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
Comment
|> Ash.Changeset.for_create(:create, %{title: "match", likes: 50})
|> Ash.Changeset.force_change_attribute(
:created_at,
DateTime.add(DateTime.utc_now(), :timer.hours(24) * -20, :second)
)
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %Post{count_of_recent_popular_comments: 2} =
Post
|> Ash.Query.load([
:count_of_recent_popular_comments
])
|> Api.read_one!()
end
test "a count aggregate with a related filter returns the proper value" do
post =
Post
|> Ash.Changeset.new(%{title: "title", category: "foo"})
|> Api.create!()
Comment
|> Ash.Changeset.for_create(:create, %{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
Comment
|> Ash.Changeset.for_create(:create, %{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
Comment
|> Ash.Changeset.for_create(:create, %{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %Post{count_of_comments_that_have_a_post: 3} =
Post
|> Ash.Query.load([
:count_of_comments_that_have_a_post
])
|> Api.read_one!()
end
test "a count aggregate with a related filter that uses `exists` returns the proper value" do
post =
Post
|> Ash.Changeset.new(%{title: "title", category: "foo"})
|> Api.create!()
Comment
|> Ash.Changeset.for_create(:create, %{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
Comment
|> Ash.Changeset.for_create(:create, %{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
Comment
|> Ash.Changeset.for_create(:create, %{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
assert %Post{count_of_comments_that_have_a_post_with_exists: 3} =
Post
|> Ash.Query.load([
:count_of_comments_that_have_a_post_with_exists
])
|> Api.read_one!()
end
test "a count with a filter that references a relationship that also has a filter" do
post =
Post
|> Ash.Changeset.new(%{title: "title", category: "foo"})
|> Api.create!()
comment =
Comment
|> Ash.Changeset.for_create(:create, %{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
comment2 =
Comment
|> Ash.Changeset.for_create(:create, %{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
Rating
|> Ash.Changeset.for_create(:create, %{score: 10, resource_id: comment.id})
|> Ash.Changeset.set_context(%{data_layer: %{table: "comment_ratings"}})
|> Api.create!()
Rating
|> Ash.Changeset.for_create(:create, %{score: 1, resource_id: comment2.id})
|> Ash.Changeset.set_context(%{data_layer: %{table: "comment_ratings"}})
|> Api.create!()
assert %Post{count_of_popular_comments: 1} =
Post
|> Ash.Query.load([
:count_of_popular_comments
])
|> Api.read_one!()
end
test "a count with a filter that references a relationship combined with another" do
post =
Post
|> Ash.Changeset.new(%{title: "title", category: "foo"})
|> Api.create!()
comment =
Comment
|> Ash.Changeset.for_create(:create, %{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
comment2 =
Comment
|> Ash.Changeset.for_create(:create, %{title: "match"})
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|> Api.create!()
Rating
|> Ash.Changeset.for_create(:create, %{score: 10, resource_id: comment.id})
|> Ash.Changeset.set_context(%{data_layer: %{table: "comment_ratings"}})
|> Api.create!()
Rating
|> Ash.Changeset.for_create(:create, %{score: 1, resource_id: comment2.id})
|> Ash.Changeset.set_context(%{data_layer: %{table: "comment_ratings"}})
|> Api.create!()
assert %Post{count_of_popular_comments: 1} =
Post
|> Ash.Query.load([
:count_of_comments,
:count_of_popular_comments
])
|> Api.read_one!()
end
end
end