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

@ -8,7 +8,7 @@
*/
import { Vector } from '../coreTypes.js'
import { AddParams, RelateParams, Result, Entity, FindParams, SimilarParams } from './brainy.types.js'
import { AddParams, RelateParams, Result, Entity, FindParams, SimilarParams, AggregateDefinition } from './brainy.types.js'
import { NounType, VerbType } from './graphTypes.js'
import type { MigrationPreview, MigrationResult, MigrateOptions } from '../migration/types.js'
@ -179,4 +179,18 @@ export interface BrainyInterface<T = unknown> {
* ```
*/
migrate(options?: MigrateOptions): Promise<MigrationResult | MigrationPreview>
/**
* Define a named aggregate for incremental computation
*
* @param def - Aggregate definition (name, source filter, groupBy, metrics)
*/
defineAggregate(def: AggregateDefinition): void
/**
* Remove a named aggregate and clean up its state
*
* @param name - Name of the aggregate to remove
*/
removeAggregate(name: string): void
}