@tanstack/table-core 9.0.0-beta.47 → 9.0.0-beta.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/dist/core/row-models/coreRowModelsFeature.types.d.cts +1 -1
  2. package/dist/core/row-models/coreRowModelsFeature.types.d.ts +1 -1
  3. package/dist/core/row-models/coreRowModelsFeature.utils.cjs +1 -1
  4. package/dist/core/row-models/coreRowModelsFeature.utils.cjs.map +1 -1
  5. package/dist/core/row-models/coreRowModelsFeature.utils.d.cts +1 -1
  6. package/dist/core/row-models/coreRowModelsFeature.utils.d.ts +1 -1
  7. package/dist/core/row-models/coreRowModelsFeature.utils.js +1 -1
  8. package/dist/core/row-models/coreRowModelsFeature.utils.js.map +1 -1
  9. package/dist/features/aggregation/aggregationFeature.cjs +38 -0
  10. package/dist/features/aggregation/aggregationFeature.cjs.map +1 -0
  11. package/dist/features/aggregation/aggregationFeature.d.cts +10 -0
  12. package/dist/features/aggregation/aggregationFeature.d.ts +10 -0
  13. package/dist/features/aggregation/aggregationFeature.js +38 -0
  14. package/dist/features/aggregation/aggregationFeature.js.map +1 -0
  15. package/dist/features/aggregation/aggregationFeature.types.cjs +13 -0
  16. package/dist/features/aggregation/aggregationFeature.types.cjs.map +1 -0
  17. package/dist/features/aggregation/aggregationFeature.types.d.cts +172 -0
  18. package/dist/features/aggregation/aggregationFeature.types.d.ts +172 -0
  19. package/dist/features/aggregation/aggregationFeature.types.js +12 -0
  20. package/dist/features/aggregation/aggregationFeature.types.js.map +1 -0
  21. package/dist/features/aggregation/aggregationFeature.utils.cjs +198 -0
  22. package/dist/features/aggregation/aggregationFeature.utils.cjs.map +1 -0
  23. package/dist/features/aggregation/aggregationFeature.utils.d.cts +33 -0
  24. package/dist/features/aggregation/aggregationFeature.utils.d.ts +33 -0
  25. package/dist/features/aggregation/aggregationFeature.utils.js +192 -0
  26. package/dist/features/aggregation/aggregationFeature.utils.js.map +1 -0
  27. package/dist/features/aggregation/aggregationFns.cjs +240 -0
  28. package/dist/features/aggregation/aggregationFns.cjs.map +1 -0
  29. package/dist/features/aggregation/aggregationFns.d.cts +67 -0
  30. package/dist/features/aggregation/aggregationFns.d.ts +67 -0
  31. package/dist/features/aggregation/aggregationFns.js +229 -0
  32. package/dist/features/aggregation/aggregationFns.js.map +1 -0
  33. package/dist/features/column-faceting/createFacetedMinMaxValues.cjs +7 -4
  34. package/dist/features/column-faceting/createFacetedMinMaxValues.cjs.map +1 -1
  35. package/dist/features/column-faceting/createFacetedMinMaxValues.js +8 -5
  36. package/dist/features/column-faceting/createFacetedMinMaxValues.js.map +1 -1
  37. package/dist/features/column-faceting/createFacetedRowModel.cjs +1 -1
  38. package/dist/features/column-faceting/createFacetedRowModel.cjs.map +1 -1
  39. package/dist/features/column-faceting/createFacetedRowModel.js +1 -1
  40. package/dist/features/column-faceting/createFacetedRowModel.js.map +1 -1
  41. package/dist/features/column-faceting/createFacetedUniqueValues.cjs +8 -4
  42. package/dist/features/column-faceting/createFacetedUniqueValues.cjs.map +1 -1
  43. package/dist/features/column-faceting/createFacetedUniqueValues.js +9 -5
  44. package/dist/features/column-faceting/createFacetedUniqueValues.js.map +1 -1
  45. package/dist/features/column-filtering/columnFilteringFeature.types.d.cts +1 -1
  46. package/dist/features/column-filtering/columnFilteringFeature.types.d.ts +1 -1
  47. package/dist/{fns → features/column-filtering}/filterFns.cjs +1 -1
  48. package/dist/features/column-filtering/filterFns.cjs.map +1 -0
  49. package/dist/{fns → features/column-filtering}/filterFns.d.cts +4 -4
  50. package/dist/{fns → features/column-filtering}/filterFns.d.ts +4 -4
  51. package/dist/{fns → features/column-filtering}/filterFns.js +1 -1
  52. package/dist/features/column-filtering/filterFns.js.map +1 -0
  53. package/dist/features/column-grouping/columnGroupingFeature.cjs +3 -12
  54. package/dist/features/column-grouping/columnGroupingFeature.cjs.map +1 -1
  55. package/dist/features/column-grouping/columnGroupingFeature.d.cts +1 -1
  56. package/dist/features/column-grouping/columnGroupingFeature.d.ts +1 -1
  57. package/dist/features/column-grouping/columnGroupingFeature.js +4 -13
  58. package/dist/features/column-grouping/columnGroupingFeature.js.map +1 -1
  59. package/dist/features/column-grouping/columnGroupingFeature.types.d.cts +6 -87
  60. package/dist/features/column-grouping/columnGroupingFeature.types.d.ts +6 -87
  61. package/dist/features/column-grouping/columnGroupingFeature.utils.cjs +0 -64
  62. package/dist/features/column-grouping/columnGroupingFeature.utils.cjs.map +1 -1
  63. package/dist/features/column-grouping/columnGroupingFeature.utils.d.cts +2 -44
  64. package/dist/features/column-grouping/columnGroupingFeature.utils.d.ts +2 -44
  65. package/dist/features/column-grouping/columnGroupingFeature.utils.js +2 -63
  66. package/dist/features/column-grouping/columnGroupingFeature.utils.js.map +1 -1
  67. package/dist/features/column-grouping/createGroupedRowModel.cjs +23 -16
  68. package/dist/features/column-grouping/createGroupedRowModel.cjs.map +1 -1
  69. package/dist/features/column-grouping/createGroupedRowModel.d.cts +2 -6
  70. package/dist/features/column-grouping/createGroupedRowModel.d.ts +2 -6
  71. package/dist/features/column-grouping/createGroupedRowModel.js +25 -18
  72. package/dist/features/column-grouping/createGroupedRowModel.js.map +1 -1
  73. package/dist/features/global-filtering/globalFilteringFeature.utils.cjs +1 -1
  74. package/dist/features/global-filtering/globalFilteringFeature.utils.cjs.map +1 -1
  75. package/dist/features/global-filtering/globalFilteringFeature.utils.js +1 -1
  76. package/dist/features/global-filtering/globalFilteringFeature.utils.js.map +1 -1
  77. package/dist/features/row-sorting/rowSortingFeature.types.d.cts +1 -1
  78. package/dist/features/row-sorting/rowSortingFeature.types.d.ts +1 -1
  79. package/dist/features/row-sorting/rowSortingFeature.utils.cjs +1 -1
  80. package/dist/features/row-sorting/rowSortingFeature.utils.cjs.map +1 -1
  81. package/dist/features/row-sorting/rowSortingFeature.utils.js +1 -1
  82. package/dist/features/row-sorting/rowSortingFeature.utils.js.map +1 -1
  83. package/dist/{fns → features/row-sorting}/sortFns.cjs +1 -1
  84. package/dist/{fns/sortFns.js.map → features/row-sorting/sortFns.cjs.map} +1 -1
  85. package/dist/{fns → features/row-sorting}/sortFns.d.cts +4 -4
  86. package/dist/{fns → features/row-sorting}/sortFns.d.ts +4 -4
  87. package/dist/{fns → features/row-sorting}/sortFns.js +1 -1
  88. package/dist/features/row-sorting/sortFns.js.map +1 -0
  89. package/dist/features/stockFeatures.cjs +2 -0
  90. package/dist/features/stockFeatures.cjs.map +1 -1
  91. package/dist/features/stockFeatures.d.cts +2 -0
  92. package/dist/features/stockFeatures.d.ts +2 -0
  93. package/dist/features/stockFeatures.js +2 -0
  94. package/dist/features/stockFeatures.js.map +1 -1
  95. package/dist/index.cjs +7 -4
  96. package/dist/index.d.cts +7 -5
  97. package/dist/index.d.ts +7 -5
  98. package/dist/index.js +6 -4
  99. package/dist/static-functions.cjs +8 -3
  100. package/dist/static-functions.d.cts +3 -2
  101. package/dist/static-functions.d.ts +3 -2
  102. package/dist/static-functions.js +3 -2
  103. package/dist/types/Cell.d.cts +3 -1
  104. package/dist/types/Cell.d.ts +3 -1
  105. package/dist/types/Column.d.cts +4 -2
  106. package/dist/types/Column.d.ts +4 -2
  107. package/dist/types/ColumnDef.d.cts +5 -3
  108. package/dist/types/ColumnDef.d.ts +5 -3
  109. package/dist/types/Row.d.cts +3 -1
  110. package/dist/types/Row.d.ts +3 -1
  111. package/dist/types/RowModel.d.cts +1 -1
  112. package/dist/types/RowModel.d.ts +1 -1
  113. package/dist/types/RowModelFns.d.cts +3 -3
  114. package/dist/types/RowModelFns.d.ts +3 -3
  115. package/dist/types/Table.d.cts +1 -1
  116. package/dist/types/Table.d.ts +1 -1
  117. package/dist/types/TableFeatures.d.cts +4 -4
  118. package/dist/types/TableFeatures.d.ts +4 -4
  119. package/dist/types/TableOptions.d.cts +5 -3
  120. package/dist/types/TableOptions.d.ts +5 -3
  121. package/dist/types/TableState.d.cts +1 -1
  122. package/dist/types/TableState.d.ts +1 -1
  123. package/dist/worker/initTableWorker.cjs.map +1 -1
  124. package/dist/worker/initTableWorker.js.map +1 -1
  125. package/package.json +1 -1
  126. package/skills/aggregation/SKILL.md +131 -0
  127. package/skills/api-not-found/SKILL.md +1 -1
  128. package/skills/client-vs-server/SKILL.md +1 -1
  129. package/skills/column-faceting/SKILL.md +1 -1
  130. package/skills/column-filtering/SKILL.md +1 -1
  131. package/skills/column-ordering/SKILL.md +1 -1
  132. package/skills/column-pinning/SKILL.md +1 -1
  133. package/skills/column-resizing/SKILL.md +1 -1
  134. package/skills/column-sizing/SKILL.md +1 -1
  135. package/skills/column-visibility/SKILL.md +1 -1
  136. package/skills/core/SKILL.md +1 -1
  137. package/skills/custom-features/SKILL.md +1 -1
  138. package/skills/expanding/SKILL.md +1 -1
  139. package/skills/global-filtering/SKILL.md +1 -1
  140. package/skills/grouping/SKILL.md +12 -18
  141. package/skills/migrate-v8-to-v9/SKILL.md +15 -2
  142. package/skills/pagination/SKILL.md +1 -1
  143. package/skills/row-pinning/SKILL.md +1 -1
  144. package/skills/row-selection/SKILL.md +1 -1
  145. package/skills/sorting/SKILL.md +1 -1
  146. package/skills/table-features/SKILL.md +5 -2
  147. package/skills/typescript/SKILL.md +1 -1
  148. package/src/core/row-models/coreRowModelsFeature.utils.ts +1 -1
  149. package/src/features/aggregation/aggregationFeature.ts +59 -0
  150. package/src/features/aggregation/aggregationFeature.types.ts +312 -0
  151. package/src/features/aggregation/aggregationFeature.utils.ts +401 -0
  152. package/src/features/aggregation/aggregationFns.ts +336 -0
  153. package/src/features/column-faceting/createFacetedMinMaxValues.ts +33 -7
  154. package/src/features/column-faceting/createFacetedRowModel.ts +4 -1
  155. package/src/features/column-faceting/createFacetedUniqueValues.ts +45 -11
  156. package/src/features/column-filtering/columnFilteringFeature.types.ts +1 -1
  157. package/src/{fns → features/column-filtering}/filterFns.ts +4 -4
  158. package/src/features/column-grouping/columnGroupingFeature.ts +1 -20
  159. package/src/features/column-grouping/columnGroupingFeature.types.ts +4 -141
  160. package/src/features/column-grouping/columnGroupingFeature.utils.ts +1 -122
  161. package/src/features/column-grouping/createGroupedRowModel.ts +32 -41
  162. package/src/features/global-filtering/globalFilteringFeature.utils.ts +1 -1
  163. package/src/features/row-sorting/rowSortingFeature.types.ts +1 -1
  164. package/src/features/row-sorting/rowSortingFeature.utils.ts +1 -1
  165. package/src/{fns → features/row-sorting}/sortFns.ts +4 -7
  166. package/src/features/stockFeatures.ts +3 -0
  167. package/src/index.ts +7 -8
  168. package/src/static-functions.ts +1 -0
  169. package/src/types/Cell.ts +2 -0
  170. package/src/types/Column.ts +3 -1
  171. package/src/types/ColumnDef.ts +6 -3
  172. package/src/types/Row.ts +2 -0
  173. package/src/types/RowModelFns.ts +3 -3
  174. package/src/types/TableFeatures.ts +4 -4
  175. package/src/types/TableOptions.ts +5 -1
  176. package/src/worker/initTableWorker.ts +1 -1
  177. package/dist/fns/aggregationFns.cjs +0 -234
  178. package/dist/fns/aggregationFns.cjs.map +0 -1
  179. package/dist/fns/aggregationFns.d.cts +0 -139
  180. package/dist/fns/aggregationFns.d.ts +0 -139
  181. package/dist/fns/aggregationFns.js +0 -221
  182. package/dist/fns/aggregationFns.js.map +0 -1
  183. package/dist/fns/filterFns.cjs.map +0 -1
  184. package/dist/fns/filterFns.js.map +0 -1
  185. package/dist/fns/sortFns.cjs.map +0 -1
  186. package/src/fns/aggregationFns.ts +0 -303
@@ -0,0 +1,312 @@
1
+ import type { BuiltInAggregationFn } from './aggregationFns'
2
+ import type { Cell } from '../../types/Cell'
3
+ import type { Column } from '../../types/Column'
4
+ import type { ColumnDefTemplate } from '../../types/ColumnDef'
5
+ import type { IsAny, TableFeatures } from '../../types/TableFeatures'
6
+ import type { Row } from '../../types/Row'
7
+ import type { Table } from '../../types/Table'
8
+ import type { CellData, RowData } from '../../types/type-utils'
9
+
10
+ /** Declaration-merging fallback for named aggregation definitions. */
11
+ export interface AggregationFns {}
12
+
13
+ /** Values and table objects available while one aggregation is evaluated. */
14
+ export interface AggregationContext<
15
+ TFeatures extends TableFeatures,
16
+ TData extends RowData,
17
+ TValue = unknown,
18
+ > {
19
+ /** The column whose values are being aggregated. */
20
+ column: Column<TFeatures, TData, TValue>
21
+ /** Convenience alias for `column.id`. */
22
+ columnId: string
23
+ /** Reads this column's value from one of `rows`. */
24
+ getValue: (row: Row<TFeatures, TData>) => TValue
25
+ /**
26
+ * The synthetic grouped row receiving this result. This property is omitted
27
+ * for root or caller-supplied-row aggregation. Its `depth` identifies the
28
+ * grouping level when grouped aggregation needs that distinction.
29
+ */
30
+ groupingRow?: Row<TFeatures, TData>
31
+ /**
32
+ * Terminal leaf rows included in this aggregation. The executor normalizes
33
+ * hierarchical and duplicate row inputs before invoking the definition.
34
+ */
35
+ rows: ReadonlyArray<Row<TFeatures, TData>>
36
+ /** The table that owns the column and rows. */
37
+ table: Table<TFeatures, TData>
38
+ }
39
+
40
+ /** Additional values available when merging nested grouped results. */
41
+ export interface AggregationMergeContext<
42
+ TFeatures extends TableFeatures,
43
+ TData extends RowData,
44
+ TValue,
45
+ TResult,
46
+ > extends AggregationContext<TFeatures, TData, TValue> {
47
+ /** Results produced for each immediate child group, in child-row order. */
48
+ childResults: ReadonlyArray<TResult>
49
+ /** Immediate child group rows corresponding to `childResults`. */
50
+ childRows: ReadonlyArray<Row<TFeatures, TData>>
51
+ }
52
+
53
+ /** A context-based aggregation definition and optional grouped-result merge. */
54
+ export interface AggregationFnDef<
55
+ TFeatures extends TableFeatures = any,
56
+ TData extends RowData = any,
57
+ TValue = unknown,
58
+ TResult = unknown,
59
+ > {
60
+ /** Computes a result directly from normalized terminal rows. */
61
+ aggregate: (context: AggregationContext<TFeatures, TData, TValue>) => TResult
62
+ /**
63
+ * Combines already-computed immediate child-group results. When omitted,
64
+ * nested grouping falls back to `aggregate` over the group's terminal rows.
65
+ */
66
+ merge?: (
67
+ context: AggregationMergeContext<TFeatures, TData, TValue, TResult>,
68
+ ) => TResult
69
+ }
70
+
71
+ /**
72
+ * Creates a typed context-based aggregation definition for a column or
73
+ * aggregation-function registry.
74
+ */
75
+ export function constructAggregationFn<
76
+ TFeatures extends TableFeatures = any,
77
+ TData extends RowData = any,
78
+ TValue = unknown,
79
+ TResult = unknown,
80
+ >(
81
+ definition: AggregationFnDef<TFeatures, TData, TValue, TResult>,
82
+ ): AggregationFnDef<TFeatures, TData, TValue, TResult> {
83
+ return definition
84
+ }
85
+
86
+ /** Aggregation-definition registry carried by a table feature set. */
87
+ export interface RowModelFns_Aggregation<
88
+ in out TFeatures extends TableFeatures,
89
+ in out TData extends RowData,
90
+ > {
91
+ aggregationFns: Record<string, AggregationFnDef<TFeatures, TData, any, any>>
92
+ }
93
+
94
+ /** Named context-based aggregation definitions registered on a feature set. */
95
+ export type CustomAggregationFns<
96
+ TFeatures extends TableFeatures,
97
+ TData extends RowData,
98
+ > = Record<string, AggregationFnDef<TFeatures, TData, any, any>>
99
+
100
+ /** String names available from a feature set's aggregation registry. */
101
+ export type ExtractAggregationFnKeys<TFeatures extends TableFeatures> =
102
+ IsAny<TFeatures> extends true
103
+ ? keyof AggregationFns | BuiltInAggregationFn
104
+ : TFeatures extends { aggregationFns: infer TAggregationFns extends object }
105
+ ? Extract<keyof TAggregationFns, string>
106
+ : keyof AggregationFns
107
+
108
+ /** A registered name, automatic inference, or inline aggregation definition. */
109
+ export type AggregationFnRef<
110
+ TFeatures extends TableFeatures,
111
+ TData extends RowData,
112
+ TValue = unknown,
113
+ TResult = unknown,
114
+ > =
115
+ | 'auto'
116
+ | ExtractAggregationFnKeys<TFeatures>
117
+ | AggregationFnDef<TFeatures, TData, TValue, TResult>
118
+
119
+ /** Gives an aggregation reference a stable key in a multiple result. */
120
+ export interface AggregationFnDescriptor<
121
+ TFeatures extends TableFeatures,
122
+ TData extends RowData,
123
+ TValue = unknown,
124
+ TResult = unknown,
125
+ > {
126
+ /** The named, automatic, or inline definition to execute. */
127
+ aggregationFn: AggregationFnRef<TFeatures, TData, TValue, TResult>
128
+ /** Stable key used in the object returned by a multiple aggregation. */
129
+ id: string
130
+ }
131
+
132
+ /** One named or explicitly keyed entry in a multiple aggregation option. */
133
+ export type AggregationFnListItem<
134
+ TFeatures extends TableFeatures,
135
+ TData extends RowData,
136
+ TValue = unknown,
137
+ > =
138
+ | 'auto'
139
+ | ExtractAggregationFnKeys<TFeatures>
140
+ | AggregationFnDescriptor<TFeatures, TData, TValue, any>
141
+
142
+ /** A scalar aggregation reference or a list that produces a keyed object. */
143
+ export type AggregationFnOption<
144
+ TFeatures extends TableFeatures,
145
+ TData extends RowData,
146
+ TValue = unknown,
147
+ > =
148
+ | AggregationFnRef<TFeatures, TData, TValue, any>
149
+ | ReadonlyArray<AggregationFnListItem<TFeatures, TData, TValue>>
150
+
151
+ /** Extracts the result type produced by an aggregation definition. */
152
+ export type AggregationResultOf<TDefinition> =
153
+ TDefinition extends AggregationFnDef<any, any, any, infer TResult>
154
+ ? TResult
155
+ : unknown
156
+
157
+ type RegisteredAggregationDefinition<
158
+ TFeatures extends TableFeatures,
159
+ TKey extends PropertyKey,
160
+ > = TFeatures extends {
161
+ aggregationFns: infer TRegistry extends Record<PropertyKey, unknown>
162
+ }
163
+ ? TKey extends keyof TRegistry
164
+ ? TRegistry[TKey]
165
+ : never
166
+ : never
167
+
168
+ type AggregationResultOfRef<TRef, TFeatures extends TableFeatures> =
169
+ TRef extends AggregationFnDef<any, any, any, any>
170
+ ? AggregationResultOf<TRef>
171
+ : TRef extends 'auto'
172
+ ? RegisteredAggregationResult<TFeatures>
173
+ : TRef extends PropertyKey
174
+ ? AggregationResultOf<RegisteredAggregationDefinition<TFeatures, TRef>>
175
+ : unknown
176
+
177
+ type AggregationEntryId<TEntry> = TEntry extends string
178
+ ? TEntry
179
+ : TEntry extends { id: infer TId extends string }
180
+ ? TId
181
+ : never
182
+
183
+ type AggregationEntryDefinition<TEntry> = TEntry extends {
184
+ aggregationFn: infer TDefinition
185
+ }
186
+ ? TDefinition
187
+ : TEntry
188
+
189
+ /** Infers the scalar or keyed result produced by an aggregation option. */
190
+ export type AggregationResult<TOption, TFeatures extends TableFeatures = any> =
191
+ TOption extends ReadonlyArray<infer TEntry>
192
+ ? {
193
+ [TKey in AggregationEntryId<TEntry>]: AggregationResultOfRef<
194
+ AggregationEntryDefinition<Extract<TEntry, TKey | { id: TKey }>>,
195
+ TFeatures
196
+ >
197
+ }
198
+ : AggregationResultOfRef<TOption, TFeatures>
199
+
200
+ type RegisteredAggregationResult<TFeatures extends TableFeatures> =
201
+ TFeatures extends {
202
+ aggregationFns: infer TRegistry extends Record<string, unknown>
203
+ }
204
+ ? AggregationResultOf<TRegistry[keyof TRegistry]>
205
+ : unknown
206
+
207
+ /** Default public result union when a column's precise option is not known. */
208
+ export type ColumnAggregationValue<TFeatures extends TableFeatures> =
209
+ | RegisteredAggregationResult<TFeatures>
210
+ | Record<string, RegisteredAggregationResult<TFeatures> | undefined>
211
+ | undefined
212
+
213
+ /** A validated aggregation entry returned by `column.getAggregationFns()`. */
214
+ export interface ResolvedAggregationFn<
215
+ TFeatures extends TableFeatures,
216
+ TData extends RowData,
217
+ > {
218
+ /** Resolved definition, or `undefined` when configuration is invalid. */
219
+ aggregationFn: AggregationFnDef<TFeatures, TData, any, any> | undefined
220
+ /** Key used for a multiple result; scalar inline definitions have no id. */
221
+ id: string | undefined
222
+ }
223
+
224
+ /** Column-definition options installed by `aggregationFeature`. */
225
+ export interface ColumnDef_Aggregation<
226
+ in out TFeatures extends TableFeatures,
227
+ in out TData extends RowData,
228
+ TValue extends CellData = CellData,
229
+ > {
230
+ /** Renderer used for a grouped row's aggregated cell. */
231
+ aggregatedCell?: ColumnDefTemplate<
232
+ ReturnType<Cell<TFeatures, TData, TValue>['getContext']>
233
+ >
234
+ /**
235
+ * One aggregation reference for a scalar result, or an array for a keyed
236
+ * result object. Inline definitions in an array require an explicit `id`.
237
+ */
238
+ aggregationFn?: AggregationFnOption<TFeatures, TData, TValue>
239
+ /**
240
+ * Optionally supplies a precomputed aggregation value for this column.
241
+ * Return `{ value }` to handle the request, including `{ value: undefined }`;
242
+ * return `undefined` to use the local aggregation fallback.
243
+ */
244
+ getAggregationValue?: (
245
+ context: AggregationValueContext<TFeatures, TData, TValue>,
246
+ ) => AggregationValueResult | undefined
247
+ }
248
+
249
+ /** Column instance APIs installed by `aggregationFeature`. */
250
+ export interface Column_Aggregation<
251
+ in out TFeatures extends TableFeatures,
252
+ in out TData extends RowData,
253
+ > {
254
+ /** Resolves the configured scalar or multiple aggregation definitions. */
255
+ getAggregationFns: () => ReadonlyArray<
256
+ ResolvedAggregationFn<TFeatures, TData>
257
+ >
258
+ /**
259
+ * Aggregates this column over the default pre-grouped row model, or over a
260
+ * caller-provided array of rows. Explicit rows are normalized to unique
261
+ * terminal leaves and are intentionally not cached.
262
+ */
263
+ getAggregationValue: <TResult = ColumnAggregationValue<TFeatures>>(
264
+ rows?: ReadonlyArray<Row<TFeatures, TData>>,
265
+ ) => TResult
266
+ /** Infers `sum` for a numeric first row and `extent` for a Date first row. */
267
+ getAutoAggregationFn: () =>
268
+ | AggregationFnDef<TFeatures, TData, any, any>
269
+ | undefined
270
+ }
271
+
272
+ /** Cell instance APIs installed by `aggregationFeature`. */
273
+ export interface Cell_Aggregation {
274
+ /** Whether this cell displays an aggregate on a synthetic grouped row. */
275
+ getIsAggregated: () => boolean
276
+ }
277
+
278
+ /** Internal per-row cache used while grouped aggregates are evaluated. */
279
+ export interface Row_Aggregation {
280
+ /** Cached aggregate results keyed by column id. */
281
+ _aggregationValuesCache: Record<string, unknown>
282
+ }
283
+
284
+ /** Values passed to a column-level aggregation-value provider. */
285
+ export interface AggregationValueContext<
286
+ TFeatures extends TableFeatures,
287
+ TData extends RowData,
288
+ TValue extends CellData = CellData,
289
+ > {
290
+ /** The column whose value was requested. */
291
+ column: Column<TFeatures, TData, TValue>
292
+ /** Caller-provided rows, or `undefined` for the default row model. */
293
+ rows?: ReadonlyArray<Row<TFeatures, TData>>
294
+ /** The table that owns the column. */
295
+ table: Table<TFeatures, TData>
296
+ }
297
+
298
+ /** Marks an aggregation-value override as handled. */
299
+ export interface AggregationValueResult<TResult = unknown> {
300
+ /** The supplied value. `undefined` is still a handled result. */
301
+ value: TResult
302
+ }
303
+
304
+ /** Table options installed by `aggregationFeature`. */
305
+ export interface TableOptions_Aggregation {
306
+ /**
307
+ * Disables local `column.getAggregationValue()` calculation when a column
308
+ * override does not handle the request. Group values supplied by manually
309
+ * grouped rows remain the responsibility of the data owner.
310
+ */
311
+ manualAggregation?: boolean
312
+ }
@@ -0,0 +1,401 @@
1
+ import { hasOwn, makeObjectMap } from '../../utils'
2
+ import type { Cell } from '../../types/Cell'
3
+ import type { Column, Column_Internal } from '../../types/Column'
4
+ import type { Row } from '../../types/Row'
5
+ import type { TableFeatures } from '../../types/TableFeatures'
6
+ import type { CellData, RowData } from '../../types/type-utils'
7
+ import type {
8
+ AggregationFnDef,
9
+ AggregationFnDescriptor,
10
+ AggregationFnRef,
11
+ ColumnAggregationValue,
12
+ ResolvedAggregationFn,
13
+ } from './aggregationFeature.types'
14
+
15
+ interface AggregationCacheEntry {
16
+ aggregationFnOption: unknown
17
+ dependency: unknown
18
+ registry: unknown
19
+ value: unknown
20
+ }
21
+
22
+ interface ResolvedAggregationFnsCacheEntry<
23
+ TFeatures extends TableFeatures,
24
+ TData extends RowData,
25
+ > {
26
+ coreRowModel: unknown
27
+ option: unknown
28
+ registry: unknown
29
+ value: ReadonlyArray<ResolvedAggregationFn<TFeatures, TData>>
30
+ }
31
+
32
+ function isAggregationFnDef(value: unknown): value is AggregationFnDef {
33
+ return !!value && typeof value === 'object' && 'aggregate' in value
34
+ }
35
+
36
+ function isAggregationFnDescriptor(
37
+ value: unknown,
38
+ ): value is AggregationFnDescriptor<any, any> {
39
+ return (
40
+ !!value &&
41
+ typeof value === 'object' &&
42
+ 'id' in value &&
43
+ 'aggregationFn' in value
44
+ )
45
+ }
46
+
47
+ function warn(message: string) {
48
+ if (process.env.NODE_ENV === 'development') {
49
+ console.warn(message)
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Flattens hierarchical row inputs to unique terminal leaves in encounter
55
+ * order. This is the normalization used by public aggregation-value calls.
56
+ */
57
+ export function normalizeAggregationRows<
58
+ TFeatures extends TableFeatures,
59
+ TData extends RowData,
60
+ >(rows: ReadonlyArray<Row<TFeatures, TData>>): Array<Row<TFeatures, TData>> {
61
+ const result: Array<Row<TFeatures, TData>> = []
62
+ const seen = new Set<string>()
63
+
64
+ const visit = (row: Row<TFeatures, TData>) => {
65
+ if (row.subRows.length) {
66
+ for (let i = 0; i < row.subRows.length; i++) {
67
+ visit(row.subRows[i]!)
68
+ }
69
+ return
70
+ }
71
+
72
+ if (!seen.has(row.id)) {
73
+ seen.add(row.id)
74
+ result.push(row)
75
+ }
76
+ }
77
+
78
+ for (let i = 0; i < rows.length; i++) {
79
+ visit(rows[i]!)
80
+ }
81
+
82
+ return result
83
+ }
84
+
85
+ function getAutoAggregationFnName(
86
+ value: unknown,
87
+ ): 'extent' | 'sum' | undefined {
88
+ if (typeof value === 'number') {
89
+ return 'sum'
90
+ }
91
+
92
+ if (value instanceof Date && !Number.isNaN(value.getTime())) {
93
+ return 'extent'
94
+ }
95
+
96
+ return undefined
97
+ }
98
+
99
+ /** Resolves the `sum` or `extent` definition inferred from the first core row. */
100
+ export function column_getAutoAggregationFn<
101
+ TFeatures extends TableFeatures,
102
+ TData extends RowData,
103
+ TValue extends CellData = CellData,
104
+ >(column: Column_Internal<TFeatures, TData, TValue>) {
105
+ const value = column.table.getCoreRowModel().flatRows[0]?.getValue(column.id)
106
+
107
+ const name = getAutoAggregationFnName(value)
108
+ if (!name) return undefined
109
+
110
+ const aggregationFn = column.table._rowModelFns.aggregationFns?.[name]
111
+
112
+ if (!aggregationFn) {
113
+ warn(
114
+ `aggregationFn '${name}' (auto) for column '${column.id}' is not registered`,
115
+ )
116
+ }
117
+
118
+ return aggregationFn
119
+ }
120
+
121
+ function resolveAggregationFn<
122
+ TFeatures extends TableFeatures,
123
+ TData extends RowData,
124
+ >(
125
+ column: Column_Internal<TFeatures, TData, any>,
126
+ ref: AggregationFnRef<TFeatures, TData, any, any>,
127
+ ): AggregationFnDef<TFeatures, TData, any, any> | undefined {
128
+ if (isAggregationFnDef(ref)) return ref as any
129
+ if (ref === 'auto') return column_getAutoAggregationFn(column)
130
+
131
+ const aggregationFn =
132
+ column.table._rowModelFns.aggregationFns?.[ref as string]
133
+ if (!aggregationFn) {
134
+ warn(
135
+ `aggregationFn '${String(ref)}' for column '${column.id}' is not registered`,
136
+ )
137
+ }
138
+ return aggregationFn
139
+ }
140
+
141
+ /** Resolves and validates a column's scalar or multiple aggregation option. */
142
+ export function column_getAggregationFns<
143
+ TFeatures extends TableFeatures,
144
+ TData extends RowData,
145
+ TValue extends CellData = CellData,
146
+ >(
147
+ column: Column_Internal<TFeatures, TData, TValue>,
148
+ ): ReadonlyArray<ResolvedAggregationFn<TFeatures, TData>> {
149
+ const option = column.columnDef.aggregationFn
150
+ const registry = column.table._rowModelFns.aggregationFns
151
+ const coreRowModel = column.table.getCoreRowModel()
152
+ const previous = (column as any)._resolvedAggregationFnsCache as
153
+ | ResolvedAggregationFnsCacheEntry<TFeatures, TData>
154
+ | undefined
155
+
156
+ if (
157
+ previous &&
158
+ previous.option === option &&
159
+ previous.registry === registry &&
160
+ previous.coreRowModel === coreRowModel
161
+ ) {
162
+ return previous.value
163
+ }
164
+
165
+ const finish = (
166
+ value: ReadonlyArray<ResolvedAggregationFn<TFeatures, TData>>,
167
+ ) => {
168
+ ;(column as any)._resolvedAggregationFnsCache = {
169
+ coreRowModel,
170
+ option,
171
+ registry,
172
+ value,
173
+ } satisfies ResolvedAggregationFnsCacheEntry<TFeatures, TData>
174
+ return value
175
+ }
176
+
177
+ if (option == null) return finish([])
178
+
179
+ if (!Array.isArray(option)) {
180
+ return finish([
181
+ {
182
+ aggregationFn: resolveAggregationFn(column, option as any),
183
+ id: typeof option === 'string' ? option : undefined,
184
+ },
185
+ ])
186
+ }
187
+
188
+ const ids = makeObjectMap<number>()
189
+ for (let i = 0; i < option.length; i++) {
190
+ const item = option[i]
191
+ const id =
192
+ typeof item === 'string'
193
+ ? item
194
+ : isAggregationFnDescriptor(item)
195
+ ? item.id
196
+ : undefined
197
+ if (id !== undefined) ids[id] = (ids[id] ?? 0) + 1
198
+ }
199
+
200
+ const resolved: Array<ResolvedAggregationFn<TFeatures, TData>> = []
201
+
202
+ for (let i = 0; i < option.length; i++) {
203
+ const item = option[i]
204
+ const id =
205
+ typeof item === 'string'
206
+ ? item
207
+ : isAggregationFnDescriptor(item)
208
+ ? item.id
209
+ : undefined
210
+
211
+ if (id === undefined) {
212
+ warn(
213
+ `aggregationFn at index ${i} for column '${column.id}' needs a stable id`,
214
+ )
215
+ resolved.push({ aggregationFn: undefined, id: undefined })
216
+ continue
217
+ }
218
+
219
+ if (ids[id]! > 1) {
220
+ warn(`aggregationFn id '${id}' for column '${column.id}' is duplicated`)
221
+ resolved.push({ aggregationFn: undefined, id })
222
+ continue
223
+ }
224
+
225
+ const ref = isAggregationFnDescriptor(item) ? item.aggregationFn : item
226
+ resolved.push({
227
+ aggregationFn: resolveAggregationFn(column, ref),
228
+ id,
229
+ })
230
+ }
231
+
232
+ return finish(resolved)
233
+ }
234
+
235
+ function getChildResult(
236
+ childValue: unknown,
237
+ isMultiple: boolean,
238
+ id: string | undefined,
239
+ ) {
240
+ if (!isMultiple) return childValue
241
+ if (!id || !childValue || typeof childValue !== 'object') return undefined
242
+ return hasOwn(childValue, id)
243
+ ? (childValue as Record<string, unknown>)[id]
244
+ : undefined
245
+ }
246
+
247
+ /** Executes every configured aggregation for a column over normalized rows. */
248
+ export function aggregateColumnValue<
249
+ TFeatures extends TableFeatures,
250
+ TData extends RowData,
251
+ >(args: {
252
+ childRows?: ReadonlyArray<Row<TFeatures, TData>>
253
+ column: Column<TFeatures, TData, unknown>
254
+ groupingRow?: Row<TFeatures, TData>
255
+ rows: ReadonlyArray<Row<TFeatures, TData>>
256
+ }): unknown {
257
+ const { childRows, column, groupingRow, rows } = args
258
+ const internalColumn = column as Column_Internal<TFeatures, TData, unknown>
259
+ const entries = column_getAggregationFns(internalColumn)
260
+ const isMultiple = Array.isArray(internalColumn.columnDef.aggregationFn)
261
+ const canMerge =
262
+ !!childRows?.length &&
263
+ childRows.every(
264
+ (row) =>
265
+ !!(row as any).groupingColumnId &&
266
+ (row as any).groupingColumnId !== column.id,
267
+ )
268
+
269
+ const execute = (entry: ResolvedAggregationFn<TFeatures, TData>) => {
270
+ const definition = entry.aggregationFn
271
+ if (!definition) return undefined
272
+
273
+ const context = {
274
+ column,
275
+ columnId: column.id,
276
+ getValue: (row: Row<TFeatures, TData>) => row.getValue(column.id),
277
+ ...(groupingRow ? { groupingRow } : {}),
278
+ rows,
279
+ table: column.table as any,
280
+ }
281
+
282
+ if (canMerge && definition.merge) {
283
+ return definition.merge({
284
+ ...context,
285
+ childResults: childRows.map((row) =>
286
+ getChildResult(row.getValue(column.id), isMultiple, entry.id),
287
+ ),
288
+ childRows: childRows,
289
+ })
290
+ }
291
+
292
+ return definition.aggregate(context)
293
+ }
294
+
295
+ if (!isMultiple) {
296
+ return entries[0] ? execute(entries[0]) : undefined
297
+ }
298
+
299
+ const result = makeObjectMap<unknown>()
300
+ for (let i = 0; i < entries.length; i++) {
301
+ const entry = entries[i]!
302
+ if (entry.id !== undefined) {
303
+ result[entry.id] = execute(entry)
304
+ }
305
+ }
306
+ return result
307
+ }
308
+
309
+ /** Implements `column.getAggregationValue(rows?)` and its default-value cache. */
310
+ export function column_getAggregationValue<
311
+ TFeatures extends TableFeatures,
312
+ TData extends RowData,
313
+ TValue extends CellData = CellData,
314
+ >(
315
+ column: Column_Internal<TFeatures, TData, TValue>,
316
+ rows?: ReadonlyArray<Row<TFeatures, TData>>,
317
+ ): ColumnAggregationValue<TFeatures> {
318
+ const providedResult = column.columnDef.getAggregationValue?.({
319
+ column: column as any,
320
+ rows,
321
+ table: column.table as any,
322
+ })
323
+
324
+ if (providedResult) return providedResult.value as any
325
+ if (column.table.options.manualAggregation) return undefined
326
+
327
+ if (rows !== undefined) {
328
+ return aggregateColumnValue({
329
+ column: column as any,
330
+ rows: normalizeAggregationRows(rows),
331
+ }) as any
332
+ }
333
+
334
+ const model = column.table.getPreGroupedRowModel()
335
+ const previous = (column as any)._aggregationValueCache as
336
+ | AggregationCacheEntry
337
+ | undefined
338
+ const registry = column.table._rowModelFns.aggregationFns
339
+ const aggregationFnOption = column.columnDef.aggregationFn
340
+
341
+ if (
342
+ previous &&
343
+ previous.dependency === model &&
344
+ previous.registry === registry &&
345
+ previous.aggregationFnOption === aggregationFnOption
346
+ ) {
347
+ return previous.value as any
348
+ }
349
+
350
+ const value = aggregateColumnValue({
351
+ column: column as any,
352
+ rows: normalizeAggregationRows(model.rows),
353
+ })
354
+ ;(column as any)._aggregationValueCache = {
355
+ aggregationFnOption,
356
+ dependency: model,
357
+ registry,
358
+ value,
359
+ } satisfies AggregationCacheEntry
360
+ return value as any
361
+ }
362
+
363
+ /** Implements `cell.getIsAggregated()` for synthetic grouped rows. */
364
+ export function cell_getIsAggregated<
365
+ TFeatures extends TableFeatures,
366
+ TData extends RowData,
367
+ TValue extends CellData = CellData,
368
+ >(cell: Cell<TFeatures, TData, TValue>) {
369
+ const groupingColumnId = (cell.row as any).groupingColumnId as
370
+ | string
371
+ | undefined
372
+ if (!groupingColumnId || groupingColumnId === cell.column.id) return false
373
+
374
+ const grouping = (cell.column.table as any).atoms.grouping?.get?.() as
375
+ | Array<string>
376
+ | undefined
377
+ if (grouping?.includes(cell.column.id)) return false
378
+
379
+ return column_getAggregationFns(cell.column as any).some(
380
+ (entry) => !!entry.aggregationFn,
381
+ )
382
+ }
383
+
384
+ /** Formats the default scalar or keyed aggregated-cell representation. */
385
+ export function formatAggregatedCellValue(
386
+ value: unknown,
387
+ option: unknown,
388
+ ): string | null {
389
+ if (value == null) return null
390
+
391
+ if (Array.isArray(option) && typeof value === 'object') {
392
+ const entries = Object.keys(value)
393
+ return entries
394
+ .map(
395
+ (key) => `${key}: ${String((value as Record<string, unknown>)[key])}`,
396
+ )
397
+ .join(', ')
398
+ }
399
+
400
+ return String(value)
401
+ }