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

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 (116) hide show
  1. package/dist/features/column-filtering/columnFilteringFeature.types.d.cts +43 -3
  2. package/dist/features/column-filtering/columnFilteringFeature.types.d.ts +43 -3
  3. package/dist/features/column-filtering/columnFilteringFeature.utils.cjs +18 -9
  4. package/dist/features/column-filtering/columnFilteringFeature.utils.cjs.map +1 -1
  5. package/dist/features/column-filtering/columnFilteringFeature.utils.d.cts +6 -2
  6. package/dist/features/column-filtering/columnFilteringFeature.utils.d.ts +6 -2
  7. package/dist/features/column-filtering/columnFilteringFeature.utils.js +18 -9
  8. package/dist/features/column-filtering/columnFilteringFeature.utils.js.map +1 -1
  9. package/dist/features/column-filtering/createFilteredRowModel.cjs +7 -2
  10. package/dist/features/column-filtering/createFilteredRowModel.cjs.map +1 -1
  11. package/dist/features/column-filtering/createFilteredRowModel.d.cts +6 -2
  12. package/dist/features/column-filtering/createFilteredRowModel.d.ts +6 -2
  13. package/dist/features/column-filtering/createFilteredRowModel.js +7 -2
  14. package/dist/features/column-filtering/createFilteredRowModel.js.map +1 -1
  15. package/dist/features/column-grouping/columnGroupingFeature.types.d.cts +41 -3
  16. package/dist/features/column-grouping/columnGroupingFeature.types.d.ts +41 -3
  17. package/dist/features/column-grouping/columnGroupingFeature.utils.cjs +17 -3
  18. package/dist/features/column-grouping/columnGroupingFeature.utils.cjs.map +1 -1
  19. package/dist/features/column-grouping/columnGroupingFeature.utils.d.cts +5 -0
  20. package/dist/features/column-grouping/columnGroupingFeature.utils.d.ts +5 -0
  21. package/dist/features/column-grouping/columnGroupingFeature.utils.js +17 -3
  22. package/dist/features/column-grouping/columnGroupingFeature.utils.js.map +1 -1
  23. package/dist/features/column-grouping/createGroupedRowModel.cjs +6 -3
  24. package/dist/features/column-grouping/createGroupedRowModel.cjs.map +1 -1
  25. package/dist/features/column-grouping/createGroupedRowModel.d.cts +6 -3
  26. package/dist/features/column-grouping/createGroupedRowModel.d.ts +6 -3
  27. package/dist/features/column-grouping/createGroupedRowModel.js +6 -3
  28. package/dist/features/column-grouping/createGroupedRowModel.js.map +1 -1
  29. package/dist/features/global-filtering/globalFilteringFeature.utils.cjs +3 -1
  30. package/dist/features/global-filtering/globalFilteringFeature.utils.cjs.map +1 -1
  31. package/dist/features/global-filtering/globalFilteringFeature.utils.d.cts +2 -6
  32. package/dist/features/global-filtering/globalFilteringFeature.utils.d.ts +2 -6
  33. package/dist/features/global-filtering/globalFilteringFeature.utils.js +3 -1
  34. package/dist/features/global-filtering/globalFilteringFeature.utils.js.map +1 -1
  35. package/dist/features/row-sorting/createSortedRowModel.cjs +6 -2
  36. package/dist/features/row-sorting/createSortedRowModel.cjs.map +1 -1
  37. package/dist/features/row-sorting/createSortedRowModel.d.cts +6 -2
  38. package/dist/features/row-sorting/createSortedRowModel.d.ts +6 -2
  39. package/dist/features/row-sorting/createSortedRowModel.js +6 -2
  40. package/dist/features/row-sorting/createSortedRowModel.js.map +1 -1
  41. package/dist/features/row-sorting/rowSortingFeature.types.d.cts +31 -2
  42. package/dist/features/row-sorting/rowSortingFeature.types.d.ts +31 -2
  43. package/dist/features/row-sorting/rowSortingFeature.utils.cjs +19 -4
  44. package/dist/features/row-sorting/rowSortingFeature.utils.cjs.map +1 -1
  45. package/dist/features/row-sorting/rowSortingFeature.utils.js +19 -4
  46. package/dist/features/row-sorting/rowSortingFeature.utils.js.map +1 -1
  47. package/dist/fns/aggregationFns.cjs +128 -57
  48. package/dist/fns/aggregationFns.cjs.map +1 -1
  49. package/dist/fns/aggregationFns.d.cts +72 -18
  50. package/dist/fns/aggregationFns.d.ts +72 -18
  51. package/dist/fns/aggregationFns.js +126 -58
  52. package/dist/fns/aggregationFns.js.map +1 -1
  53. package/dist/fns/filterFns.cjs +254 -97
  54. package/dist/fns/filterFns.cjs.map +1 -1
  55. package/dist/fns/filterFns.d.cts +126 -94
  56. package/dist/fns/filterFns.d.ts +126 -94
  57. package/dist/fns/filterFns.js +247 -98
  58. package/dist/fns/filterFns.js.map +1 -1
  59. package/dist/fns/sortFns.cjs +68 -21
  60. package/dist/fns/sortFns.cjs.map +1 -1
  61. package/dist/fns/sortFns.d.cts +48 -15
  62. package/dist/fns/sortFns.d.ts +48 -15
  63. package/dist/fns/sortFns.js +68 -22
  64. package/dist/fns/sortFns.js.map +1 -1
  65. package/dist/helpers/tableFeatures.cjs +5 -4
  66. package/dist/helpers/tableFeatures.cjs.map +1 -1
  67. package/dist/helpers/tableFeatures.d.cts +5 -4
  68. package/dist/helpers/tableFeatures.d.ts +5 -4
  69. package/dist/helpers/tableFeatures.js +5 -4
  70. package/dist/helpers/tableFeatures.js.map +1 -1
  71. package/dist/index.cjs +12 -0
  72. package/dist/index.d.cts +8 -8
  73. package/dist/index.d.ts +8 -8
  74. package/dist/index.js +4 -4
  75. package/dist/types/TableFeatures.d.cts +15 -7
  76. package/dist/types/TableFeatures.d.ts +15 -7
  77. package/dist/types/type-utils.d.cts +8 -1
  78. package/dist/types/type-utils.d.ts +8 -1
  79. package/package.json +1 -1
  80. package/skills/api-not-found/SKILL.md +1 -1
  81. package/skills/client-vs-server/SKILL.md +1 -1
  82. package/skills/column-faceting/SKILL.md +11 -5
  83. package/skills/column-filtering/SKILL.md +8 -3
  84. package/skills/column-ordering/SKILL.md +1 -1
  85. package/skills/column-pinning/SKILL.md +1 -1
  86. package/skills/column-resizing/SKILL.md +1 -1
  87. package/skills/column-sizing/SKILL.md +1 -1
  88. package/skills/column-visibility/SKILL.md +1 -1
  89. package/skills/core/SKILL.md +1 -1
  90. package/skills/custom-features/SKILL.md +1 -1
  91. package/skills/expanding/SKILL.md +1 -1
  92. package/skills/global-filtering/SKILL.md +3 -3
  93. package/skills/grouping/SKILL.md +8 -3
  94. package/skills/migrate-v8-to-v9/SKILL.md +7 -7
  95. package/skills/pagination/SKILL.md +1 -1
  96. package/skills/row-pinning/SKILL.md +1 -1
  97. package/skills/row-selection/SKILL.md +1 -1
  98. package/skills/sorting/SKILL.md +9 -3
  99. package/skills/table-features/SKILL.md +16 -13
  100. package/skills/typescript/SKILL.md +1 -1
  101. package/src/features/column-filtering/columnFilteringFeature.types.ts +60 -0
  102. package/src/features/column-filtering/columnFilteringFeature.utils.ts +33 -19
  103. package/src/features/column-filtering/createFilteredRowModel.ts +13 -3
  104. package/src/features/column-grouping/columnGroupingFeature.types.ts +63 -8
  105. package/src/features/column-grouping/columnGroupingFeature.utils.ts +43 -9
  106. package/src/features/column-grouping/createGroupedRowModel.ts +6 -3
  107. package/src/features/global-filtering/globalFilteringFeature.utils.ts +8 -0
  108. package/src/features/row-sorting/createSortedRowModel.ts +6 -2
  109. package/src/features/row-sorting/rowSortingFeature.types.ts +53 -1
  110. package/src/features/row-sorting/rowSortingFeature.utils.ts +45 -13
  111. package/src/fns/aggregationFns.ts +204 -146
  112. package/src/fns/filterFns.ts +361 -280
  113. package/src/fns/sortFns.ts +95 -78
  114. package/src/helpers/tableFeatures.ts +5 -4
  115. package/src/types/TableFeatures.ts +15 -7
  116. package/src/types/type-utils.ts +8 -0
@@ -1,76 +1,126 @@
1
1
  //#region src/fns/aggregationFns.ts
2
2
  /**
3
+ * Builds an `AggregationFn` from a value-level reducer plus optional
4
+ * `resolveDataValue` and `fromRows` settings.
5
+ *
6
+ * The `aggregate` reducer receives an array of the group rows' values, each
7
+ * already passed through `resolveDataValue` when one is defined. Keeping
8
+ * normalization in the resolver means a variant of an existing aggregation
9
+ * function only has to swap the resolver, not re-implement the computation.
10
+ *
11
+ * The definition is attached to the returned function, so a variant can be
12
+ * created by spreading a built-in aggregation function and overriding what
13
+ * differs. For example, a `min` that works on date columns:
14
+ *
15
+ * ```ts
16
+ * const earliest = constructAggregationFn({
17
+ * ...aggregationFn_min,
18
+ * resolveDataValue: (value) =>
19
+ * value instanceof Date ? value.getTime() : value,
20
+ * })
21
+ * ```
22
+ *
23
+ * The built-in `count`, `first`, and `last` aggregation functions are plain
24
+ * row-level functions instead: they read group position or size and never
25
+ * look at every value, so materializing a values array would be wasted work.
26
+ */
27
+ function constructAggregationFn(def) {
28
+ const aggregationFn = Object.assign((columnId, leafRows, childRows) => {
29
+ const rows = aggregationFn.fromRows === "childRows" ? childRows : leafRows;
30
+ const resolveDataValue = aggregationFn.resolveDataValue;
31
+ const values = new Array(rows.length);
32
+ for (let i = 0; i < rows.length; i++) {
33
+ const value = rows[i].getValue(columnId);
34
+ values[i] = resolveDataValue ? resolveDataValue(value) : value;
35
+ }
36
+ return aggregationFn.aggregate(values, rows, columnId);
37
+ }, def);
38
+ return aggregationFn;
39
+ }
40
+ /**
3
41
  * Sums numeric child-row values for a grouped column.
4
42
  *
5
43
  * Non-number values contribute `0`. Child rows are used so nested group totals
6
44
  * can reuse already aggregated values.
7
45
  */
8
- function aggregationFn_sum(columnId, _leafRows, childRows) {
9
- let sumValue = 0;
10
- for (let i = 0; i < childRows.length; i++) {
11
- const nextValue = childRows[i].getValue(columnId);
12
- sumValue += typeof nextValue === "number" ? nextValue : 0;
46
+ const aggregationFn_sum = constructAggregationFn({
47
+ fromRows: "childRows",
48
+ aggregate: (values) => {
49
+ let sumValue = 0;
50
+ for (let i = 0; i < values.length; i++) {
51
+ const nextValue = values[i];
52
+ sumValue += typeof nextValue === "number" ? nextValue : 0;
53
+ }
54
+ return sumValue;
13
55
  }
14
- return sumValue;
15
- }
56
+ });
16
57
  /**
17
58
  * Finds the minimum numeric child-row value for a grouped column.
18
59
  *
19
60
  * Nullish and non-number values are ignored. Returns `undefined` when no
20
61
  * numeric value is found.
21
62
  */
22
- function aggregationFn_min(columnId, _leafRows, childRows) {
23
- let minValue;
24
- for (let i = 0; i < childRows.length; i++) {
25
- const value = childRows[i].getValue(columnId);
26
- if (typeof value === "number" && (minValue === void 0 || value < minValue)) minValue = value;
63
+ const aggregationFn_min = constructAggregationFn({
64
+ fromRows: "childRows",
65
+ aggregate: (values) => {
66
+ let minValue;
67
+ for (let i = 0; i < values.length; i++) {
68
+ const value = values[i];
69
+ if (typeof value === "number" && (minValue === void 0 || value < minValue)) minValue = value;
70
+ }
71
+ return minValue;
27
72
  }
28
- return minValue;
29
- }
73
+ });
30
74
  /**
31
75
  * Finds the maximum numeric child-row value for a grouped column.
32
76
  *
33
77
  * Nullish and non-number values are ignored. Returns `undefined` when no
34
78
  * numeric value is found.
35
79
  */
36
- function aggregationFn_max(columnId, _leafRows, childRows) {
37
- let maxValue;
38
- for (let i = 0; i < childRows.length; i++) {
39
- const value = childRows[i].getValue(columnId);
40
- if (typeof value === "number" && (maxValue === void 0 || value > maxValue)) maxValue = value;
80
+ const aggregationFn_max = constructAggregationFn({
81
+ fromRows: "childRows",
82
+ aggregate: (values) => {
83
+ let maxValue;
84
+ for (let i = 0; i < values.length; i++) {
85
+ const value = values[i];
86
+ if (typeof value === "number" && (maxValue === void 0 || value > maxValue)) maxValue = value;
87
+ }
88
+ return maxValue;
41
89
  }
42
- return maxValue;
43
- }
90
+ });
44
91
  /**
45
92
  * Finds the numeric extent for a grouped column.
46
93
  *
47
94
  * Returns `[min, max]`, where each entry is `undefined` when no numeric value is
48
95
  * present.
49
96
  */
50
- function aggregationFn_extent(columnId, _leafRows, childRows) {
51
- let minValue;
52
- let maxValue;
53
- for (let i = 0; i < childRows.length; i++) {
54
- const value = childRows[i].getValue(columnId);
55
- if (typeof value === "number") if (minValue === void 0) minValue = maxValue = value;
56
- else {
57
- if (minValue > value) minValue = value;
58
- if (maxValue < value) maxValue = value;
97
+ const aggregationFn_extent = constructAggregationFn({
98
+ fromRows: "childRows",
99
+ aggregate: (values) => {
100
+ let minValue;
101
+ let maxValue;
102
+ for (let i = 0; i < values.length; i++) {
103
+ const value = values[i];
104
+ if (typeof value === "number") if (minValue === void 0) minValue = maxValue = value;
105
+ else {
106
+ if (minValue > value) minValue = value;
107
+ if (maxValue < value) maxValue = value;
108
+ }
59
109
  }
110
+ return [minValue, maxValue];
60
111
  }
61
- return [minValue, maxValue];
62
- }
112
+ });
63
113
  /**
64
114
  * Averages numeric leaf-row values for a grouped column.
65
115
  *
66
116
  * Number-like values are coerced with unary `+`; nullish and non-numeric values
67
117
  * are ignored.
68
118
  */
69
- function aggregationFn_mean(columnId, leafRows) {
119
+ const aggregationFn_mean = constructAggregationFn({ aggregate: (values) => {
70
120
  let count = 0;
71
121
  let sumValue = 0;
72
- for (let i = 0; i < leafRows.length; i++) {
73
- const value = leafRows[i].getValue(columnId);
122
+ for (let i = 0; i < values.length; i++) {
123
+ const value = values[i];
74
124
  if (value != null && typeof value === "number") {
75
125
  ++count;
76
126
  sumValue += value;
@@ -83,58 +133,74 @@ function aggregationFn_mean(columnId, leafRows) {
83
133
  }
84
134
  }
85
135
  if (count) return sumValue / count;
86
- }
136
+ } });
87
137
  /**
88
138
  * Computes the median of numeric leaf-row values for a grouped column.
89
139
  *
90
140
  * All values must be numbers. If any value is non-numeric, or no leaf rows are
91
141
  * present, the result is `undefined`.
92
142
  */
93
- function aggregationFn_median(columnId, leafRows) {
94
- if (!leafRows.length) return;
95
- const values = new Array(leafRows.length);
96
- for (let i = 0; i < leafRows.length; i++) {
97
- const v = leafRows[i].getValue(columnId);
98
- if (typeof v !== "number") return;
99
- values[i] = v;
100
- }
143
+ const aggregationFn_median = constructAggregationFn({ aggregate: (values) => {
144
+ if (!values.length) return;
145
+ for (let i = 0; i < values.length; i++) if (typeof values[i] !== "number") return;
101
146
  if (values.length === 1) return values[0];
102
147
  const mid = Math.floor(values.length / 2);
103
148
  values.sort((a, b) => a - b);
104
149
  return values.length % 2 !== 0 ? values[mid] : (values[mid - 1] + values[mid]) / 2;
105
- }
150
+ } });
106
151
  /**
107
152
  * Collects unique leaf-row values for a grouped column.
108
153
  *
109
154
  * Values are compared with JavaScript `Set` semantics.
110
155
  */
111
- function aggregationFn_unique(columnId, leafRows) {
112
- const set = /* @__PURE__ */ new Set();
113
- for (let i = 0; i < leafRows.length; i++) set.add(leafRows[i].getValue(columnId));
114
- return Array.from(set.values());
115
- }
156
+ const aggregationFn_unique = constructAggregationFn({ aggregate: (values) => Array.from(new Set(values).values()) });
116
157
  /**
117
158
  * Counts unique leaf-row values for a grouped column.
118
159
  *
119
160
  * Values are compared with JavaScript `Set` semantics.
120
161
  */
121
- function aggregationFn_uniqueCount(columnId, leafRows) {
122
- const set = /* @__PURE__ */ new Set();
123
- for (let i = 0; i < leafRows.length; i++) set.add(leafRows[i].getValue(columnId));
124
- return set.size;
125
- }
162
+ const aggregationFn_uniqueCount = constructAggregationFn({ aggregate: (values) => new Set(values).size });
126
163
  /**
127
164
  * Counts the number of leaf rows in the group.
128
165
  *
129
166
  * The column id is ignored because the result is based only on group size.
167
+ * This is a plain row-level function (not built with
168
+ * `constructAggregationFn`) because it never reads row values.
130
169
  */
131
170
  function aggregationFn_count(_columnId, leafRows) {
132
171
  return leafRows.length;
133
172
  }
134
173
  /**
174
+ * Returns the first leaf-row value for a grouped column.
175
+ *
176
+ * This is a plain row-level function (not built with
177
+ * `constructAggregationFn`) because it only reads one positional value.
178
+ */
179
+ function aggregationFn_first(columnId, leafRows) {
180
+ return leafRows[0]?.getValue(columnId);
181
+ }
182
+ /**
183
+ * Returns the last leaf-row value for a grouped column.
184
+ *
185
+ * This is a plain row-level function (not built with
186
+ * `constructAggregationFn`) because it only reads one positional value.
187
+ */
188
+ function aggregationFn_last(columnId, leafRows) {
189
+ return leafRows[leafRows.length - 1]?.getValue(columnId);
190
+ }
191
+ /**
135
192
  * The built-in aggregation function registry.
136
193
  *
137
- * Pass this object to grouped row model creation or extend it with custom aggregation functions for grouped columns.
194
+ * Registering this full object opts out of tree-shaking: every built-in
195
+ * aggregation function ends up in your bundle. Prefer importing the
196
+ * `aggregationFn_*` functions you actually use and registering just those in
197
+ * the `aggregationFns` slot, or passing them directly to the `aggregationFn`
198
+ * column option.
199
+ *
200
+ * @deprecated Import individual `aggregationFn_*` functions instead for a
201
+ * smaller bundle. This export still works and is not going away in v9, but
202
+ * built-in name resolution (including `aggregationFn: 'auto'`) only finds
203
+ * functions you register yourself.
138
204
  */
139
205
  const aggregationFns = {
140
206
  sum: aggregationFn_sum,
@@ -145,9 +211,11 @@ const aggregationFns = {
145
211
  median: aggregationFn_median,
146
212
  unique: aggregationFn_unique,
147
213
  uniqueCount: aggregationFn_uniqueCount,
148
- count: aggregationFn_count
214
+ count: aggregationFn_count,
215
+ first: aggregationFn_first,
216
+ last: aggregationFn_last
149
217
  };
150
218
 
151
219
  //#endregion
152
- export { aggregationFn_count, aggregationFn_extent, aggregationFn_max, aggregationFn_mean, aggregationFn_median, aggregationFn_min, aggregationFn_sum, aggregationFn_unique, aggregationFn_uniqueCount, aggregationFns };
220
+ export { aggregationFn_count, aggregationFn_extent, aggregationFn_first, aggregationFn_last, aggregationFn_max, aggregationFn_mean, aggregationFn_median, aggregationFn_min, aggregationFn_sum, aggregationFn_unique, aggregationFn_uniqueCount, aggregationFns, constructAggregationFn };
153
221
  //# sourceMappingURL=aggregationFns.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"aggregationFns.js","names":[],"sources":["../../src/fns/aggregationFns.ts"],"sourcesContent":["import type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { Row } from '../types/Row'\n\n/**\n * Sums numeric child-row values for a grouped column.\n *\n * Non-number values contribute `0`. Child rows are used so nested group totals\n * can reuse already aggregated values.\n */\nexport function aggregationFn_sum<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n columnId: string,\n _leafRows: Array<Row<TFeatures, TData>>,\n childRows: Array<Row<TFeatures, TData>>,\n) {\n // It's faster to just add the aggregations together instead of\n // process leaf nodes individually\n let sumValue = 0\n for (let i = 0; i < childRows.length; i++) {\n const nextValue = childRows[i]!.getValue(columnId)\n sumValue += typeof nextValue === 'number' ? nextValue : 0\n }\n return sumValue\n}\n\n/**\n * Finds the minimum numeric child-row value for a grouped column.\n *\n * Nullish and non-number values are ignored. Returns `undefined` when no\n * numeric value is found.\n */\nexport function aggregationFn_min<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n columnId: string,\n _leafRows: Array<Row<TFeatures, TData>>,\n childRows: Array<Row<TFeatures, TData>>,\n) {\n let minValue: number | undefined\n\n for (let i = 0; i < childRows.length; i++) {\n const value = childRows[i]!.getValue(columnId)\n\n if (\n typeof value === 'number' &&\n (minValue === undefined || value < minValue)\n ) {\n minValue = value\n }\n }\n\n return minValue\n}\n\n/**\n * Finds the maximum numeric child-row value for a grouped column.\n *\n * Nullish and non-number values are ignored. Returns `undefined` when no\n * numeric value is found.\n */\nexport function aggregationFn_max<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n columnId: string,\n _leafRows: Array<Row<TFeatures, TData>>,\n childRows: Array<Row<TFeatures, TData>>,\n) {\n let maxValue: number | undefined\n\n for (let i = 0; i < childRows.length; i++) {\n const value = childRows[i]!.getValue(columnId)\n if (\n typeof value === 'number' &&\n (maxValue === undefined || value > maxValue)\n ) {\n maxValue = value\n }\n }\n\n return maxValue\n}\n\n/**\n * Finds the numeric extent for a grouped column.\n *\n * Returns `[min, max]`, where each entry is `undefined` when no numeric value is\n * present.\n */\nexport function aggregationFn_extent<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n columnId: string,\n _leafRows: Array<Row<TFeatures, TData>>,\n childRows: Array<Row<TFeatures, TData>>,\n) {\n let minValue: number | undefined\n let maxValue: number | undefined\n\n for (let i = 0; i < childRows.length; i++) {\n const value = childRows[i]!.getValue(columnId)\n if (typeof value === 'number') {\n if (minValue === undefined) {\n minValue = maxValue = value\n } else {\n if (minValue > value) minValue = value\n if (maxValue! < value) maxValue = value\n }\n }\n }\n\n return [minValue, maxValue]\n}\n\n/**\n * Averages numeric leaf-row values for a grouped column.\n *\n * Number-like values are coerced with unary `+`; nullish and non-numeric values\n * are ignored.\n */\nexport function aggregationFn_mean<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(columnId: string, leafRows: Array<Row<TFeatures, TData>>) {\n let count = 0\n let sumValue = 0\n\n for (let i = 0; i < leafRows.length; i++) {\n const value = leafRows[i]!.getValue(columnId)\n if (value != null && typeof value === 'number') {\n ++count\n sumValue += value\n } else if (value != null) {\n const numValue = +value\n if (!Number.isNaN(numValue)) {\n ++count\n sumValue += numValue\n }\n }\n }\n\n if (count) return sumValue / count\n\n return\n}\n\n/**\n * Computes the median of numeric leaf-row values for a grouped column.\n *\n * All values must be numbers. If any value is non-numeric, or no leaf rows are\n * present, the result is `undefined`.\n */\nexport function aggregationFn_median<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(columnId: string, leafRows: Array<Row<TFeatures, TData>>) {\n if (!leafRows.length) {\n return\n }\n\n const values: Array<number> = new Array(leafRows.length)\n for (let i = 0; i < leafRows.length; i++) {\n const v = leafRows[i]!.getValue(columnId)\n if (typeof v !== 'number') return\n values[i] = v\n }\n\n if (values.length === 1) {\n return values[0]\n }\n\n const mid = Math.floor(values.length / 2)\n values.sort((a, b) => a - b)\n return values.length % 2 !== 0\n ? values[mid]\n : (values[mid - 1]! + values[mid]!) / 2\n}\n\n/**\n * Collects unique leaf-row values for a grouped column.\n *\n * Values are compared with JavaScript `Set` semantics.\n */\nexport function aggregationFn_unique<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(columnId: string, leafRows: Array<Row<TFeatures, TData>>) {\n const set = new Set<unknown>()\n for (let i = 0; i < leafRows.length; i++) {\n set.add(leafRows[i]!.getValue(columnId))\n }\n return Array.from(set.values())\n}\n\n/**\n * Counts unique leaf-row values for a grouped column.\n *\n * Values are compared with JavaScript `Set` semantics.\n */\nexport function aggregationFn_uniqueCount<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(columnId: string, leafRows: Array<Row<TFeatures, TData>>) {\n const set = new Set<unknown>()\n for (let i = 0; i < leafRows.length; i++) {\n set.add(leafRows[i]!.getValue(columnId))\n }\n return set.size\n}\n\n/**\n * Counts the number of leaf rows in the group.\n *\n * The column id is ignored because the result is based only on group size.\n */\nexport function aggregationFn_count<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(_columnId: string, leafRows: Array<Row<TFeatures, TData>>) {\n return leafRows.length\n}\n\n/**\n * The built-in aggregation function registry.\n *\n * Pass this object to grouped row model creation or extend it with custom aggregation functions for grouped columns.\n */\nexport const aggregationFns = {\n sum: aggregationFn_sum,\n min: aggregationFn_min,\n max: aggregationFn_max,\n extent: aggregationFn_extent,\n mean: aggregationFn_mean,\n median: aggregationFn_median,\n unique: aggregationFn_unique,\n uniqueCount: aggregationFn_uniqueCount,\n count: aggregationFn_count,\n}\n\nexport type BuiltInAggregationFn = keyof typeof aggregationFns\n"],"mappings":"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"}
1
+ {"version":3,"file":"aggregationFns.js","names":[],"sources":["../../src/fns/aggregationFns.ts"],"sourcesContent":["import type {\n AggregationFnDef,\n CreatedAggregationFn,\n} from '../features/column-grouping/columnGroupingFeature.types'\nimport type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { Row } from '../types/Row'\n\n/**\n * Builds an `AggregationFn` from a value-level reducer plus optional\n * `resolveDataValue` and `fromRows` settings.\n *\n * The `aggregate` reducer receives an array of the group rows' values, each\n * already passed through `resolveDataValue` when one is defined. Keeping\n * normalization in the resolver means a variant of an existing aggregation\n * function only has to swap the resolver, not re-implement the computation.\n *\n * The definition is attached to the returned function, so a variant can be\n * created by spreading a built-in aggregation function and overriding what\n * differs. For example, a `min` that works on date columns:\n *\n * ```ts\n * const earliest = constructAggregationFn({\n * ...aggregationFn_min,\n * resolveDataValue: (value) =>\n * value instanceof Date ? value.getTime() : value,\n * })\n * ```\n *\n * The built-in `count`, `first`, and `last` aggregation functions are plain\n * row-level functions instead: they read group position or size and never\n * look at every value, so materializing a values array would be wasted work.\n */\nexport function constructAggregationFn<\n TFeatures extends TableFeatures = any,\n TData extends RowData = any,\n>(\n def: AggregationFnDef<TFeatures, TData>,\n): CreatedAggregationFn<TFeatures, TData> {\n const aggregationFn: CreatedAggregationFn<TFeatures, TData> = Object.assign(\n <TRowFeatures extends TableFeatures, TRowData extends RowData>(\n columnId: string,\n leafRows: Array<Row<TRowFeatures, TRowData>>,\n childRows: Array<Row<TRowFeatures, TRowData>>,\n ): any => {\n const rows = aggregationFn.fromRows === 'childRows' ? childRows : leafRows\n const resolveDataValue = aggregationFn.resolveDataValue\n const values: Array<any> = new Array(rows.length)\n for (let i = 0; i < rows.length; i++) {\n const value = rows[i]!.getValue(columnId)\n values[i] = resolveDataValue ? resolveDataValue(value) : value\n }\n // The def's reducer is typed against the factory's TFeatures/TData;\n // the caller's row generics are erased at this boundary.\n return aggregationFn.aggregate(values, rows as any, columnId)\n },\n def,\n )\n return aggregationFn\n}\n\n/**\n * Sums numeric child-row values for a grouped column.\n *\n * Non-number values contribute `0`. Child rows are used so nested group totals\n * can reuse already aggregated values.\n */\nexport const aggregationFn_sum = constructAggregationFn({\n fromRows: 'childRows',\n aggregate: (values) => {\n let sumValue = 0\n for (let i = 0; i < values.length; i++) {\n const nextValue = values[i]\n sumValue += typeof nextValue === 'number' ? nextValue : 0\n }\n return sumValue\n },\n})\n\n/**\n * Finds the minimum numeric child-row value for a grouped column.\n *\n * Nullish and non-number values are ignored. Returns `undefined` when no\n * numeric value is found.\n */\nexport const aggregationFn_min = constructAggregationFn({\n fromRows: 'childRows',\n aggregate: (values) => {\n let minValue: number | undefined\n\n for (let i = 0; i < values.length; i++) {\n const value = values[i]\n if (\n typeof value === 'number' &&\n (minValue === undefined || value < minValue)\n ) {\n minValue = value\n }\n }\n\n return minValue\n },\n})\n\n/**\n * Finds the maximum numeric child-row value for a grouped column.\n *\n * Nullish and non-number values are ignored. Returns `undefined` when no\n * numeric value is found.\n */\nexport const aggregationFn_max = constructAggregationFn({\n fromRows: 'childRows',\n aggregate: (values) => {\n let maxValue: number | undefined\n\n for (let i = 0; i < values.length; i++) {\n const value = values[i]\n if (\n typeof value === 'number' &&\n (maxValue === undefined || value > maxValue)\n ) {\n maxValue = value\n }\n }\n\n return maxValue\n },\n})\n\n/**\n * Finds the numeric extent for a grouped column.\n *\n * Returns `[min, max]`, where each entry is `undefined` when no numeric value is\n * present.\n */\nexport const aggregationFn_extent = constructAggregationFn({\n fromRows: 'childRows',\n aggregate: (values) => {\n let minValue: number | undefined\n let maxValue: number | undefined\n\n for (let i = 0; i < values.length; i++) {\n const value = values[i]\n if (typeof value === 'number') {\n if (minValue === undefined) {\n minValue = maxValue = value\n } else {\n if (minValue > value) minValue = value\n if (maxValue! < value) maxValue = value\n }\n }\n }\n\n return [minValue, maxValue]\n },\n})\n\n/**\n * Averages numeric leaf-row values for a grouped column.\n *\n * Number-like values are coerced with unary `+`; nullish and non-numeric values\n * are ignored.\n */\nexport const aggregationFn_mean = constructAggregationFn({\n aggregate: (values) => {\n let count = 0\n let sumValue = 0\n\n for (let i = 0; i < values.length; i++) {\n const value = values[i]\n if (value != null && typeof value === 'number') {\n ++count\n sumValue += value\n } else if (value != null) {\n const numValue = +value\n if (!Number.isNaN(numValue)) {\n ++count\n sumValue += numValue\n }\n }\n }\n\n if (count) return sumValue / count\n\n return\n },\n})\n\n/**\n * Computes the median of numeric leaf-row values for a grouped column.\n *\n * All values must be numbers. If any value is non-numeric, or no leaf rows are\n * present, the result is `undefined`.\n */\nexport const aggregationFn_median = constructAggregationFn({\n aggregate: (values: Array<number>) => {\n if (!values.length) {\n return\n }\n\n for (let i = 0; i < values.length; i++) {\n if (typeof values[i] !== 'number') return\n }\n\n if (values.length === 1) {\n return values[0]\n }\n\n const mid = Math.floor(values.length / 2)\n values.sort((a, b) => a - b)\n return values.length % 2 !== 0\n ? values[mid]\n : (values[mid - 1]! + values[mid]!) / 2\n },\n})\n\n/**\n * Collects unique leaf-row values for a grouped column.\n *\n * Values are compared with JavaScript `Set` semantics.\n */\nexport const aggregationFn_unique = constructAggregationFn({\n aggregate: (values) => Array.from(new Set(values).values()),\n})\n\n/**\n * Counts unique leaf-row values for a grouped column.\n *\n * Values are compared with JavaScript `Set` semantics.\n */\nexport const aggregationFn_uniqueCount = constructAggregationFn({\n aggregate: (values) => new Set(values).size,\n})\n\n/**\n * Counts the number of leaf rows in the group.\n *\n * The column id is ignored because the result is based only on group size.\n * This is a plain row-level function (not built with\n * `constructAggregationFn`) because it never reads row values.\n */\nexport function aggregationFn_count<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(_columnId: string, leafRows: Array<Row<TFeatures, TData>>) {\n return leafRows.length\n}\n\n/**\n * Returns the first leaf-row value for a grouped column.\n *\n * This is a plain row-level function (not built with\n * `constructAggregationFn`) because it only reads one positional value.\n */\nexport function aggregationFn_first<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(columnId: string, leafRows: Array<Row<TFeatures, TData>>) {\n return leafRows[0]?.getValue(columnId)\n}\n\n/**\n * Returns the last leaf-row value for a grouped column.\n *\n * This is a plain row-level function (not built with\n * `constructAggregationFn`) because it only reads one positional value.\n */\nexport function aggregationFn_last<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(columnId: string, leafRows: Array<Row<TFeatures, TData>>) {\n return leafRows[leafRows.length - 1]?.getValue(columnId)\n}\n\n/**\n * The built-in aggregation function registry.\n *\n * Registering this full object opts out of tree-shaking: every built-in\n * aggregation function ends up in your bundle. Prefer importing the\n * `aggregationFn_*` functions you actually use and registering just those in\n * the `aggregationFns` slot, or passing them directly to the `aggregationFn`\n * column option.\n *\n * @deprecated Import individual `aggregationFn_*` functions instead for a\n * smaller bundle. This export still works and is not going away in v9, but\n * built-in name resolution (including `aggregationFn: 'auto'`) only finds\n * functions you register yourself.\n */\nexport const aggregationFns = {\n sum: aggregationFn_sum,\n min: aggregationFn_min,\n max: aggregationFn_max,\n extent: aggregationFn_extent,\n mean: aggregationFn_mean,\n median: aggregationFn_median,\n unique: aggregationFn_unique,\n uniqueCount: aggregationFn_uniqueCount,\n count: aggregationFn_count,\n first: aggregationFn_first,\n last: aggregationFn_last,\n}\n\nexport type BuiltInAggregationFn = keyof typeof aggregationFns\n"],"mappings":"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"}