@tanstack/table-core 9.0.0-beta.51 → 9.0.0-beta.52
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.
- package/dist/features/column-grouping/createGroupedRowModel.cjs +19 -11
- package/dist/features/column-grouping/createGroupedRowModel.cjs.map +1 -1
- package/dist/features/column-grouping/createGroupedRowModel.js +20 -12
- package/dist/features/column-grouping/createGroupedRowModel.js.map +1 -1
- package/dist/features/row-aggregation/aggregationFns.cjs +80 -35
- package/dist/features/row-aggregation/aggregationFns.cjs.map +1 -1
- package/dist/features/row-aggregation/aggregationFns.js +80 -35
- package/dist/features/row-aggregation/aggregationFns.js.map +1 -1
- package/dist/features/row-aggregation/rowAggregationFeature.cjs +0 -3
- package/dist/features/row-aggregation/rowAggregationFeature.cjs.map +1 -1
- package/dist/features/row-aggregation/rowAggregationFeature.js +1 -4
- package/dist/features/row-aggregation/rowAggregationFeature.js.map +1 -1
- package/dist/features/row-aggregation/rowAggregationFeature.types.cjs.map +1 -1
- package/dist/features/row-aggregation/rowAggregationFeature.types.d.cts +2 -2
- package/dist/features/row-aggregation/rowAggregationFeature.types.d.ts +2 -2
- package/dist/features/row-aggregation/rowAggregationFeature.types.js.map +1 -1
- package/dist/features/row-aggregation/rowAggregationFeature.utils.cjs +35 -4
- package/dist/features/row-aggregation/rowAggregationFeature.utils.cjs.map +1 -1
- package/dist/features/row-aggregation/rowAggregationFeature.utils.d.cts +15 -1
- package/dist/features/row-aggregation/rowAggregationFeature.utils.d.ts +15 -1
- package/dist/features/row-aggregation/rowAggregationFeature.utils.js +35 -5
- package/dist/features/row-aggregation/rowAggregationFeature.utils.js.map +1 -1
- package/dist/static-functions.cjs +1 -0
- package/dist/static-functions.d.cts +2 -2
- package/dist/static-functions.d.ts +2 -2
- package/dist/static-functions.js +2 -2
- package/package.json +1 -1
- package/skills/aggregation/SKILL.md +1 -1
- package/skills/api-not-found/SKILL.md +1 -1
- package/skills/client-vs-server/SKILL.md +1 -1
- package/skills/column-faceting/SKILL.md +1 -1
- package/skills/column-filtering/SKILL.md +1 -1
- package/skills/column-ordering/SKILL.md +1 -1
- package/skills/column-pinning/SKILL.md +1 -1
- package/skills/column-resizing/SKILL.md +1 -1
- package/skills/column-sizing/SKILL.md +1 -1
- package/skills/column-visibility/SKILL.md +1 -1
- package/skills/core/SKILL.md +1 -1
- package/skills/custom-features/SKILL.md +1 -1
- package/skills/expanding/SKILL.md +1 -1
- package/skills/global-filtering/SKILL.md +1 -1
- package/skills/grouping/SKILL.md +1 -1
- package/skills/migrate-v8-to-v9/SKILL.md +1 -1
- package/skills/pagination/SKILL.md +1 -1
- package/skills/row-pinning/SKILL.md +1 -1
- package/skills/row-selection/SKILL.md +1 -1
- package/skills/sorting/SKILL.md +1 -1
- package/skills/table-features/SKILL.md +1 -1
- package/skills/typescript/SKILL.md +1 -1
- package/src/features/column-grouping/createGroupedRowModel.ts +47 -10
- package/src/features/row-aggregation/aggregationFns.ts +80 -42
- package/src/features/row-aggregation/rowAggregationFeature.ts +1 -5
- package/src/features/row-aggregation/rowAggregationFeature.types.ts +2 -2
- package/src/features/row-aggregation/rowAggregationFeature.utils.ts +60 -3
package/skills/core/SKILL.md
CHANGED
|
@@ -5,7 +5,7 @@ description: >
|
|
|
5
5
|
metadata:
|
|
6
6
|
type: sub-skill
|
|
7
7
|
library: '@tanstack/table-core'
|
|
8
|
-
library_version: '9.0.0-beta.
|
|
8
|
+
library_version: '9.0.0-beta.52'
|
|
9
9
|
requires: ['core', 'table-features', 'typescript']
|
|
10
10
|
sources:
|
|
11
11
|
- 'TanStack/table:docs/framework/react/guide/custom-features.md'
|
package/skills/grouping/SKILL.md
CHANGED
|
@@ -5,7 +5,7 @@ description: >
|
|
|
5
5
|
metadata:
|
|
6
6
|
type: lifecycle
|
|
7
7
|
library: '@tanstack/table-core'
|
|
8
|
-
library_version: '9.0.0-beta.
|
|
8
|
+
library_version: '9.0.0-beta.52'
|
|
9
9
|
requires: ['core', 'table-features', 'typescript']
|
|
10
10
|
sources:
|
|
11
11
|
- 'TanStack/table:docs/framework/react/guide/migrating.md'
|
package/skills/sorting/SKILL.md
CHANGED
|
@@ -5,10 +5,10 @@ import { table_autoResetExpanded } from '../row-expanding/rowExpandingFeature.ut
|
|
|
5
5
|
import { table_autoResetPageIndex } from '../row-pagination/rowPaginationFeature.utils'
|
|
6
6
|
import {
|
|
7
7
|
aggregateColumnValue,
|
|
8
|
-
|
|
8
|
+
normalizeUniqueAggregationRows,
|
|
9
9
|
} from '../row-aggregation/rowAggregationFeature.utils'
|
|
10
|
-
import { row_getGroupingValue } from './columnGroupingFeature.utils'
|
|
11
10
|
import type { Row_ColumnGrouping } from './columnGroupingFeature.types'
|
|
11
|
+
import type { Column_Internal } from '../../types/Column'
|
|
12
12
|
import type { TableFeatures } from '../../types/TableFeatures'
|
|
13
13
|
import type { RowModel } from '../../core/row-models/coreRowModelsFeature.types'
|
|
14
14
|
import type { Table, Table_Internal } from '../../types/Table'
|
|
@@ -103,7 +103,7 @@ function _createGroupedRowModel<
|
|
|
103
103
|
const columnId = existingGrouping[depth] as string
|
|
104
104
|
|
|
105
105
|
// Group the rows together for this level
|
|
106
|
-
const rowGroupsMap = groupBy(rows, columnId)
|
|
106
|
+
const rowGroupsMap = groupBy(table, rows, columnId)
|
|
107
107
|
|
|
108
108
|
// Perform aggregations for each group
|
|
109
109
|
const aggregatedGroupedRows = Array.from(rowGroupsMap.entries()).map(
|
|
@@ -118,7 +118,13 @@ function _createGroupedRowModel<
|
|
|
118
118
|
subRow.parentId = id
|
|
119
119
|
})
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
// Rows produced by groupBy are disjoint members of the pre-grouped
|
|
122
|
+
// row tree, so the duplicate-id guard is unnecessary; flat groups
|
|
123
|
+
// reuse the partition array as-is.
|
|
124
|
+
const leafRows = normalizeUniqueAggregationRows(
|
|
125
|
+
groupedRows,
|
|
126
|
+
Infinity,
|
|
127
|
+
) as Array<Row<TFeatures, TData>>
|
|
122
128
|
|
|
123
129
|
const row = constructRow(
|
|
124
130
|
table,
|
|
@@ -171,6 +177,7 @@ function _createGroupedRowModel<
|
|
|
171
177
|
column,
|
|
172
178
|
groupingRow: row,
|
|
173
179
|
rows: groupedRows,
|
|
180
|
+
uniqueRows: true,
|
|
174
181
|
})
|
|
175
182
|
return cache[colId]
|
|
176
183
|
},
|
|
@@ -203,19 +210,49 @@ function _createGroupedRowModel<
|
|
|
203
210
|
}
|
|
204
211
|
|
|
205
212
|
function groupBy<TFeatures extends TableFeatures, TData extends RowData = any>(
|
|
213
|
+
table: Table_Internal<TFeatures, TData>,
|
|
206
214
|
rows: Array<Row<TFeatures, TData>>,
|
|
207
215
|
columnId: string,
|
|
208
216
|
) {
|
|
209
217
|
const groupMap = new Map<any, Array<Row<TFeatures, TData>>>()
|
|
210
218
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
219
|
+
// Resolve the column once instead of per row: `table.getColumn` goes
|
|
220
|
+
// through the memoized-API dispatcher, which is far too expensive to sit
|
|
221
|
+
// inside this per-row loop. The branches below mirror
|
|
222
|
+
// `row_getGroupingValue`'s caching contract exactly.
|
|
223
|
+
const column = table_getColumn(table, columnId) as
|
|
224
|
+
| Column_Internal<TFeatures, TData, unknown>
|
|
225
|
+
| undefined
|
|
226
|
+
const getGroupingValue = column?.columnDef.getGroupingValue
|
|
227
|
+
|
|
228
|
+
for (let i = 0; i < rows.length; i++) {
|
|
229
|
+
const row = rows[i]!
|
|
230
|
+
let groupingValue
|
|
231
|
+
if (getGroupingValue) {
|
|
232
|
+
const cache = (row as any)._groupingValuesCache as
|
|
233
|
+
| Record<string, unknown>
|
|
234
|
+
| undefined
|
|
235
|
+
if (cache && hasOwn(cache, columnId)) {
|
|
236
|
+
groupingValue = cache[columnId]
|
|
237
|
+
} else if (cache) {
|
|
238
|
+
groupingValue = cache[columnId] = getGroupingValue(
|
|
239
|
+
row.original,
|
|
240
|
+
row.index,
|
|
241
|
+
row,
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
} else {
|
|
245
|
+
groupingValue = row.getValue(columnId)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const resKey = `${groupingValue}`
|
|
249
|
+
const previous = groupMap.get(resKey)
|
|
214
250
|
if (!previous) {
|
|
215
|
-
|
|
251
|
+
groupMap.set(resKey, [row])
|
|
216
252
|
} else {
|
|
217
253
|
previous.push(row)
|
|
218
254
|
}
|
|
219
|
-
|
|
220
|
-
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return groupMap
|
|
221
258
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { constructAggregationFn } from './rowAggregationFeature.types'
|
|
2
|
-
import type { AggregationContext } from './rowAggregationFeature.types'
|
|
3
2
|
|
|
4
3
|
type RangeValue = Date | number
|
|
5
4
|
|
|
@@ -23,19 +22,9 @@ function compareRangeValues(left: RangeValue, right: RangeValue) {
|
|
|
23
22
|
return leftValue - rightValue
|
|
24
23
|
}
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
for (let i = 0; i < context.rows.length; i++) {
|
|
31
|
-
const value = context.getValue(context.rows[i]!)
|
|
32
|
-
const valueKind = getRangeKind(value)
|
|
33
|
-
if (!valueKind) continue
|
|
34
|
-
kind ??= valueKind
|
|
35
|
-
if (valueKind === kind) values.push(value as RangeValue)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return values
|
|
25
|
+
/** Comparable representation of a range value; `Date`s compare by time. */
|
|
26
|
+
function toRangeNumber(value: RangeValue): number {
|
|
27
|
+
return value instanceof Date ? value.getTime() : value
|
|
39
28
|
}
|
|
40
29
|
|
|
41
30
|
/**
|
|
@@ -49,9 +38,10 @@ export const aggregationFn_sum = constructAggregationFn<
|
|
|
49
38
|
number
|
|
50
39
|
>({
|
|
51
40
|
aggregate: (context) => {
|
|
41
|
+
const rows = context.rows
|
|
52
42
|
let sum = 0
|
|
53
|
-
for (let i = 0; i <
|
|
54
|
-
const value = context.getValue(
|
|
43
|
+
for (let i = 0; i < rows.length; i++) {
|
|
44
|
+
const value = context.getValue(rows[i]!)
|
|
55
45
|
sum += typeof value === 'number' ? value : 0
|
|
56
46
|
}
|
|
57
47
|
return sum
|
|
@@ -77,10 +67,23 @@ export const aggregationFn_min = constructAggregationFn<
|
|
|
77
67
|
RangeValue | undefined
|
|
78
68
|
>({
|
|
79
69
|
aggregate: (context) => {
|
|
80
|
-
const
|
|
81
|
-
let
|
|
82
|
-
|
|
83
|
-
|
|
70
|
+
const rows = context.rows
|
|
71
|
+
let kind: 'date' | 'number' | undefined
|
|
72
|
+
let result: RangeValue | undefined
|
|
73
|
+
let resultNumber = 0
|
|
74
|
+
for (let i = 0; i < rows.length; i++) {
|
|
75
|
+
const value = context.getValue(rows[i]!)
|
|
76
|
+
const valueKind = getRangeKind(value)
|
|
77
|
+
if (!valueKind || (kind !== undefined && valueKind !== kind)) continue
|
|
78
|
+
const valueNumber = toRangeNumber(value as RangeValue)
|
|
79
|
+
if (kind === undefined) {
|
|
80
|
+
kind = valueKind
|
|
81
|
+
result = value as RangeValue
|
|
82
|
+
resultNumber = valueNumber
|
|
83
|
+
} else if (valueNumber - resultNumber < 0) {
|
|
84
|
+
result = value as RangeValue
|
|
85
|
+
resultNumber = valueNumber
|
|
86
|
+
}
|
|
84
87
|
}
|
|
85
88
|
return result
|
|
86
89
|
},
|
|
@@ -113,10 +116,23 @@ export const aggregationFn_max = constructAggregationFn<
|
|
|
113
116
|
RangeValue | undefined
|
|
114
117
|
>({
|
|
115
118
|
aggregate: (context) => {
|
|
116
|
-
const
|
|
117
|
-
let
|
|
118
|
-
|
|
119
|
-
|
|
119
|
+
const rows = context.rows
|
|
120
|
+
let kind: 'date' | 'number' | undefined
|
|
121
|
+
let result: RangeValue | undefined
|
|
122
|
+
let resultNumber = 0
|
|
123
|
+
for (let i = 0; i < rows.length; i++) {
|
|
124
|
+
const value = context.getValue(rows[i]!)
|
|
125
|
+
const valueKind = getRangeKind(value)
|
|
126
|
+
if (!valueKind || (kind !== undefined && valueKind !== kind)) continue
|
|
127
|
+
const valueNumber = toRangeNumber(value as RangeValue)
|
|
128
|
+
if (kind === undefined) {
|
|
129
|
+
kind = valueKind
|
|
130
|
+
result = value as RangeValue
|
|
131
|
+
resultNumber = valueNumber
|
|
132
|
+
} else if (valueNumber - resultNumber > 0) {
|
|
133
|
+
result = value as RangeValue
|
|
134
|
+
resultNumber = valueNumber
|
|
135
|
+
}
|
|
120
136
|
}
|
|
121
137
|
return result
|
|
122
138
|
},
|
|
@@ -150,15 +166,33 @@ export const aggregationFn_extent = constructAggregationFn<
|
|
|
150
166
|
[RangeValue | undefined, RangeValue | undefined]
|
|
151
167
|
>({
|
|
152
168
|
aggregate: (context) => {
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
let min
|
|
156
|
-
let max
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
169
|
+
const rows = context.rows
|
|
170
|
+
let kind: 'date' | 'number' | undefined
|
|
171
|
+
let min: RangeValue | undefined
|
|
172
|
+
let max: RangeValue | undefined
|
|
173
|
+
let minNumber = 0
|
|
174
|
+
let maxNumber = 0
|
|
175
|
+
for (let i = 0; i < rows.length; i++) {
|
|
176
|
+
const value = context.getValue(rows[i]!)
|
|
177
|
+
const valueKind = getRangeKind(value)
|
|
178
|
+
if (!valueKind || (kind !== undefined && valueKind !== kind)) continue
|
|
179
|
+
const valueNumber = toRangeNumber(value as RangeValue)
|
|
180
|
+
if (kind === undefined) {
|
|
181
|
+
kind = valueKind
|
|
182
|
+
min = max = value as RangeValue
|
|
183
|
+
minNumber = maxNumber = valueNumber
|
|
184
|
+
} else {
|
|
185
|
+
if (valueNumber - minNumber < 0) {
|
|
186
|
+
min = value as RangeValue
|
|
187
|
+
minNumber = valueNumber
|
|
188
|
+
}
|
|
189
|
+
if (valueNumber - maxNumber > 0) {
|
|
190
|
+
max = value as RangeValue
|
|
191
|
+
maxNumber = valueNumber
|
|
192
|
+
}
|
|
193
|
+
}
|
|
161
194
|
}
|
|
195
|
+
if (kind === undefined) return [undefined, undefined]
|
|
162
196
|
return [min, max]
|
|
163
197
|
},
|
|
164
198
|
merge: ({ subRowResults }) => {
|
|
@@ -205,10 +239,11 @@ export const aggregationFn_mean = constructAggregationFn<
|
|
|
205
239
|
number | undefined
|
|
206
240
|
>({
|
|
207
241
|
aggregate: (context) => {
|
|
242
|
+
const rows = context.rows
|
|
208
243
|
let count = 0
|
|
209
244
|
let sum = 0
|
|
210
|
-
for (let i = 0; i <
|
|
211
|
-
const value = context.getValue(
|
|
245
|
+
for (let i = 0; i < rows.length; i++) {
|
|
246
|
+
const value = context.getValue(rows[i]!)
|
|
212
247
|
if (value == null) continue
|
|
213
248
|
const numberValue = typeof value === 'number' ? value : +value
|
|
214
249
|
if (!Number.isNaN(numberValue)) {
|
|
@@ -231,10 +266,11 @@ export const aggregationFn_median = constructAggregationFn<
|
|
|
231
266
|
number | undefined
|
|
232
267
|
>({
|
|
233
268
|
aggregate: (context) => {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
269
|
+
const rows = context.rows
|
|
270
|
+
if (!rows.length) return undefined
|
|
271
|
+
const values = new Array<number>(rows.length)
|
|
272
|
+
for (let i = 0; i < rows.length; i++) {
|
|
273
|
+
const value = context.getValue(rows[i]!)
|
|
238
274
|
if (typeof value !== 'number') return undefined
|
|
239
275
|
values[i] = value
|
|
240
276
|
}
|
|
@@ -254,9 +290,10 @@ export const aggregationFn_unique = constructAggregationFn<
|
|
|
254
290
|
Array<unknown>
|
|
255
291
|
>({
|
|
256
292
|
aggregate: (context) => {
|
|
293
|
+
const rows = context.rows
|
|
257
294
|
const values = new Set<unknown>()
|
|
258
|
-
for (let i = 0; i <
|
|
259
|
-
values.add(context.getValue(
|
|
295
|
+
for (let i = 0; i < rows.length; i++) {
|
|
296
|
+
values.add(context.getValue(rows[i]!))
|
|
260
297
|
}
|
|
261
298
|
return Array.from(values)
|
|
262
299
|
},
|
|
@@ -270,9 +307,10 @@ export const aggregationFn_uniqueCount = constructAggregationFn<
|
|
|
270
307
|
number
|
|
271
308
|
>({
|
|
272
309
|
aggregate: (context) => {
|
|
310
|
+
const rows = context.rows
|
|
273
311
|
const values = new Set<unknown>()
|
|
274
|
-
for (let i = 0; i <
|
|
275
|
-
values.add(context.getValue(
|
|
312
|
+
for (let i = 0; i < rows.length; i++) {
|
|
313
|
+
values.add(context.getValue(rows[i]!))
|
|
276
314
|
}
|
|
277
315
|
return values.size
|
|
278
316
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { assignPrototypeAPIs
|
|
1
|
+
import { assignPrototypeAPIs } from '../../utils'
|
|
2
2
|
import {
|
|
3
3
|
cell_getIsAggregated,
|
|
4
4
|
column_getAggregationFns,
|
|
@@ -53,8 +53,4 @@ export const rowAggregationFeature: TableFeature = {
|
|
|
53
53
|
;(column as any)._aggregationValueCache = undefined
|
|
54
54
|
;(column as any)._resolvedAggregationFnsCache = undefined
|
|
55
55
|
},
|
|
56
|
-
|
|
57
|
-
initRowInstanceData: (row) => {
|
|
58
|
-
;(row as any)._aggregationValuesCache = makeObjectMap()
|
|
59
|
-
},
|
|
60
56
|
}
|
|
@@ -302,8 +302,8 @@ export interface Cell_Aggregation {
|
|
|
302
302
|
|
|
303
303
|
/** Internal per-row cache used while grouped aggregates are evaluated. */
|
|
304
304
|
export interface Row_Aggregation {
|
|
305
|
-
/** Cached aggregate results keyed by column id. */
|
|
306
|
-
_aggregationValuesCache
|
|
305
|
+
/** Cached aggregate results keyed by column id; created lazily on grouped rows. */
|
|
306
|
+
_aggregationValuesCache?: Record<string, unknown>
|
|
307
307
|
}
|
|
308
308
|
|
|
309
309
|
/** Values passed to a column-level aggregation-value provider. */
|
|
@@ -95,6 +95,52 @@ export function normalizeAggregationRows<
|
|
|
95
95
|
return result
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Frontier selection for rows that are distinct nodes of a single row tree —
|
|
100
|
+
* the row models the table builds itself. Skips `normalizeAggregationRows`'
|
|
101
|
+
* duplicate-id guard (disjoint subtrees cannot revisit a row) and returns
|
|
102
|
+
* `rows` unchanged when no row descends, so the default `maxDepth: 0` case
|
|
103
|
+
* costs nothing per aggregation.
|
|
104
|
+
*/
|
|
105
|
+
export function normalizeUniqueAggregationRows<
|
|
106
|
+
TFeatures extends TableFeatures,
|
|
107
|
+
TData extends RowData,
|
|
108
|
+
>(
|
|
109
|
+
rows: ReadonlyArray<Row<TFeatures, TData>>,
|
|
110
|
+
maxDepth = 0,
|
|
111
|
+
): ReadonlyArray<Row<TFeatures, TData>> {
|
|
112
|
+
const normalizedMaxDepth = resolveMaxAggregationDepth(maxDepth)
|
|
113
|
+
|
|
114
|
+
let needsDescent = false
|
|
115
|
+
if (normalizedMaxDepth > 0) {
|
|
116
|
+
for (let i = 0; i < rows.length; i++) {
|
|
117
|
+
if (rows[i]!.subRows.length) {
|
|
118
|
+
needsDescent = true
|
|
119
|
+
break
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (!needsDescent) return rows
|
|
124
|
+
|
|
125
|
+
const result: Array<Row<TFeatures, TData>> = []
|
|
126
|
+
|
|
127
|
+
const visit = (row: Row<TFeatures, TData>, depth: number) => {
|
|
128
|
+
if (row.subRows.length && depth < normalizedMaxDepth) {
|
|
129
|
+
for (let i = 0; i < row.subRows.length; i++) {
|
|
130
|
+
visit(row.subRows[i]!, depth + 1)
|
|
131
|
+
}
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
result.push(row)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
for (let i = 0; i < rows.length; i++) {
|
|
138
|
+
visit(rows[i]!, 0)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return result
|
|
142
|
+
}
|
|
143
|
+
|
|
98
144
|
function getAutoAggregationFnName(
|
|
99
145
|
value: unknown,
|
|
100
146
|
): 'extent' | 'sum' | undefined {
|
|
@@ -267,13 +313,21 @@ export function aggregateColumnValue<
|
|
|
267
313
|
column: Column<TFeatures, TData, unknown>
|
|
268
314
|
groupingRow?: Row<TFeatures, TData>
|
|
269
315
|
rows: ReadonlyArray<Row<TFeatures, TData>>
|
|
316
|
+
/**
|
|
317
|
+
* Marks `rows` as distinct nodes of a single row tree (rows the table's own
|
|
318
|
+
* row models produced), enabling frontier selection without the
|
|
319
|
+
* duplicate-id guard. Caller-supplied row arrays must omit this.
|
|
320
|
+
*/
|
|
321
|
+
uniqueRows?: boolean
|
|
270
322
|
}): unknown {
|
|
271
|
-
const { subRows, column, groupingRow, rows } = args
|
|
323
|
+
const { subRows, column, groupingRow, rows, uniqueRows } = args
|
|
272
324
|
const internalColumn = column as Column_Internal<TFeatures, TData, unknown>
|
|
273
325
|
const maxDepth = resolveMaxAggregationDepth(
|
|
274
326
|
args.maxDepth ?? internalColumn.columnDef.maxAggregationDepth,
|
|
275
327
|
)
|
|
276
|
-
const aggregationRows =
|
|
328
|
+
const aggregationRows = uniqueRows
|
|
329
|
+
? normalizeUniqueAggregationRows(rows, maxDepth)
|
|
330
|
+
: normalizeAggregationRows(rows, maxDepth)
|
|
277
331
|
const entries = column_getAggregationFns(internalColumn)
|
|
278
332
|
const isMultiple = Array.isArray(internalColumn.columnDef.aggregationFn)
|
|
279
333
|
const canMerge =
|
|
@@ -284,6 +338,8 @@ export function aggregateColumnValue<
|
|
|
284
338
|
(row as any).groupingColumnId !== column.id,
|
|
285
339
|
)
|
|
286
340
|
|
|
341
|
+
const getValue = (row: Row<TFeatures, TData>) => row.getValue(column.id)
|
|
342
|
+
|
|
287
343
|
const execute = (entry: ResolvedAggregationFn<TFeatures, TData>) => {
|
|
288
344
|
const definition = entry.aggregationFn
|
|
289
345
|
if (!definition) return undefined
|
|
@@ -292,7 +348,7 @@ export function aggregateColumnValue<
|
|
|
292
348
|
...(subRows ? { subRows } : {}),
|
|
293
349
|
column,
|
|
294
350
|
columnId: column.id,
|
|
295
|
-
getValue
|
|
351
|
+
getValue,
|
|
296
352
|
...(groupingRow ? { groupingRow } : {}),
|
|
297
353
|
maxDepth,
|
|
298
354
|
rows: aggregationRows,
|
|
@@ -378,6 +434,7 @@ export function column_getAggregationValue<
|
|
|
378
434
|
column: column as any,
|
|
379
435
|
maxDepth: resolvedMaxDepth,
|
|
380
436
|
rows: model.rows,
|
|
437
|
+
uniqueRows: true,
|
|
381
438
|
})
|
|
382
439
|
;(column as any)._aggregationValueCache = {
|
|
383
440
|
aggregationFnOption,
|