feat: add aggregation engine with incremental SUM/COUNT/AVG/MIN/MAX, GROUP BY, and time windows

Add a write-time incremental aggregation engine that maintains running
totals on every add/update/delete for O(1) read performance. Integrates
into brain.find({ aggregate }) for a unified query API.

Core features:
- AggregationIndex with defineAggregate()/removeAggregate() API
- Five aggregation operations: SUM, COUNT, AVG, MIN, MAX
- GROUP BY with multiple dimensions including time windows
- Time window bucketing: hour, day, week, month, quarter, year, custom
- Materialization of results as NounType.Measurement entities
- Debounced persistence of definitions and state to storage
- Definition change detection via FNV-1a hashing with auto-rebuild
- Infinite loop prevention for materialized entities
- 'aggregation' plugin provider key for native acceleration
- Lazy initialization (created on first defineAggregate() call)
- 73 tests (unit + integration) covering all functionality

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
David Snelling 2026-02-16 16:57:53 -08:00
parent 089a4d4141
commit f024e56ee7
19 changed files with 2986 additions and 21 deletions

View file

@ -1339,6 +1339,42 @@ await brain.find({
- No performance penalty - same speed as any metadata filter
- Works seamlessly with vector + metadata + graph queries
## 5. Aggregate Queries
The `find()` method also supports aggregate queries via the `aggregate` parameter. When set, `find()` bypasses all vector/metadata/graph search paths and returns pre-computed aggregate results from the incremental aggregation engine.
```typescript
// Define the aggregate (once — survives restarts)
brain.defineAggregate({
name: 'monthly_spending',
source: { type: NounType.Event, where: { domain: 'financial' } },
groupBy: ['category', { field: 'date', window: 'month' }],
metrics: {
total: { op: 'sum', field: 'amount' },
count: { op: 'count' }
}
})
// Query it through find()
const results = await brain.find({
aggregate: 'monthly_spending',
where: { category: 'food' }, // Filters aggregate groups (not raw entities)
orderBy: 'total',
order: 'desc',
limit: 12
})
```
**Key characteristics:**
- **O(1) read performance** — results come from running totals, no query-time computation
- **Updated incrementally** — every `add()`, `update()`, `delete()` updates matching aggregates
- **Same Result<T>[] format** — aggregate results are returned as `NounType.Measurement` entities
- **Combinable with `where`/`orderBy`/`limit`/`offset`** — standard find() parameters apply to group filtering
See the **[API Reference → Aggregation Engine](./api/README.md#aggregation-engine)** for the full API.
---
### Migration from v4.6.x
**BREAKING CHANGE**: The `includeVFS` parameter has been removed: