/** * AggregationService - Server-side count and group_by aggregation for elements * * Provides lightweight aggregation queries that return counts and groupings * without fetching full paginated item lists. This saves ~98% of tokens * compared to listing all items when only counts are needed. * * Issue #309: Token-efficient aggregation * * DESIGN: * - Uses FilterService.filter() directly (not full query pipeline) for efficiency * - Deduplicates array values in group_by to prevent double-counting * - Validates group_by fields against a whitelist to prevent internal field exposure * - Stateless and safe for concurrent use * * @module services/query/AggregationService */ import { IElement } from '../../types/elements/IElement.js'; import { FilterCriteria, AggregationOptions } from './types.js'; /** * Result of an aggregation query. * * @example * ```typescript * // Count only: * { count: 42, element_type: 'persona' } * * // Count with group_by: * { count: 42, element_type: 'persona', groups: { 'assistant': 15, 'creative': 12, 'technical': 15 } } * ``` */ export interface AggregationResult { /** Total number of elements matching filters (or all elements if no filters) */ count: number; /** Element type that was aggregated */ element_type: string; /** Group counts when group_by is specified. Maps field values to occurrence counts. */ groups?: Record; } /** * Aggregate elements with optional filtering and grouping. * * Uses FilterService.filter() directly for efficiency — skips the sort and * paginate steps that the full query pipeline would apply, since aggregation * only needs to count elements, not order or slice them. * * @param elements - Full element array to aggregate over * @param elementType - Element type string for the result * @param options - Aggregation options (count, group_by) * @param filters - Optional filter criteria to apply before aggregating * @returns Aggregation result with count and optional groups * * @example * ```typescript * // Count all personas * const result = aggregateElements(personas, 'persona', { count: true }); * // → { count: 42, element_type: 'persona' } * * // Count personas grouped by category * const grouped = aggregateElements(personas, 'persona', * { count: true, group_by: 'category' }); * // → { count: 42, element_type: 'persona', groups: { assistant: 15, creative: 27 } } * * // Count with filters * const filtered = aggregateElements(personas, 'persona', * { count: true, group_by: 'tags' }, * { status: 'active' }); * // → { count: 10, element_type: 'persona', groups: { typescript: 5, python: 3, rust: 2 } } * ``` */ export declare function aggregateElements(elements: IElement[], elementType: string, options: AggregationOptions, filters?: FilterCriteria): AggregationResult; /** * Validate aggregation options before execution. * * @param options - Aggregation options to validate * @returns null if valid, error message string if invalid */ export declare function validateAggregationOptions(options: AggregationOptions): string | null; /** * Get the set of allowed group_by fields (for introspection/documentation). */ export declare function getAllowedGroupByFields(): string[]; //# sourceMappingURL=AggregationService.d.ts.map