mirror of
https://github.com/ash-project/ash.git
synced 2024-09-19 21:13:10 +12:00
improvement: add sum aggregate (#221)
This commit is contained in:
parent
7ecd72e61d
commit
6805d431ac
5 changed files with 44 additions and 7 deletions
|
@ -89,6 +89,8 @@ locals_without_parens = [
|
|||
source_field: 1,
|
||||
source_field_on_join_table: 1,
|
||||
strategy: 1,
|
||||
sum: 3,
|
||||
sum: 4,
|
||||
table: 1,
|
||||
through: 1,
|
||||
timestamps: 0,
|
||||
|
|
|
@ -13,7 +13,7 @@ defmodule Ash.Query.Aggregate do
|
|||
:load
|
||||
]
|
||||
|
||||
@kinds [:count, :first]
|
||||
@kinds [:count, :first, :sum]
|
||||
|
||||
@type t :: %__MODULE__{}
|
||||
@type kind :: unquote(Enum.reduce(@kinds, &{:|, [], [&1, &2]}))
|
||||
|
@ -90,6 +90,7 @@ defmodule Ash.Query.Aggregate do
|
|||
|
||||
defp default_value(:count), do: 0
|
||||
defp default_value(:first), do: nil
|
||||
defp default_value(:sum), do: nil
|
||||
|
||||
defp validate_query(nil), do: {:ok, nil}
|
||||
|
||||
|
@ -114,8 +115,8 @@ defmodule Ash.Query.Aggregate do
|
|||
|
||||
@doc false
|
||||
def kind_to_type(:count, _field_type), do: {:ok, Ash.Type.Integer}
|
||||
def kind_to_type(:first, nil), do: {:error, "Must provide field type for :first"}
|
||||
def kind_to_type(:first, field_type), do: {:ok, field_type}
|
||||
def kind_to_type(kind, nil), do: {:error, "Must provide field type for #{kind}"}
|
||||
def kind_to_type(kind, field_type) when kind in [:first, :sum], do: {:ok, field_type}
|
||||
def kind_to_type(kind, _field_type), do: {:error, "Invalid aggregate kind: #{kind}"}
|
||||
|
||||
def requests(initial_query, can_be_in_query?, authorizing?) do
|
||||
|
|
|
@ -14,7 +14,7 @@ defmodule Ash.Resource.Aggregate do
|
|||
required: true
|
||||
],
|
||||
kind: [
|
||||
type: {:in, [:count, :first]},
|
||||
type: {:in, [:count, :first, :sum]},
|
||||
doc: "The kind of the aggregate",
|
||||
required: true
|
||||
],
|
||||
|
@ -50,7 +50,7 @@ defmodule Ash.Resource.Aggregate do
|
|||
relationship_path: {:ok, list(atom())} | {:error, String.t()},
|
||||
filter: Keyword.t(),
|
||||
field: atom,
|
||||
kind: :count | :first,
|
||||
kind: :count | :first | :sum,
|
||||
description: String.t() | nil,
|
||||
private?: boolean
|
||||
}
|
||||
|
|
|
@ -743,6 +743,26 @@ defmodule Ash.Resource.Dsl do
|
|||
auto_set_fields: [kind: :first]
|
||||
}
|
||||
|
||||
@sum %Ash.Dsl.Entity{
|
||||
name: :sum,
|
||||
describe: """
|
||||
Declares a named `sum` aggregate on the resource
|
||||
|
||||
Supports `filter`, but not `sort` (because that wouldn't affect the count)
|
||||
""",
|
||||
examples: [
|
||||
"""
|
||||
sum :assigned_ticket_price_sum, :assigned_tickets, :price do
|
||||
filter [active: true]
|
||||
end
|
||||
"""
|
||||
],
|
||||
target: Ash.Resource.Aggregate,
|
||||
args: [:name, :relationship_path, :field],
|
||||
schema: Keyword.delete(Ash.Resource.Aggregate.schema(), :sort),
|
||||
auto_set_fields: [kind: :sum]
|
||||
}
|
||||
|
||||
@aggregates %Ash.Dsl.Section{
|
||||
name: :aggregates,
|
||||
describe: """
|
||||
|
@ -762,7 +782,8 @@ defmodule Ash.Resource.Dsl do
|
|||
],
|
||||
entities: [
|
||||
@count,
|
||||
@first
|
||||
@first,
|
||||
@sum
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ defmodule Ash.Test.Resource.AggregatesTest do
|
|||
aggregates do
|
||||
count :count_of_comments, :comments
|
||||
count :another_count_but_private, :comments, private?: true
|
||||
sum :sum_of_comment_likes, :comments, :likes
|
||||
end
|
||||
|
||||
relationships do
|
||||
|
@ -45,17 +46,29 @@ defmodule Ash.Test.Resource.AggregatesTest do
|
|||
assert [
|
||||
%Aggregate{
|
||||
name: :count_of_comments,
|
||||
kind: :count,
|
||||
relationship_path: [:comments],
|
||||
private?: false
|
||||
},
|
||||
%Aggregate{
|
||||
name: :another_count_but_private,
|
||||
kind: :count,
|
||||
relationship_path: [:comments],
|
||||
private?: true
|
||||
},
|
||||
%Ash.Resource.Aggregate{
|
||||
field: :likes,
|
||||
kind: :sum,
|
||||
name: :sum_of_comment_likes,
|
||||
private?: false,
|
||||
relationship_path: [:comments]
|
||||
}
|
||||
] = Ash.Resource.Info.aggregates(Post)
|
||||
|
||||
assert [%Aggregate{name: :count_of_comments}] = Ash.Resource.Info.public_aggregates(Post)
|
||||
assert [
|
||||
%Aggregate{name: :count_of_comments},
|
||||
%Aggregate{name: :sum_of_comment_likes}
|
||||
] = Ash.Resource.Info.public_aggregates(Post)
|
||||
|
||||
assert %Aggregate{name: :another_count_but_private} =
|
||||
Ash.Resource.Info.aggregate(Post, :another_count_but_private)
|
||||
|
|
Loading…
Reference in a new issue