Skip to content

Support multiple filters in aggregations#2568

Open
TravelCurry02 wants to merge 6 commits into
ash-project:mainfrom
TravelCurry02:support-multiple-filters-in-aggregations
Open

Support multiple filters in aggregations#2568
TravelCurry02 wants to merge 6 commits into
ash-project:mainfrom
TravelCurry02:support-multiple-filters-in-aggregations

Conversation

@TravelCurry02
Copy link
Copy Markdown
Contributor

@TravelCurry02 TravelCurry02 commented Feb 17, 2026

Contributor checklist

Leave anything that you believe does not apply unchecked.

  • I accept the AI Policy, or AI was not used in the creation of this PR.
  • Bug fixes include regression tests
  • Chores
  • Documentation changes
  • Features include unit/acceptance tests
  • Refactoring
  • Update dependencies

Overview

This PR implements support for multiple filter lines in aggregate definitions, matching the behavior of read actions. Previously, attempting to use multiple filters in an aggregate would result in the error: "Multiple values for key :filter".

Issue: #1265

What Changed

Before

aggregates do
  count :total_students_this_month, :students do
    filter expr(inserted_at >= fragment("date_trunc('month', now())"))
    filter expr(inserted_at < fragment("date_trunc('month', now()) + interval '1 month'"))
    # Error: Multiple values for key `:filter`
  end
end

After

aggregates do
  count :total_students_this_month, :students do
    filter expr(inserted_at >= fragment("date_trunc('month', now())"))
    filter expr(inserted_at < fragment("date_trunc('month', now()) + interval '1 month'"))
    # Works! Both filters are combined with AND
  end
end

Implementation Details

Files Modified

  1. lib/ash/resource/aggregate/aggregate.ex

    • Added filters: [] field to struct to store multiple filter entities
    • Added concat_filters/1 to combine multiple filters with AND (single code path for one or many)
    • Added combine_filter/2 helper to merge with existing filter when present (backward compatibility)
    • Updated transform/1 to call concat_filters after relationship path normalization
    • Updated type spec to include filters: [any]
  2. lib/ash/resource/dsl.ex

    • Added filters: [@filter] entity to all 9 aggregate types (count, first, max, min, sum, avg, exists, custom, list)
    • Removed filter from schema in aggregate entities to avoid DSL ambiguity
  3. test/resource/aggregates_test.exs

    • Added 6 test cases in describe "multiple filters" block:
      • Basic multiple filter support
      • Filter combination verification
      • Backward compatibility (single filter)
      • All aggregate types support
      • Runtime execution test with real data
      • Edge case (empty filters)

How It Works

  1. DSL level: Aggregate blocks accept multiple filter expr(...) lines as repeatable entities (same pattern as read actions).
  2. Storage: Each filter line is stored in the filters: [] list on the aggregate struct.
  3. Combination: concat_filters/1 combines all filters using Ash.Query.BooleanExpression.new(:and, ...).
  4. Result: The combined filter is stored in aggregate.filter, which existing code continues to use.

Backward Compatibility

  • Single filter expr(...) still works (same code path; when rest is empty, reduce returns the single filter).
  • Existing aggregates with one filter are unchanged.
  • The filter field on the struct remains; downstream code is unchanged.

Testing

All tests pass, including:

  • Compilation and structure tests
  • Runtime execution tests with real data
  • Backward compatibility tests
  • Edge case tests (empty filters)

Related Patterns

This implementation mirrors existing patterns:

  • Read actions: filters: [@filter] entity → concat_filters → combined filter
  • Join filters: Aggregate already had join_filters: []; this adds the same list pattern for main filters

@TravelCurry02 TravelCurry02 marked this pull request as draft February 18, 2026 20:02
@TravelCurry02 TravelCurry02 marked this pull request as ready for review February 18, 2026 20:02
@TravelCurry02 TravelCurry02 marked this pull request as draft February 18, 2026 20:03
@TravelCurry02 TravelCurry02 marked this pull request as ready for review February 18, 2026 20:09
@TravelCurry02 TravelCurry02 marked this pull request as draft February 18, 2026 20:53
@TravelCurry02 TravelCurry02 marked this pull request as ready for review February 18, 2026 20:56
@TravelCurry02 TravelCurry02 marked this pull request as draft February 18, 2026 21:05
@TravelCurry02 TravelCurry02 marked this pull request as ready for review February 18, 2026 21:09
@TravelCurry02
Copy link
Copy Markdown
Contributor Author

Is there anything else that I need to implement for this PR?

@joshprice joshprice requested a review from zachdaniel April 14, 2026 20:36
Comment thread lib/ash/domain/domain.ex
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did we move this?

Copy link
Copy Markdown
Contributor

@zachdaniel zachdaniel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good, but not sure why the domain code moved.

@TravelCurry02
Copy link
Copy Markdown
Contributor Author

I am not sure why the domain code moved let me look into that.

@TravelCurry02 TravelCurry02 force-pushed the support-multiple-filters-in-aggregations branch from d9e89c2 to c39b6d5 Compare April 27, 2026 20:42
@TravelCurry02
Copy link
Copy Markdown
Contributor Author

I think I fixed it, but there are issues with the checks not passing. I will continue working on this so that the checks will pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants