[codex] Add SQLite aggregate support - #3
Draft
wtsnz wants to merge 7 commits into
Draft
Conversation
wtsnz
force-pushed
the
feat/sqlite-aggregate-support
branch
from
May 20, 2026 03:26
9593ce9 to
01b9e8a
Compare
wtsnz
force-pushed
the
feat/sqlite-aggregate-support
branch
from
June 5, 2026 19:14
a7e1639 to
28b3b48
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is my first proper dive into extending the Ash ecosystem, so I’m still getting my bearings with some of the internals and conventions.
I needed aggregates for a local app I’m building on SQLite, and spent the last couple of days exploring the existing SQL adapters and getting this branch into shape with Codex helping lots along the way. My goal was to get most of the common usage of aggregates working with sqlite so that I could continue building my app.
I took a look at what AshPostgres supports - the tests helped a lot to get an idea of what to support - and tried to get most of it working in SQLite.
Summary
This covers the aggregate kinds I most wanted to use day-to-day:
countsumavgminmaxexistsfirstlistcustomaggregatesThis also adds
AshSqlite.CustomAggregatethat follows the same general idea asAshPostgres.CustomAggregate- you've just got to make sure that you emit SQLite-compatible SQL.Approach
I originally hoped this could mostly reuse the shared
ash_sqlaggregate machinery, but the existing aggregate planner is built around SQL shapes SQLite does not support cleanly. Lateral joins and PostgreSQL-style list aggregation are the big ones. For SQLite, the safer route (according to the LLMs!) is grouped/windowed subqueries, JSON aggregation for lists, and explicit errors when a filter shape could multiply the rows being aggregated.So this different approach requires us to add our own SQLite-specific aggregate planner in
AshSqlite.Aggregate.The implementation builds aggregate queries as grouped subqueries or windowed subqueries, then joins those results back to the parent query. Scalar aggregates can often share grouped subqueries.
firstandlistneed window/query handling so ordering stays deterministic, andlistuses SQLite JSON aggregation before being decoded back into the loaded aggregate value.A lot of the work here is defensive so that AshSqlite does not generate SQL that returns subtly wrong results. Aggregate filters that join across to-many relationships can accidentally multiply rows and over-count or over-sum. For those cases, I've tried to either use a safe shape or return an explicit unsupported error. I've made sure to add enough tests to be confident in the implementation.
Future potential
This pr is intentionally SQLite-scoped rather than full AshPostgres parity, and already does pretty much everything I need for my project so far.
The main things I’ve left out are cases where SQLite would need a very different query shape, or where the generated SQL could quietly return the wrong answer. That includes things like parent-dependent aggregate filters, manual relationships, some mixed multi-hop/many-to-many paths, and fanout-prone filters over to-many relationships.
Those cases should fail with explicit unsupported errors rather than producing over-counted or over-summed results. The docs include the fuller list of current limitations.
Validation
MIX_ENV=test mix test.resetMIX_ENV=test mix testLatest local result:
187 tests, 0 failures.Contributor checklist
Leave anything that you believe does not apply unchecked.