setup usage_rules
This commit is contained in:
105
.claude/skills/ash-framework/references/aggregates.md
Normal file
105
.claude/skills/ash-framework/references/aggregates.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# Aggregates
|
||||
|
||||
Aggregates allow you to retrieve summary information over groups of related data, like counts, sums, or averages. Define aggregates in the `aggregates` block of a resource.
|
||||
|
||||
Aggregates can work over relationships or directly over unrelated resources:
|
||||
|
||||
```elixir
|
||||
aggregates do
|
||||
# Related aggregates - use relationship path
|
||||
count :published_post_count, :posts do
|
||||
filter expr(published == true)
|
||||
end
|
||||
|
||||
sum :total_sales, :orders, :amount
|
||||
|
||||
exists :is_admin, :roles do
|
||||
filter expr(name == "admin")
|
||||
end
|
||||
|
||||
# Unrelated aggregates - use resource module directly
|
||||
count :matching_profiles_count, Profile do
|
||||
filter expr(name == parent(name))
|
||||
end
|
||||
|
||||
sum :total_report_score, Report, :score do
|
||||
filter expr(author_name == parent(name))
|
||||
end
|
||||
|
||||
exists :has_reports, Report do
|
||||
filter expr(author_name == parent(name))
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
For unrelated aggregates, use `parent/1` to reference fields from the source resource.
|
||||
|
||||
## Aggregate Types
|
||||
|
||||
- **count**: Counts related items meeting criteria
|
||||
- **sum**: Sums a field across related items
|
||||
- **exists**: Returns boolean indicating if matching related items exist (also supports unrelated resources)
|
||||
- **first**: Gets the first related value matching criteria
|
||||
- **list**: Lists the related values for a specific field
|
||||
- **max**: Gets the maximum value of a field
|
||||
- **min**: Gets the minimum value of a field
|
||||
- **avg**: Gets the average value of a field
|
||||
|
||||
## Using Aggregates
|
||||
|
||||
```elixir
|
||||
# Using code interface options (preferred)
|
||||
users = MyDomain.list_users!(
|
||||
load: [:published_post_count, :total_sales],
|
||||
query: [
|
||||
filter: [published_post_count: [greater_than: 5]],
|
||||
sort: [published_post_count: :desc]
|
||||
]
|
||||
)
|
||||
|
||||
# Manual query building (for complex cases)
|
||||
User |> Ash.Query.filter(published_post_count > 5) |> Ash.read!()
|
||||
|
||||
# Loading on existing records
|
||||
Ash.load!(users, :published_post_count)
|
||||
```
|
||||
|
||||
### Join Filters
|
||||
|
||||
For complex aggregates involving multiple relationships, use join filters:
|
||||
|
||||
```elixir
|
||||
aggregates do
|
||||
sum :redeemed_deal_amount, [:redeems, :deal], :amount do
|
||||
# Filter on the aggregate as a whole
|
||||
filter expr(redeems.redeemed == true)
|
||||
|
||||
# Apply filters to specific relationship steps
|
||||
join_filter :redeems, expr(redeemed == true)
|
||||
join_filter [:redeems, :deal], expr(active == parent(require_active))
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## Inline Aggregates
|
||||
|
||||
Use aggregates inline within expressions:
|
||||
|
||||
```elixir
|
||||
# Related inline aggregates
|
||||
calculate :grade_percentage, :decimal, expr(
|
||||
count(answers, query: [filter: expr(correct == true)]) * 100 /
|
||||
count(answers)
|
||||
)
|
||||
|
||||
# Unrelated inline aggregates
|
||||
calculate :profile_count, :integer, expr(
|
||||
count(Profile, filter: expr(name == parent(name)))
|
||||
)
|
||||
|
||||
calculate :stats, :map, expr(%{
|
||||
profiles: count(Profile, filter: expr(active == true)),
|
||||
reports: count(Report, filter: expr(author_name == parent(name))),
|
||||
has_active_profile: exists(Profile, active == true and name == parent(name))
|
||||
})
|
||||
```
|
||||
Reference in New Issue
Block a user