import type { GridFilterBindTarget } from '@xh/hoist/cmp/grid'; import { HoistBase, PlainObject, Some } from '@xh/hoist/core'; import { Cube, CubeField, Filter, FilterBindTarget, FilterLike, FilterValueSource, Query, QueryConfig, Store, StoreRecordId } from '@xh/hoist/data'; import { ViewRowData } from '@xh/hoist/data/cube/ViewRowData'; import { ViewDiagnostics } from './impl/ViewDiagnostics'; import { AggregationContext } from './aggregate/AggregationContext'; import { RowCache } from './impl/RowCache'; import { ExposedLeafRow } from './row/LeafRow'; import { RecordSet, RecordSetDelta } from '../impl/RecordSet'; /** * Configuration for a {@link View} - a query result from a {@link Cube} that can optionally * stay connected for live updates. Create via {@link Cube.createView}. * * See the Cube package README (`data/cube/README.md`) for query patterns. * * @see View * @see QueryConfig */ export interface ViewConfig { /** Query to be used to construct this view. */ query: Query; /** * Store(s) to be automatically (re)loaded with data from this view. * Optional - read {@link View.result} directly to use without a Store. * * Connected stores should generally set {@link StoreConfig.projectionOnly} - view rows are * already parsed and owned by this View, so adopting them directly improves performance * when no additional record parsing or local data modification is required. */ stores?: Store[] | Store; /** * True to reactively update the View's {@link View.result} and any connected store(s) when data * in the underlying Cube changes. False (default) to have this view run its query once to * capture a snapshot without further (automatic) updates. */ connect?: boolean; } export interface ViewResult { rows: ViewRowData[]; /** * Leaf-level rows, keyed by the id of their source Cube record. * * Null unless the Query sets {@link Query.includeLeaves} or {@link Query.provideLeaves} - views * that expose no leaves keep them as zero-copy references to Cube record data, which is not * safe to publish. Use {@link Cube.store} to read source records directly in that case. */ leafMap: Map; } export interface DimensionValue { /** Dimension field. */ field: CubeField; /** Unique non-null values for the dimension */ values: Set; } /** * Primary interface for consuming grouped and aggregated data from a {@link Cube}. * Created via {@link Cube.createView} with a {@link QueryConfig} and optional connected * stores. Views can be transient (run once) or connected for auto-updating results. * * Use `updateQuery()` to change dimensions, filters, or options dynamically. * * See the Cube package README (`data/cube/README.md`) for query patterns and examples * of grand totals, leaf drill-down, and store integration. * * @see ViewConfig * @see QueryConfig * @see Cube * * @mcpHint live or snapshot view of aggregated Cube data */ export declare class View extends HoistBase implements FilterBindTarget, FilterValueSource, GridFilterBindTarget { static isView(obj: unknown): obj is View; readonly isFilterValueSource = true; /** Query defining this View. Update via {@link updateQuery}. */ query: Query; /** * Results of this view, an observable object with a `rows` property containing an array of * hierarchical {@link ViewRowData} objects. */ result: ViewResult; /** Stores to which results of this view should be (re)loaded. */ stores: Store[]; /** The source {@link Cube.info} as of the last time the view was updated. */ info: PlainObject; /** The source {@link Cube.lastUpdated} as of the last time the view was updated. */ cubeUpdated: number; /** Timestamp (ms) when the view was last updated. */ lastUpdated: number; /** @internal */ readonly diagnostics: ViewDiagnostics; _created: number; private _rowDatas; private _leafMap; _records: RecordSet; private _bucketDependentFields; private _fieldsByName; private _rowDataGenerator; _rowDigest: number; _aggFieldsByDepth: CubeField[][]; _aggFieldNamesByDepth: Set[]; _canAggregateFnFieldsByDepth: CubeField[][]; _complexAggFieldsByDepth: CubeField[][]; _aggContext: AggregationContext; _rowCache: RowCache; /** @internal - applications should use {@link Cube.createView} */ constructor(config: ViewConfig); get cube(): Cube; get fields(): CubeField[]; get fieldNames(): string[]; get filter(): Filter; get isConnected(): boolean; get isFiltered(): boolean; /** Stop receiving live updates into this view when the linked Cube data changes. */ disconnect(): void; /** Connect to the associated Cube to begin receiving live updates. */ connect(): void; /** * Change the query in some way, re-computing the data in this View to reflect the new query. * * @param overrides - changes to be applied to the query. If changing the `cube` and currently * connected, then we will disconnect from the old cube and connect to the new one. */ updateQuery(overrides: Partial): void; /** Gather all unique values for each dimension field in the query. */ getDimensionValues(): DimensionValue[]; /** Get a specific Field by name.*/ getField(name: string): CubeField; /** Set stores to be loaded/reloaded with data from this view. */ setStores(stores: Some): void; /** Update the filter on the current Query.*/ setFilter(filter: FilterLike): void; noteCubeLoaded(): void; noteCubeUpdated(changes: RecordSetDelta): void; getValuesForFieldFilter(fieldName: string, filter?: Filter): any[]; /** * True if leaf rows are exposed on results - i.e. Query sets includeLeaves or provideLeaves. * @internal */ get exposesLeaves(): boolean; /** * Create a new aggregate or bucket row data object. * @internal */ newParentRowData(id: string): ViewRowData; /** * Create the data object for an exposed leaf row. * @internal */ newLeafRowData(id: string, src: PlainObject): ViewRowData; assignDigest(data: ViewRowData): void; private buildIndices; private fullUpdate; private dataOnlyUpdate; private dataUnchangedUpdate; private loadStores; private updateResults; private generateRows; private groupAndInsertRecords; private bucketRows; private getSimpleUpdates; private hasDimOrBucketUpdates; private filterRecords; private createAggregationContext; /** * True if all aggregators depend only on child rows, allowing aggregate/bucket row reuse * and incremental data-only updates - see {@link Aggregator.dependsOnChildrenOnly}. * @internal */ get aggregatorsAreSimple(): boolean; /** * True if reused parent rows must re-derive context-reading fields - complex aggregators and * `canAggregateFn` results - on every generation, as either may move with the * per-generation AggregationContext. See {@link ParentRow.reuse}. * @internal */ get hasContextDependentFields(): boolean; private parseStores; destroy(): void; }