@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
|
@@ -3,7 +3,6 @@ const require_coreColumnsFeature_utils = require('../../core/columns/coreColumns
|
|
|
3
3
|
const require_constructRow = require('../../core/rows/constructRow.cjs');
|
|
4
4
|
const require_rowPaginationFeature_utils = require('../row-pagination/rowPaginationFeature.utils.cjs');
|
|
5
5
|
const require_rowAggregationFeature_utils = require('../row-aggregation/rowAggregationFeature.utils.cjs');
|
|
6
|
-
const require_columnGroupingFeature_utils = require('./columnGroupingFeature.utils.cjs');
|
|
7
6
|
const require_rowExpandingFeature_utils = require('../row-expanding/rowExpandingFeature.utils.cjs');
|
|
8
7
|
|
|
9
8
|
//#region src/features/column-grouping/createGroupedRowModel.ts
|
|
@@ -62,7 +61,7 @@ function _createGroupedRowModel(table) {
|
|
|
62
61
|
return row;
|
|
63
62
|
});
|
|
64
63
|
const columnId = existingGrouping[depth];
|
|
65
|
-
const rowGroupsMap = groupBy(rows, columnId);
|
|
64
|
+
const rowGroupsMap = groupBy(table, rows, columnId);
|
|
66
65
|
return Array.from(rowGroupsMap.entries()).map(([groupingValue, groupedRows], index) => {
|
|
67
66
|
let id = `${columnId}:${groupingValue}`;
|
|
68
67
|
id = parentId ? `${parentId}>${id}` : id;
|
|
@@ -70,7 +69,7 @@ function _createGroupedRowModel(table) {
|
|
|
70
69
|
subRows.forEach((subRow) => {
|
|
71
70
|
subRow.parentId = id;
|
|
72
71
|
});
|
|
73
|
-
const leafRows = require_rowAggregationFeature_utils.
|
|
72
|
+
const leafRows = require_rowAggregationFeature_utils.normalizeUniqueAggregationRows(groupedRows, Infinity);
|
|
74
73
|
const row = require_constructRow.constructRow(table, id, leafRows[0].original, index, depth, void 0, parentId);
|
|
75
74
|
Object.assign(row, {
|
|
76
75
|
groupingColumnId: columnId,
|
|
@@ -93,7 +92,8 @@ function _createGroupedRowModel(table) {
|
|
|
93
92
|
subRows,
|
|
94
93
|
column,
|
|
95
94
|
groupingRow: row,
|
|
96
|
-
rows: groupedRows
|
|
95
|
+
rows: groupedRows,
|
|
96
|
+
uniqueRows: true
|
|
97
97
|
});
|
|
98
98
|
return cache[colId];
|
|
99
99
|
}
|
|
@@ -116,15 +116,23 @@ function _createGroupedRowModel(table) {
|
|
|
116
116
|
rowsById: groupedRowsById
|
|
117
117
|
};
|
|
118
118
|
}
|
|
119
|
-
function groupBy(rows, columnId) {
|
|
119
|
+
function groupBy(table, rows, columnId) {
|
|
120
120
|
const groupMap = /* @__PURE__ */ new Map();
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
|
|
121
|
+
const getGroupingValue = require_coreColumnsFeature_utils.table_getColumn(table, columnId)?.columnDef.getGroupingValue;
|
|
122
|
+
for (let i = 0; i < rows.length; i++) {
|
|
123
|
+
const row = rows[i];
|
|
124
|
+
let groupingValue;
|
|
125
|
+
if (getGroupingValue) {
|
|
126
|
+
const cache = row._groupingValuesCache;
|
|
127
|
+
if (cache && require_utils.hasOwn(cache, columnId)) groupingValue = cache[columnId];
|
|
128
|
+
else if (cache) groupingValue = cache[columnId] = getGroupingValue(row.original, row.index, row);
|
|
129
|
+
} else groupingValue = row.getValue(columnId);
|
|
130
|
+
const resKey = `${groupingValue}`;
|
|
131
|
+
const previous = groupMap.get(resKey);
|
|
132
|
+
if (!previous) groupMap.set(resKey, [row]);
|
|
125
133
|
else previous.push(row);
|
|
126
|
-
|
|
127
|
-
|
|
134
|
+
}
|
|
135
|
+
return groupMap;
|
|
128
136
|
}
|
|
129
137
|
|
|
130
138
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createGroupedRowModel.cjs","names":["tableMemo","table_getColumn","makeObjectMap","normalizeAggregationRows","constructRow","hasOwn","aggregateColumnValue","row_getGroupingValue"],"sources":["../../../src/features/column-grouping/createGroupedRowModel.ts"],"sourcesContent":["import { hasOwn, makeObjectMap, tableMemo } from '../../utils'\nimport { constructRow } from '../../core/rows/constructRow'\nimport { table_getColumn } from '../../core/columns/coreColumnsFeature.utils'\nimport { table_autoResetExpanded } from '../row-expanding/rowExpandingFeature.utils'\nimport { table_autoResetPageIndex } from '../row-pagination/rowPaginationFeature.utils'\nimport {\n aggregateColumnValue,\n normalizeAggregationRows,\n} from '../row-aggregation/rowAggregationFeature.utils'\nimport { row_getGroupingValue } from './columnGroupingFeature.utils'\nimport type { Row_ColumnGrouping } from './columnGroupingFeature.types'\nimport type { TableFeatures } from '../../types/TableFeatures'\nimport type { RowModel } from '../../core/row-models/coreRowModelsFeature.types'\nimport type { Table, Table_Internal } from '../../types/Table'\nimport type { Row } from '../../types/Row'\nimport type { RowData } from '../../types/type-utils'\n\n/**\n * Creates a memoized grouped row model factory.\n *\n * The factory reads the relevant table state atoms and options, then returns a row model function used by the table row-model pipeline.\n *\n * When rowAggregationFeature is also registered, grouped rows use its shared\n * executor for non-group values. Grouping remains useful without aggregation.\n */\nexport function createGroupedRowModel<\n TFeatures extends TableFeatures,\n TData extends RowData = any,\n>(): (table: Table<TFeatures, TData>) => () => RowModel<TFeatures, TData> {\n return (_table) => {\n const table = _table as unknown as Table_Internal<TFeatures, TData>\n return tableMemo({\n feature: 'columnGroupingFeature',\n table,\n fnName: 'table.getGroupedRowModel',\n memoDeps: () => [\n table.atoms.grouping?.get(),\n table.getPreGroupedRowModel(),\n table.options.columns,\n ],\n fn: () => _createGroupedRowModel(table),\n onAfterUpdate: () => {\n table_autoResetExpanded(table)\n table_autoResetPageIndex(table)\n },\n })\n }\n}\n\nfunction _createGroupedRowModel<\n TFeatures extends TableFeatures,\n TData extends RowData = any,\n>(table: Table_Internal<TFeatures, TData>): RowModel<TFeatures, TData> {\n const rowModel = table.getPreGroupedRowModel()\n const grouping = table.atoms.grouping?.get()\n\n if (!rowModel.rows.length || !grouping?.length) {\n rowModel.rows.forEach((row) => {\n row.depth = 0\n row.parentId = undefined\n })\n return rowModel\n }\n\n // Filter the grouping list down to columns that exist\n const existingGrouping = grouping.filter((columnId) =>\n table_getColumn(table, columnId),\n )\n\n const groupedFlatRows: Array<Row<TFeatures, TData>> &\n Partial<Row_ColumnGrouping> = []\n const groupedRowsById = makeObjectMap<Row<TFeatures, TData>>()\n\n // Recursively group the data\n const groupUpRecursively = (\n rows: Array<Row<TFeatures, TData>>,\n depth = 0,\n parentId?: string,\n ) => {\n // Grouping depth has been been met\n // Stop grouping and simply rewrite thd depth and row relationships\n if (depth >= existingGrouping.length) {\n return rows.map((row) => {\n row.depth = depth\n\n // Every row is pushed into flatRows/rowsById exactly once, by its\n // parent frame: rows returned here are pushed by the caller (the\n // parent group's loop or the root loop), so only descendants below\n // the terminal depth are pushed here.\n if (row.subRows.length) {\n row.subRows = groupUpRecursively(row.subRows, depth + 1, row.id)\n for (let i = 0; i < row.subRows.length; i++) {\n const subRow = row.subRows[i]!\n groupedFlatRows.push(subRow)\n groupedRowsById[subRow.id] = subRow\n }\n }\n\n return row\n })\n }\n\n const columnId = existingGrouping[depth] as string\n\n // Group the rows together for this level\n const rowGroupsMap = groupBy(rows, columnId)\n\n // Perform aggregations for each group\n const aggregatedGroupedRows = Array.from(rowGroupsMap.entries()).map(\n ([groupingValue, groupedRows], index) => {\n let id = `${columnId}:${groupingValue}`\n id = parentId ? `${parentId}>${id}` : id\n\n // First, Recurse to group sub rows before aggregation\n const subRows = groupUpRecursively(groupedRows, depth + 1, id)\n\n subRows.forEach((subRow) => {\n subRow.parentId = id\n })\n\n const leafRows = normalizeAggregationRows(groupedRows, Infinity)\n\n const row = constructRow(\n table,\n id,\n leafRows[0]!.original,\n index,\n depth,\n undefined,\n parentId,\n ) as Row<TFeatures, TData> & Partial<Row_ColumnGrouping>\n\n Object.assign(row, {\n groupingColumnId: columnId,\n groupingValue,\n subRows,\n leafRows,\n getValue: (colId: string) => {\n const groupingIndex = existingGrouping.indexOf(colId)\n\n // The active grouping column and ancestor grouping columns expose\n // their inherited grouping values. Columns grouped at deeper\n // levels are still eligible for aggregation here.\n if (groupingIndex !== -1 && groupingIndex <= depth) {\n if (hasOwn(row._valuesCache, colId)) {\n return row._valuesCache[colId]\n }\n\n if (groupedRows[0]) {\n row._valuesCache[colId] =\n groupedRows[0].getValue(colId) ?? undefined\n }\n\n return row._valuesCache[colId]\n }\n\n const aggregationCache = (row as any)._aggregationValuesCache as\n | Record<string, unknown>\n | undefined\n if (aggregationCache && hasOwn(aggregationCache, colId)) {\n return aggregationCache[colId]\n }\n\n const column = table.getColumn(colId) as any\n if (typeof column.getAggregationFns !== 'function') return undefined\n\n const cache = ((row as any)._aggregationValuesCache ??=\n makeObjectMap())\n cache[colId] = aggregateColumnValue({\n subRows,\n column,\n groupingRow: row,\n rows: groupedRows,\n })\n return cache[colId]\n },\n })\n\n subRows.forEach((subRow) => {\n groupedFlatRows.push(subRow)\n groupedRowsById[subRow.id] = subRow\n })\n\n return row\n },\n )\n\n return aggregatedGroupedRows\n }\n\n const groupedRows = groupUpRecursively(rowModel.rows, 0)\n\n groupedRows.forEach((subRow) => {\n groupedFlatRows.push(subRow)\n groupedRowsById[subRow.id] = subRow\n })\n\n return {\n rows: groupedRows,\n flatRows: groupedFlatRows,\n rowsById: groupedRowsById,\n }\n}\n\nfunction groupBy<TFeatures extends TableFeatures, TData extends RowData = any>(\n rows: Array<Row<TFeatures, TData>>,\n columnId: string,\n) {\n const groupMap = new Map<any, Array<Row<TFeatures, TData>>>()\n\n return rows.reduce((map, row) => {\n const resKey = `${row_getGroupingValue(row, columnId)}`\n const previous = map.get(resKey)\n if (!previous) {\n map.set(resKey, [row])\n } else {\n previous.push(row)\n }\n return map\n }, groupMap)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createGroupedRowModel.cjs","names":["tableMemo","table_getColumn","makeObjectMap","normalizeUniqueAggregationRows","constructRow","hasOwn","aggregateColumnValue"],"sources":["../../../src/features/column-grouping/createGroupedRowModel.ts"],"sourcesContent":["import { hasOwn, makeObjectMap, tableMemo } from '../../utils'\nimport { constructRow } from '../../core/rows/constructRow'\nimport { table_getColumn } from '../../core/columns/coreColumnsFeature.utils'\nimport { table_autoResetExpanded } from '../row-expanding/rowExpandingFeature.utils'\nimport { table_autoResetPageIndex } from '../row-pagination/rowPaginationFeature.utils'\nimport {\n aggregateColumnValue,\n normalizeUniqueAggregationRows,\n} from '../row-aggregation/rowAggregationFeature.utils'\nimport type { Row_ColumnGrouping } from './columnGroupingFeature.types'\nimport type { Column_Internal } from '../../types/Column'\nimport type { TableFeatures } from '../../types/TableFeatures'\nimport type { RowModel } from '../../core/row-models/coreRowModelsFeature.types'\nimport type { Table, Table_Internal } from '../../types/Table'\nimport type { Row } from '../../types/Row'\nimport type { RowData } from '../../types/type-utils'\n\n/**\n * Creates a memoized grouped row model factory.\n *\n * The factory reads the relevant table state atoms and options, then returns a row model function used by the table row-model pipeline.\n *\n * When rowAggregationFeature is also registered, grouped rows use its shared\n * executor for non-group values. Grouping remains useful without aggregation.\n */\nexport function createGroupedRowModel<\n TFeatures extends TableFeatures,\n TData extends RowData = any,\n>(): (table: Table<TFeatures, TData>) => () => RowModel<TFeatures, TData> {\n return (_table) => {\n const table = _table as unknown as Table_Internal<TFeatures, TData>\n return tableMemo({\n feature: 'columnGroupingFeature',\n table,\n fnName: 'table.getGroupedRowModel',\n memoDeps: () => [\n table.atoms.grouping?.get(),\n table.getPreGroupedRowModel(),\n table.options.columns,\n ],\n fn: () => _createGroupedRowModel(table),\n onAfterUpdate: () => {\n table_autoResetExpanded(table)\n table_autoResetPageIndex(table)\n },\n })\n }\n}\n\nfunction _createGroupedRowModel<\n TFeatures extends TableFeatures,\n TData extends RowData = any,\n>(table: Table_Internal<TFeatures, TData>): RowModel<TFeatures, TData> {\n const rowModel = table.getPreGroupedRowModel()\n const grouping = table.atoms.grouping?.get()\n\n if (!rowModel.rows.length || !grouping?.length) {\n rowModel.rows.forEach((row) => {\n row.depth = 0\n row.parentId = undefined\n })\n return rowModel\n }\n\n // Filter the grouping list down to columns that exist\n const existingGrouping = grouping.filter((columnId) =>\n table_getColumn(table, columnId),\n )\n\n const groupedFlatRows: Array<Row<TFeatures, TData>> &\n Partial<Row_ColumnGrouping> = []\n const groupedRowsById = makeObjectMap<Row<TFeatures, TData>>()\n\n // Recursively group the data\n const groupUpRecursively = (\n rows: Array<Row<TFeatures, TData>>,\n depth = 0,\n parentId?: string,\n ) => {\n // Grouping depth has been been met\n // Stop grouping and simply rewrite thd depth and row relationships\n if (depth >= existingGrouping.length) {\n return rows.map((row) => {\n row.depth = depth\n\n // Every row is pushed into flatRows/rowsById exactly once, by its\n // parent frame: rows returned here are pushed by the caller (the\n // parent group's loop or the root loop), so only descendants below\n // the terminal depth are pushed here.\n if (row.subRows.length) {\n row.subRows = groupUpRecursively(row.subRows, depth + 1, row.id)\n for (let i = 0; i < row.subRows.length; i++) {\n const subRow = row.subRows[i]!\n groupedFlatRows.push(subRow)\n groupedRowsById[subRow.id] = subRow\n }\n }\n\n return row\n })\n }\n\n const columnId = existingGrouping[depth] as string\n\n // Group the rows together for this level\n const rowGroupsMap = groupBy(table, rows, columnId)\n\n // Perform aggregations for each group\n const aggregatedGroupedRows = Array.from(rowGroupsMap.entries()).map(\n ([groupingValue, groupedRows], index) => {\n let id = `${columnId}:${groupingValue}`\n id = parentId ? `${parentId}>${id}` : id\n\n // First, Recurse to group sub rows before aggregation\n const subRows = groupUpRecursively(groupedRows, depth + 1, id)\n\n subRows.forEach((subRow) => {\n subRow.parentId = id\n })\n\n // Rows produced by groupBy are disjoint members of the pre-grouped\n // row tree, so the duplicate-id guard is unnecessary; flat groups\n // reuse the partition array as-is.\n const leafRows = normalizeUniqueAggregationRows(\n groupedRows,\n Infinity,\n ) as Array<Row<TFeatures, TData>>\n\n const row = constructRow(\n table,\n id,\n leafRows[0]!.original,\n index,\n depth,\n undefined,\n parentId,\n ) as Row<TFeatures, TData> & Partial<Row_ColumnGrouping>\n\n Object.assign(row, {\n groupingColumnId: columnId,\n groupingValue,\n subRows,\n leafRows,\n getValue: (colId: string) => {\n const groupingIndex = existingGrouping.indexOf(colId)\n\n // The active grouping column and ancestor grouping columns expose\n // their inherited grouping values. Columns grouped at deeper\n // levels are still eligible for aggregation here.\n if (groupingIndex !== -1 && groupingIndex <= depth) {\n if (hasOwn(row._valuesCache, colId)) {\n return row._valuesCache[colId]\n }\n\n if (groupedRows[0]) {\n row._valuesCache[colId] =\n groupedRows[0].getValue(colId) ?? undefined\n }\n\n return row._valuesCache[colId]\n }\n\n const aggregationCache = (row as any)._aggregationValuesCache as\n | Record<string, unknown>\n | undefined\n if (aggregationCache && hasOwn(aggregationCache, colId)) {\n return aggregationCache[colId]\n }\n\n const column = table.getColumn(colId) as any\n if (typeof column.getAggregationFns !== 'function') return undefined\n\n const cache = ((row as any)._aggregationValuesCache ??=\n makeObjectMap())\n cache[colId] = aggregateColumnValue({\n subRows,\n column,\n groupingRow: row,\n rows: groupedRows,\n uniqueRows: true,\n })\n return cache[colId]\n },\n })\n\n subRows.forEach((subRow) => {\n groupedFlatRows.push(subRow)\n groupedRowsById[subRow.id] = subRow\n })\n\n return row\n },\n )\n\n return aggregatedGroupedRows\n }\n\n const groupedRows = groupUpRecursively(rowModel.rows, 0)\n\n groupedRows.forEach((subRow) => {\n groupedFlatRows.push(subRow)\n groupedRowsById[subRow.id] = subRow\n })\n\n return {\n rows: groupedRows,\n flatRows: groupedFlatRows,\n rowsById: groupedRowsById,\n }\n}\n\nfunction groupBy<TFeatures extends TableFeatures, TData extends RowData = any>(\n table: Table_Internal<TFeatures, TData>,\n rows: Array<Row<TFeatures, TData>>,\n columnId: string,\n) {\n const groupMap = new Map<any, Array<Row<TFeatures, TData>>>()\n\n // Resolve the column once instead of per row: `table.getColumn` goes\n // through the memoized-API dispatcher, which is far too expensive to sit\n // inside this per-row loop. The branches below mirror\n // `row_getGroupingValue`'s caching contract exactly.\n const column = table_getColumn(table, columnId) as\n | Column_Internal<TFeatures, TData, unknown>\n | undefined\n const getGroupingValue = column?.columnDef.getGroupingValue\n\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i]!\n let groupingValue\n if (getGroupingValue) {\n const cache = (row as any)._groupingValuesCache as\n | Record<string, unknown>\n | undefined\n if (cache && hasOwn(cache, columnId)) {\n groupingValue = cache[columnId]\n } else if (cache) {\n groupingValue = cache[columnId] = getGroupingValue(\n row.original,\n row.index,\n row,\n )\n }\n } else {\n groupingValue = row.getValue(columnId)\n }\n\n const resKey = `${groupingValue}`\n const previous = groupMap.get(resKey)\n if (!previous) {\n groupMap.set(resKey, [row])\n } else {\n previous.push(row)\n }\n }\n\n return groupMap\n}\n"],"mappings":"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"}
|
|
@@ -2,8 +2,7 @@ import { hasOwn, makeObjectMap, tableMemo } from "../../utils.js";
|
|
|
2
2
|
import { table_getColumn } from "../../core/columns/coreColumnsFeature.utils.js";
|
|
3
3
|
import { constructRow } from "../../core/rows/constructRow.js";
|
|
4
4
|
import { table_autoResetPageIndex } from "../row-pagination/rowPaginationFeature.utils.js";
|
|
5
|
-
import { aggregateColumnValue,
|
|
6
|
-
import { row_getGroupingValue } from "./columnGroupingFeature.utils.js";
|
|
5
|
+
import { aggregateColumnValue, normalizeUniqueAggregationRows } from "../row-aggregation/rowAggregationFeature.utils.js";
|
|
7
6
|
import { table_autoResetExpanded } from "../row-expanding/rowExpandingFeature.utils.js";
|
|
8
7
|
|
|
9
8
|
//#region src/features/column-grouping/createGroupedRowModel.ts
|
|
@@ -62,7 +61,7 @@ function _createGroupedRowModel(table) {
|
|
|
62
61
|
return row;
|
|
63
62
|
});
|
|
64
63
|
const columnId = existingGrouping[depth];
|
|
65
|
-
const rowGroupsMap = groupBy(rows, columnId);
|
|
64
|
+
const rowGroupsMap = groupBy(table, rows, columnId);
|
|
66
65
|
return Array.from(rowGroupsMap.entries()).map(([groupingValue, groupedRows], index) => {
|
|
67
66
|
let id = `${columnId}:${groupingValue}`;
|
|
68
67
|
id = parentId ? `${parentId}>${id}` : id;
|
|
@@ -70,7 +69,7 @@ function _createGroupedRowModel(table) {
|
|
|
70
69
|
subRows.forEach((subRow) => {
|
|
71
70
|
subRow.parentId = id;
|
|
72
71
|
});
|
|
73
|
-
const leafRows =
|
|
72
|
+
const leafRows = normalizeUniqueAggregationRows(groupedRows, Infinity);
|
|
74
73
|
const row = constructRow(table, id, leafRows[0].original, index, depth, void 0, parentId);
|
|
75
74
|
Object.assign(row, {
|
|
76
75
|
groupingColumnId: columnId,
|
|
@@ -93,7 +92,8 @@ function _createGroupedRowModel(table) {
|
|
|
93
92
|
subRows,
|
|
94
93
|
column,
|
|
95
94
|
groupingRow: row,
|
|
96
|
-
rows: groupedRows
|
|
95
|
+
rows: groupedRows,
|
|
96
|
+
uniqueRows: true
|
|
97
97
|
});
|
|
98
98
|
return cache[colId];
|
|
99
99
|
}
|
|
@@ -116,15 +116,23 @@ function _createGroupedRowModel(table) {
|
|
|
116
116
|
rowsById: groupedRowsById
|
|
117
117
|
};
|
|
118
118
|
}
|
|
119
|
-
function groupBy(rows, columnId) {
|
|
119
|
+
function groupBy(table, rows, columnId) {
|
|
120
120
|
const groupMap = /* @__PURE__ */ new Map();
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
|
|
121
|
+
const getGroupingValue = table_getColumn(table, columnId)?.columnDef.getGroupingValue;
|
|
122
|
+
for (let i = 0; i < rows.length; i++) {
|
|
123
|
+
const row = rows[i];
|
|
124
|
+
let groupingValue;
|
|
125
|
+
if (getGroupingValue) {
|
|
126
|
+
const cache = row._groupingValuesCache;
|
|
127
|
+
if (cache && hasOwn(cache, columnId)) groupingValue = cache[columnId];
|
|
128
|
+
else if (cache) groupingValue = cache[columnId] = getGroupingValue(row.original, row.index, row);
|
|
129
|
+
} else groupingValue = row.getValue(columnId);
|
|
130
|
+
const resKey = `${groupingValue}`;
|
|
131
|
+
const previous = groupMap.get(resKey);
|
|
132
|
+
if (!previous) groupMap.set(resKey, [row]);
|
|
125
133
|
else previous.push(row);
|
|
126
|
-
|
|
127
|
-
|
|
134
|
+
}
|
|
135
|
+
return groupMap;
|
|
128
136
|
}
|
|
129
137
|
|
|
130
138
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createGroupedRowModel.js","names":[],"sources":["../../../src/features/column-grouping/createGroupedRowModel.ts"],"sourcesContent":["import { hasOwn, makeObjectMap, tableMemo } from '../../utils'\nimport { constructRow } from '../../core/rows/constructRow'\nimport { table_getColumn } from '../../core/columns/coreColumnsFeature.utils'\nimport { table_autoResetExpanded } from '../row-expanding/rowExpandingFeature.utils'\nimport { table_autoResetPageIndex } from '../row-pagination/rowPaginationFeature.utils'\nimport {\n aggregateColumnValue,\n normalizeAggregationRows,\n} from '../row-aggregation/rowAggregationFeature.utils'\nimport { row_getGroupingValue } from './columnGroupingFeature.utils'\nimport type { Row_ColumnGrouping } from './columnGroupingFeature.types'\nimport type { TableFeatures } from '../../types/TableFeatures'\nimport type { RowModel } from '../../core/row-models/coreRowModelsFeature.types'\nimport type { Table, Table_Internal } from '../../types/Table'\nimport type { Row } from '../../types/Row'\nimport type { RowData } from '../../types/type-utils'\n\n/**\n * Creates a memoized grouped row model factory.\n *\n * The factory reads the relevant table state atoms and options, then returns a row model function used by the table row-model pipeline.\n *\n * When rowAggregationFeature is also registered, grouped rows use its shared\n * executor for non-group values. Grouping remains useful without aggregation.\n */\nexport function createGroupedRowModel<\n TFeatures extends TableFeatures,\n TData extends RowData = any,\n>(): (table: Table<TFeatures, TData>) => () => RowModel<TFeatures, TData> {\n return (_table) => {\n const table = _table as unknown as Table_Internal<TFeatures, TData>\n return tableMemo({\n feature: 'columnGroupingFeature',\n table,\n fnName: 'table.getGroupedRowModel',\n memoDeps: () => [\n table.atoms.grouping?.get(),\n table.getPreGroupedRowModel(),\n table.options.columns,\n ],\n fn: () => _createGroupedRowModel(table),\n onAfterUpdate: () => {\n table_autoResetExpanded(table)\n table_autoResetPageIndex(table)\n },\n })\n }\n}\n\nfunction _createGroupedRowModel<\n TFeatures extends TableFeatures,\n TData extends RowData = any,\n>(table: Table_Internal<TFeatures, TData>): RowModel<TFeatures, TData> {\n const rowModel = table.getPreGroupedRowModel()\n const grouping = table.atoms.grouping?.get()\n\n if (!rowModel.rows.length || !grouping?.length) {\n rowModel.rows.forEach((row) => {\n row.depth = 0\n row.parentId = undefined\n })\n return rowModel\n }\n\n // Filter the grouping list down to columns that exist\n const existingGrouping = grouping.filter((columnId) =>\n table_getColumn(table, columnId),\n )\n\n const groupedFlatRows: Array<Row<TFeatures, TData>> &\n Partial<Row_ColumnGrouping> = []\n const groupedRowsById = makeObjectMap<Row<TFeatures, TData>>()\n\n // Recursively group the data\n const groupUpRecursively = (\n rows: Array<Row<TFeatures, TData>>,\n depth = 0,\n parentId?: string,\n ) => {\n // Grouping depth has been been met\n // Stop grouping and simply rewrite thd depth and row relationships\n if (depth >= existingGrouping.length) {\n return rows.map((row) => {\n row.depth = depth\n\n // Every row is pushed into flatRows/rowsById exactly once, by its\n // parent frame: rows returned here are pushed by the caller (the\n // parent group's loop or the root loop), so only descendants below\n // the terminal depth are pushed here.\n if (row.subRows.length) {\n row.subRows = groupUpRecursively(row.subRows, depth + 1, row.id)\n for (let i = 0; i < row.subRows.length; i++) {\n const subRow = row.subRows[i]!\n groupedFlatRows.push(subRow)\n groupedRowsById[subRow.id] = subRow\n }\n }\n\n return row\n })\n }\n\n const columnId = existingGrouping[depth] as string\n\n // Group the rows together for this level\n const rowGroupsMap = groupBy(rows, columnId)\n\n // Perform aggregations for each group\n const aggregatedGroupedRows = Array.from(rowGroupsMap.entries()).map(\n ([groupingValue, groupedRows], index) => {\n let id = `${columnId}:${groupingValue}`\n id = parentId ? `${parentId}>${id}` : id\n\n // First, Recurse to group sub rows before aggregation\n const subRows = groupUpRecursively(groupedRows, depth + 1, id)\n\n subRows.forEach((subRow) => {\n subRow.parentId = id\n })\n\n const leafRows = normalizeAggregationRows(groupedRows, Infinity)\n\n const row = constructRow(\n table,\n id,\n leafRows[0]!.original,\n index,\n depth,\n undefined,\n parentId,\n ) as Row<TFeatures, TData> & Partial<Row_ColumnGrouping>\n\n Object.assign(row, {\n groupingColumnId: columnId,\n groupingValue,\n subRows,\n leafRows,\n getValue: (colId: string) => {\n const groupingIndex = existingGrouping.indexOf(colId)\n\n // The active grouping column and ancestor grouping columns expose\n // their inherited grouping values. Columns grouped at deeper\n // levels are still eligible for aggregation here.\n if (groupingIndex !== -1 && groupingIndex <= depth) {\n if (hasOwn(row._valuesCache, colId)) {\n return row._valuesCache[colId]\n }\n\n if (groupedRows[0]) {\n row._valuesCache[colId] =\n groupedRows[0].getValue(colId) ?? undefined\n }\n\n return row._valuesCache[colId]\n }\n\n const aggregationCache = (row as any)._aggregationValuesCache as\n | Record<string, unknown>\n | undefined\n if (aggregationCache && hasOwn(aggregationCache, colId)) {\n return aggregationCache[colId]\n }\n\n const column = table.getColumn(colId) as any\n if (typeof column.getAggregationFns !== 'function') return undefined\n\n const cache = ((row as any)._aggregationValuesCache ??=\n makeObjectMap())\n cache[colId] = aggregateColumnValue({\n subRows,\n column,\n groupingRow: row,\n rows: groupedRows,\n })\n return cache[colId]\n },\n })\n\n subRows.forEach((subRow) => {\n groupedFlatRows.push(subRow)\n groupedRowsById[subRow.id] = subRow\n })\n\n return row\n },\n )\n\n return aggregatedGroupedRows\n }\n\n const groupedRows = groupUpRecursively(rowModel.rows, 0)\n\n groupedRows.forEach((subRow) => {\n groupedFlatRows.push(subRow)\n groupedRowsById[subRow.id] = subRow\n })\n\n return {\n rows: groupedRows,\n flatRows: groupedFlatRows,\n rowsById: groupedRowsById,\n }\n}\n\nfunction groupBy<TFeatures extends TableFeatures, TData extends RowData = any>(\n rows: Array<Row<TFeatures, TData>>,\n columnId: string,\n) {\n const groupMap = new Map<any, Array<Row<TFeatures, TData>>>()\n\n return rows.reduce((map, row) => {\n const resKey = `${row_getGroupingValue(row, columnId)}`\n const previous = map.get(resKey)\n if (!previous) {\n map.set(resKey, [row])\n } else {\n previous.push(row)\n }\n return map\n }, groupMap)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createGroupedRowModel.js","names":[],"sources":["../../../src/features/column-grouping/createGroupedRowModel.ts"],"sourcesContent":["import { hasOwn, makeObjectMap, tableMemo } from '../../utils'\nimport { constructRow } from '../../core/rows/constructRow'\nimport { table_getColumn } from '../../core/columns/coreColumnsFeature.utils'\nimport { table_autoResetExpanded } from '../row-expanding/rowExpandingFeature.utils'\nimport { table_autoResetPageIndex } from '../row-pagination/rowPaginationFeature.utils'\nimport {\n aggregateColumnValue,\n normalizeUniqueAggregationRows,\n} from '../row-aggregation/rowAggregationFeature.utils'\nimport type { Row_ColumnGrouping } from './columnGroupingFeature.types'\nimport type { Column_Internal } from '../../types/Column'\nimport type { TableFeatures } from '../../types/TableFeatures'\nimport type { RowModel } from '../../core/row-models/coreRowModelsFeature.types'\nimport type { Table, Table_Internal } from '../../types/Table'\nimport type { Row } from '../../types/Row'\nimport type { RowData } from '../../types/type-utils'\n\n/**\n * Creates a memoized grouped row model factory.\n *\n * The factory reads the relevant table state atoms and options, then returns a row model function used by the table row-model pipeline.\n *\n * When rowAggregationFeature is also registered, grouped rows use its shared\n * executor for non-group values. Grouping remains useful without aggregation.\n */\nexport function createGroupedRowModel<\n TFeatures extends TableFeatures,\n TData extends RowData = any,\n>(): (table: Table<TFeatures, TData>) => () => RowModel<TFeatures, TData> {\n return (_table) => {\n const table = _table as unknown as Table_Internal<TFeatures, TData>\n return tableMemo({\n feature: 'columnGroupingFeature',\n table,\n fnName: 'table.getGroupedRowModel',\n memoDeps: () => [\n table.atoms.grouping?.get(),\n table.getPreGroupedRowModel(),\n table.options.columns,\n ],\n fn: () => _createGroupedRowModel(table),\n onAfterUpdate: () => {\n table_autoResetExpanded(table)\n table_autoResetPageIndex(table)\n },\n })\n }\n}\n\nfunction _createGroupedRowModel<\n TFeatures extends TableFeatures,\n TData extends RowData = any,\n>(table: Table_Internal<TFeatures, TData>): RowModel<TFeatures, TData> {\n const rowModel = table.getPreGroupedRowModel()\n const grouping = table.atoms.grouping?.get()\n\n if (!rowModel.rows.length || !grouping?.length) {\n rowModel.rows.forEach((row) => {\n row.depth = 0\n row.parentId = undefined\n })\n return rowModel\n }\n\n // Filter the grouping list down to columns that exist\n const existingGrouping = grouping.filter((columnId) =>\n table_getColumn(table, columnId),\n )\n\n const groupedFlatRows: Array<Row<TFeatures, TData>> &\n Partial<Row_ColumnGrouping> = []\n const groupedRowsById = makeObjectMap<Row<TFeatures, TData>>()\n\n // Recursively group the data\n const groupUpRecursively = (\n rows: Array<Row<TFeatures, TData>>,\n depth = 0,\n parentId?: string,\n ) => {\n // Grouping depth has been been met\n // Stop grouping and simply rewrite thd depth and row relationships\n if (depth >= existingGrouping.length) {\n return rows.map((row) => {\n row.depth = depth\n\n // Every row is pushed into flatRows/rowsById exactly once, by its\n // parent frame: rows returned here are pushed by the caller (the\n // parent group's loop or the root loop), so only descendants below\n // the terminal depth are pushed here.\n if (row.subRows.length) {\n row.subRows = groupUpRecursively(row.subRows, depth + 1, row.id)\n for (let i = 0; i < row.subRows.length; i++) {\n const subRow = row.subRows[i]!\n groupedFlatRows.push(subRow)\n groupedRowsById[subRow.id] = subRow\n }\n }\n\n return row\n })\n }\n\n const columnId = existingGrouping[depth] as string\n\n // Group the rows together for this level\n const rowGroupsMap = groupBy(table, rows, columnId)\n\n // Perform aggregations for each group\n const aggregatedGroupedRows = Array.from(rowGroupsMap.entries()).map(\n ([groupingValue, groupedRows], index) => {\n let id = `${columnId}:${groupingValue}`\n id = parentId ? `${parentId}>${id}` : id\n\n // First, Recurse to group sub rows before aggregation\n const subRows = groupUpRecursively(groupedRows, depth + 1, id)\n\n subRows.forEach((subRow) => {\n subRow.parentId = id\n })\n\n // Rows produced by groupBy are disjoint members of the pre-grouped\n // row tree, so the duplicate-id guard is unnecessary; flat groups\n // reuse the partition array as-is.\n const leafRows = normalizeUniqueAggregationRows(\n groupedRows,\n Infinity,\n ) as Array<Row<TFeatures, TData>>\n\n const row = constructRow(\n table,\n id,\n leafRows[0]!.original,\n index,\n depth,\n undefined,\n parentId,\n ) as Row<TFeatures, TData> & Partial<Row_ColumnGrouping>\n\n Object.assign(row, {\n groupingColumnId: columnId,\n groupingValue,\n subRows,\n leafRows,\n getValue: (colId: string) => {\n const groupingIndex = existingGrouping.indexOf(colId)\n\n // The active grouping column and ancestor grouping columns expose\n // their inherited grouping values. Columns grouped at deeper\n // levels are still eligible for aggregation here.\n if (groupingIndex !== -1 && groupingIndex <= depth) {\n if (hasOwn(row._valuesCache, colId)) {\n return row._valuesCache[colId]\n }\n\n if (groupedRows[0]) {\n row._valuesCache[colId] =\n groupedRows[0].getValue(colId) ?? undefined\n }\n\n return row._valuesCache[colId]\n }\n\n const aggregationCache = (row as any)._aggregationValuesCache as\n | Record<string, unknown>\n | undefined\n if (aggregationCache && hasOwn(aggregationCache, colId)) {\n return aggregationCache[colId]\n }\n\n const column = table.getColumn(colId) as any\n if (typeof column.getAggregationFns !== 'function') return undefined\n\n const cache = ((row as any)._aggregationValuesCache ??=\n makeObjectMap())\n cache[colId] = aggregateColumnValue({\n subRows,\n column,\n groupingRow: row,\n rows: groupedRows,\n uniqueRows: true,\n })\n return cache[colId]\n },\n })\n\n subRows.forEach((subRow) => {\n groupedFlatRows.push(subRow)\n groupedRowsById[subRow.id] = subRow\n })\n\n return row\n },\n )\n\n return aggregatedGroupedRows\n }\n\n const groupedRows = groupUpRecursively(rowModel.rows, 0)\n\n groupedRows.forEach((subRow) => {\n groupedFlatRows.push(subRow)\n groupedRowsById[subRow.id] = subRow\n })\n\n return {\n rows: groupedRows,\n flatRows: groupedFlatRows,\n rowsById: groupedRowsById,\n }\n}\n\nfunction groupBy<TFeatures extends TableFeatures, TData extends RowData = any>(\n table: Table_Internal<TFeatures, TData>,\n rows: Array<Row<TFeatures, TData>>,\n columnId: string,\n) {\n const groupMap = new Map<any, Array<Row<TFeatures, TData>>>()\n\n // Resolve the column once instead of per row: `table.getColumn` goes\n // through the memoized-API dispatcher, which is far too expensive to sit\n // inside this per-row loop. The branches below mirror\n // `row_getGroupingValue`'s caching contract exactly.\n const column = table_getColumn(table, columnId) as\n | Column_Internal<TFeatures, TData, unknown>\n | undefined\n const getGroupingValue = column?.columnDef.getGroupingValue\n\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i]!\n let groupingValue\n if (getGroupingValue) {\n const cache = (row as any)._groupingValuesCache as\n | Record<string, unknown>\n | undefined\n if (cache && hasOwn(cache, columnId)) {\n groupingValue = cache[columnId]\n } else if (cache) {\n groupingValue = cache[columnId] = getGroupingValue(\n row.original,\n row.index,\n row,\n )\n }\n } else {\n groupingValue = row.getValue(columnId)\n }\n\n const resKey = `${groupingValue}`\n const previous = groupMap.get(resKey)\n if (!previous) {\n groupMap.set(resKey, [row])\n } else {\n previous.push(row)\n }\n }\n\n return groupMap\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAyBA,SAAgB,wBAG0D;CACxE,QAAQ,WAAW;EACjB,MAAM,QAAQ;EACd,OAAO,UAAU;GACf,SAAS;GACT;GACA,QAAQ;GACR,gBAAgB;IACd,MAAM,MAAM,UAAU,IAAI;IAC1B,MAAM,sBAAsB;IAC5B,MAAM,QAAQ;GAChB;GACA,UAAU,uBAAuB,KAAK;GACtC,qBAAqB;IACnB,wBAAwB,KAAK;IAC7B,yBAAyB,KAAK;GAChC;EACF,CAAC;CACH;AACF;AAEA,SAAS,uBAGP,OAAqE;CACrE,MAAM,WAAW,MAAM,sBAAsB;CAC7C,MAAM,WAAW,MAAM,MAAM,UAAU,IAAI;CAE3C,IAAI,CAAC,SAAS,KAAK,UAAU,CAAC,UAAU,QAAQ;EAC9C,SAAS,KAAK,SAAS,QAAQ;GAC7B,IAAI,QAAQ;GACZ,IAAI,WAAW;EACjB,CAAC;EACD,OAAO;CACT;CAGA,MAAM,mBAAmB,SAAS,QAAQ,aACxC,gBAAgB,OAAO,QAAQ,CACjC;CAEA,MAAM,kBAC0B,CAAC;CACjC,MAAM,kBAAkB,cAAqC;CAG7D,MAAM,sBACJ,MACA,QAAQ,GACR,aACG;EAGH,IAAI,SAAS,iBAAiB,QAC5B,OAAO,KAAK,KAAK,QAAQ;GACvB,IAAI,QAAQ;GAMZ,IAAI,IAAI,QAAQ,QAAQ;IACtB,IAAI,UAAU,mBAAmB,IAAI,SAAS,QAAQ,GAAG,IAAI,EAAE;IAC/D,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,QAAQ,KAAK;KAC3C,MAAM,SAAS,IAAI,QAAQ;KAC3B,gBAAgB,KAAK,MAAM;KAC3B,gBAAgB,OAAO,MAAM;IAC/B;GACF;GAEA,OAAO;EACT,CAAC;EAGH,MAAM,WAAW,iBAAiB;EAGlC,MAAM,eAAe,QAAQ,OAAO,MAAM,QAAQ;EAyFlD,OAtF8B,MAAM,KAAK,aAAa,QAAQ,CAAC,CAAC,CAAC,KAC9D,CAAC,eAAe,cAAc,UAAU;GACvC,IAAI,KAAK,GAAG,SAAS,GAAG;GACxB,KAAK,WAAW,GAAG,SAAS,GAAG,OAAO;GAGtC,MAAM,UAAU,mBAAmB,aAAa,QAAQ,GAAG,EAAE;GAE7D,QAAQ,SAAS,WAAW;IAC1B,OAAO,WAAW;GACpB,CAAC;GAKD,MAAM,WAAW,+BACf,aACA,QACF;GAEA,MAAM,MAAM,aACV,OACA,IACA,SAAS,EAAE,CAAE,UACb,OACA,OACA,QACA,QACF;GAEA,OAAO,OAAO,KAAK;IACjB,kBAAkB;IAClB;IACA;IACA;IACA,WAAW,UAAkB;KAC3B,MAAM,gBAAgB,iBAAiB,QAAQ,KAAK;KAKpD,IAAI,kBAAkB,MAAM,iBAAiB,OAAO;MAClD,IAAI,OAAO,IAAI,cAAc,KAAK,GAChC,OAAO,IAAI,aAAa;MAG1B,IAAI,YAAY,IACd,IAAI,aAAa,SACf,YAAY,EAAE,CAAC,SAAS,KAAK,KAAK;MAGtC,OAAO,IAAI,aAAa;KAC1B;KAEA,MAAM,mBAAoB,IAAY;KAGtC,IAAI,oBAAoB,OAAO,kBAAkB,KAAK,GACpD,OAAO,iBAAiB;KAG1B,MAAM,SAAS,MAAM,UAAU,KAAK;KACpC,IAAI,OAAO,OAAO,sBAAsB,YAAY,OAAO;KAE3D,MAAM,QAAS,AAAC,IAAY,4BAC1B,cAAc;KAChB,MAAM,SAAS,qBAAqB;MAClC;MACA;MACA,aAAa;MACb,MAAM;MACN,YAAY;KACd,CAAC;KACD,OAAO,MAAM;IACf;GACF,CAAC;GAED,QAAQ,SAAS,WAAW;IAC1B,gBAAgB,KAAK,MAAM;IAC3B,gBAAgB,OAAO,MAAM;GAC/B,CAAC;GAED,OAAO;EACT,CAGyB;CAC7B;CAEA,MAAM,cAAc,mBAAmB,SAAS,MAAM,CAAC;CAEvD,YAAY,SAAS,WAAW;EAC9B,gBAAgB,KAAK,MAAM;EAC3B,gBAAgB,OAAO,MAAM;CAC/B,CAAC;CAED,OAAO;EACL,MAAM;EACN,UAAU;EACV,UAAU;CACZ;AACF;AAEA,SAAS,QACP,OACA,MACA,UACA;CACA,MAAM,2BAAW,IAAI,IAAuC;CAS5D,MAAM,mBAHS,gBAAgB,OAAO,QAGR,CAAC,EAAE,UAAU;CAE3C,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,MAAM,KAAK;EACjB,IAAI;EACJ,IAAI,kBAAkB;GACpB,MAAM,QAAS,IAAY;GAG3B,IAAI,SAAS,OAAO,OAAO,QAAQ,GACjC,gBAAgB,MAAM;QACjB,IAAI,OACT,gBAAgB,MAAM,YAAY,iBAChC,IAAI,UACJ,IAAI,OACJ,GACF;EAEJ,OACE,gBAAgB,IAAI,SAAS,QAAQ;EAGvC,MAAM,SAAS,GAAG;EAClB,MAAM,WAAW,SAAS,IAAI,MAAM;EACpC,IAAI,CAAC,UACH,SAAS,IAAI,QAAQ,CAAC,GAAG,CAAC;OAE1B,SAAS,KAAK,GAAG;CAErB;CAEA,OAAO;AACT"}
|
|
@@ -14,17 +14,9 @@ function getRangeKind(value) {
|
|
|
14
14
|
function compareRangeValues(left, right) {
|
|
15
15
|
return (left instanceof Date ? left.getTime() : left) - (right instanceof Date ? right.getTime() : right);
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
for (let i = 0; i < context.rows.length; i++) {
|
|
21
|
-
const value = context.getValue(context.rows[i]);
|
|
22
|
-
const valueKind = getRangeKind(value);
|
|
23
|
-
if (!valueKind) continue;
|
|
24
|
-
kind ??= valueKind;
|
|
25
|
-
if (valueKind === kind) values.push(value);
|
|
26
|
-
}
|
|
27
|
-
return values;
|
|
17
|
+
/** Comparable representation of a range value; `Date`s compare by time. */
|
|
18
|
+
function toRangeNumber(value) {
|
|
19
|
+
return value instanceof Date ? value.getTime() : value;
|
|
28
20
|
}
|
|
29
21
|
/**
|
|
30
22
|
* Sums numeric selected-row values. Non-number values contribute zero. As in
|
|
@@ -32,9 +24,10 @@ function collectRangeValues(context) {
|
|
|
32
24
|
*/
|
|
33
25
|
const aggregationFn_sum = require_rowAggregationFeature_types.constructAggregationFn({
|
|
34
26
|
aggregate: (context) => {
|
|
27
|
+
const rows = context.rows;
|
|
35
28
|
let sum = 0;
|
|
36
|
-
for (let i = 0; i <
|
|
37
|
-
const value = context.getValue(
|
|
29
|
+
for (let i = 0; i < rows.length; i++) {
|
|
30
|
+
const value = context.getValue(rows[i]);
|
|
38
31
|
sum += typeof value === "number" ? value : 0;
|
|
39
32
|
}
|
|
40
33
|
return sum;
|
|
@@ -54,9 +47,24 @@ const aggregationFn_sum = require_rowAggregationFeature_types.constructAggregati
|
|
|
54
47
|
*/
|
|
55
48
|
const aggregationFn_min = require_rowAggregationFeature_types.constructAggregationFn({
|
|
56
49
|
aggregate: (context) => {
|
|
57
|
-
const
|
|
58
|
-
let
|
|
59
|
-
|
|
50
|
+
const rows = context.rows;
|
|
51
|
+
let kind;
|
|
52
|
+
let result;
|
|
53
|
+
let resultNumber = 0;
|
|
54
|
+
for (let i = 0; i < rows.length; i++) {
|
|
55
|
+
const value = context.getValue(rows[i]);
|
|
56
|
+
const valueKind = getRangeKind(value);
|
|
57
|
+
if (!valueKind || kind !== void 0 && valueKind !== kind) continue;
|
|
58
|
+
const valueNumber = toRangeNumber(value);
|
|
59
|
+
if (kind === void 0) {
|
|
60
|
+
kind = valueKind;
|
|
61
|
+
result = value;
|
|
62
|
+
resultNumber = valueNumber;
|
|
63
|
+
} else if (valueNumber - resultNumber < 0) {
|
|
64
|
+
result = value;
|
|
65
|
+
resultNumber = valueNumber;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
60
68
|
return result;
|
|
61
69
|
},
|
|
62
70
|
merge: ({ subRowResults }) => {
|
|
@@ -80,9 +88,24 @@ const aggregationFn_min = require_rowAggregationFeature_types.constructAggregati
|
|
|
80
88
|
*/
|
|
81
89
|
const aggregationFn_max = require_rowAggregationFeature_types.constructAggregationFn({
|
|
82
90
|
aggregate: (context) => {
|
|
83
|
-
const
|
|
84
|
-
let
|
|
85
|
-
|
|
91
|
+
const rows = context.rows;
|
|
92
|
+
let kind;
|
|
93
|
+
let result;
|
|
94
|
+
let resultNumber = 0;
|
|
95
|
+
for (let i = 0; i < rows.length; i++) {
|
|
96
|
+
const value = context.getValue(rows[i]);
|
|
97
|
+
const valueKind = getRangeKind(value);
|
|
98
|
+
if (!valueKind || kind !== void 0 && valueKind !== kind) continue;
|
|
99
|
+
const valueNumber = toRangeNumber(value);
|
|
100
|
+
if (kind === void 0) {
|
|
101
|
+
kind = valueKind;
|
|
102
|
+
result = value;
|
|
103
|
+
resultNumber = valueNumber;
|
|
104
|
+
} else if (valueNumber - resultNumber > 0) {
|
|
105
|
+
result = value;
|
|
106
|
+
resultNumber = valueNumber;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
86
109
|
return result;
|
|
87
110
|
},
|
|
88
111
|
merge: ({ subRowResults }) => {
|
|
@@ -107,15 +130,33 @@ const aggregationFn_max = require_rowAggregationFeature_types.constructAggregati
|
|
|
107
130
|
*/
|
|
108
131
|
const aggregationFn_extent = require_rowAggregationFeature_types.constructAggregationFn({
|
|
109
132
|
aggregate: (context) => {
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
let min
|
|
113
|
-
let max
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
133
|
+
const rows = context.rows;
|
|
134
|
+
let kind;
|
|
135
|
+
let min;
|
|
136
|
+
let max;
|
|
137
|
+
let minNumber = 0;
|
|
138
|
+
let maxNumber = 0;
|
|
139
|
+
for (let i = 0; i < rows.length; i++) {
|
|
140
|
+
const value = context.getValue(rows[i]);
|
|
141
|
+
const valueKind = getRangeKind(value);
|
|
142
|
+
if (!valueKind || kind !== void 0 && valueKind !== kind) continue;
|
|
143
|
+
const valueNumber = toRangeNumber(value);
|
|
144
|
+
if (kind === void 0) {
|
|
145
|
+
kind = valueKind;
|
|
146
|
+
min = max = value;
|
|
147
|
+
minNumber = maxNumber = valueNumber;
|
|
148
|
+
} else {
|
|
149
|
+
if (valueNumber - minNumber < 0) {
|
|
150
|
+
min = value;
|
|
151
|
+
minNumber = valueNumber;
|
|
152
|
+
}
|
|
153
|
+
if (valueNumber - maxNumber > 0) {
|
|
154
|
+
max = value;
|
|
155
|
+
maxNumber = valueNumber;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
118
158
|
}
|
|
159
|
+
if (kind === void 0) return [void 0, void 0];
|
|
119
160
|
return [min, max];
|
|
120
161
|
},
|
|
121
162
|
merge: ({ subRowResults }) => {
|
|
@@ -144,10 +185,11 @@ const aggregationFn_extent = require_rowAggregationFeature_types.constructAggreg
|
|
|
144
185
|
* are ignored; other values retain the legacy unary-plus coercion behavior.
|
|
145
186
|
*/
|
|
146
187
|
const aggregationFn_mean = require_rowAggregationFeature_types.constructAggregationFn({ aggregate: (context) => {
|
|
188
|
+
const rows = context.rows;
|
|
147
189
|
let count = 0;
|
|
148
190
|
let sum = 0;
|
|
149
|
-
for (let i = 0; i <
|
|
150
|
-
const value = context.getValue(
|
|
191
|
+
for (let i = 0; i < rows.length; i++) {
|
|
192
|
+
const value = context.getValue(rows[i]);
|
|
151
193
|
if (value == null) continue;
|
|
152
194
|
const numberValue = typeof value === "number" ? value : +value;
|
|
153
195
|
if (!Number.isNaN(numberValue)) {
|
|
@@ -162,10 +204,11 @@ const aggregationFn_mean = require_rowAggregationFeature_types.constructAggregat
|
|
|
162
204
|
* for empty inputs or when any value is non-numeric.
|
|
163
205
|
*/
|
|
164
206
|
const aggregationFn_median = require_rowAggregationFeature_types.constructAggregationFn({ aggregate: (context) => {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
207
|
+
const rows = context.rows;
|
|
208
|
+
if (!rows.length) return void 0;
|
|
209
|
+
const values = new Array(rows.length);
|
|
210
|
+
for (let i = 0; i < rows.length; i++) {
|
|
211
|
+
const value = context.getValue(rows[i]);
|
|
169
212
|
if (typeof value !== "number") return void 0;
|
|
170
213
|
values[i] = value;
|
|
171
214
|
}
|
|
@@ -175,14 +218,16 @@ const aggregationFn_median = require_rowAggregationFeature_types.constructAggreg
|
|
|
175
218
|
} });
|
|
176
219
|
/** Collects distinct row values using JavaScript `Set` semantics. */
|
|
177
220
|
const aggregationFn_unique = require_rowAggregationFeature_types.constructAggregationFn({ aggregate: (context) => {
|
|
221
|
+
const rows = context.rows;
|
|
178
222
|
const values = /* @__PURE__ */ new Set();
|
|
179
|
-
for (let i = 0; i <
|
|
223
|
+
for (let i = 0; i < rows.length; i++) values.add(context.getValue(rows[i]));
|
|
180
224
|
return Array.from(values);
|
|
181
225
|
} });
|
|
182
226
|
/** Counts distinct row values using JavaScript `Set` semantics. */
|
|
183
227
|
const aggregationFn_uniqueCount = require_rowAggregationFeature_types.constructAggregationFn({ aggregate: (context) => {
|
|
228
|
+
const rows = context.rows;
|
|
184
229
|
const values = /* @__PURE__ */ new Set();
|
|
185
|
-
for (let i = 0; i <
|
|
230
|
+
for (let i = 0; i < rows.length; i++) values.add(context.getValue(rows[i]));
|
|
186
231
|
return values.size;
|
|
187
232
|
} });
|
|
188
233
|
/** Counts rows, independently of the column's values. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aggregationFns.cjs","names":["constructAggregationFn"],"sources":["../../../src/features/row-aggregation/aggregationFns.ts"],"sourcesContent":["import { constructAggregationFn } from './rowAggregationFeature.types'\nimport type { AggregationContext } from './rowAggregationFeature.types'\n\ntype RangeValue = Date | number\n\nfunction isNumber(value: unknown): value is number {\n return typeof value === 'number'\n}\n\nfunction isValidDate(value: unknown): value is Date {\n return value instanceof Date && !Number.isNaN(value.getTime())\n}\n\nfunction getRangeKind(value: unknown): 'date' | 'number' | undefined {\n if (isNumber(value)) return 'number'\n if (isValidDate(value)) return 'date'\n return undefined\n}\n\nfunction compareRangeValues(left: RangeValue, right: RangeValue) {\n const leftValue = left instanceof Date ? left.getTime() : left\n const rightValue = right instanceof Date ? right.getTime() : right\n return leftValue - rightValue\n}\n\nfunction collectRangeValues(context: AggregationContext<any, any, unknown>) {\n const values: Array<RangeValue> = []\n let kind: 'date' | 'number' | undefined\n\n for (let i = 0; i < context.rows.length; i++) {\n const value = context.getValue(context.rows[i]!)\n const valueKind = getRangeKind(value)\n if (!valueKind) continue\n kind ??= valueKind\n if (valueKind === kind) values.push(value as RangeValue)\n }\n\n return values\n}\n\n/**\n * Sums numeric selected-row values. Non-number values contribute zero. As in\n * the previous API, `NaN` is a number and therefore propagates through the sum.\n */\nexport const aggregationFn_sum = constructAggregationFn<\n any,\n any,\n unknown,\n number\n>({\n aggregate: (context) => {\n let sum = 0\n for (let i = 0; i < context.rows.length; i++) {\n const value = context.getValue(context.rows[i]!)\n sum += typeof value === 'number' ? value : 0\n }\n return sum\n },\n merge: ({ subRowResults }) => {\n let sum = 0\n for (let i = 0; i < subRowResults.length; i++) {\n const value = subRowResults[i]\n if (isNumber(value)) sum += value\n }\n return sum\n },\n})\n\n/**\n * Finds the minimum numeric or Date value from the selected rows. Invalid value\n * types are ignored; `NaN` preserves the legacy numeric seeding behavior.\n */\nexport const aggregationFn_min = constructAggregationFn<\n any,\n any,\n unknown,\n RangeValue | undefined\n>({\n aggregate: (context) => {\n const values = collectRangeValues(context)\n let result = values[0]\n for (let i = 1; i < values.length; i++) {\n if (compareRangeValues(values[i]!, result!) < 0) result = values[i]\n }\n return result\n },\n merge: ({ subRowResults }) => {\n let result: RangeValue | undefined\n let kind: 'date' | 'number' | undefined\n for (let i = 0; i < subRowResults.length; i++) {\n const value = subRowResults[i]\n const valueKind = getRangeKind(value)\n if (!valueKind) continue\n if (value === undefined) continue\n kind ??= valueKind\n if (kind !== valueKind) continue\n if (result === undefined || compareRangeValues(value, result) < 0) {\n result = value\n }\n }\n return result\n },\n})\n\n/**\n * Finds the maximum numeric or Date value from the selected rows. Invalid value\n * types are ignored; `NaN` preserves the legacy numeric seeding behavior.\n */\nexport const aggregationFn_max = constructAggregationFn<\n any,\n any,\n unknown,\n RangeValue | undefined\n>({\n aggregate: (context) => {\n const values = collectRangeValues(context)\n let result = values[0]\n for (let i = 1; i < values.length; i++) {\n if (compareRangeValues(values[i]!, result!) > 0) result = values[i]\n }\n return result\n },\n merge: ({ subRowResults }) => {\n let result: RangeValue | undefined\n let kind: 'date' | 'number' | undefined\n for (let i = 0; i < subRowResults.length; i++) {\n const value = subRowResults[i]\n const valueKind = getRangeKind(value)\n if (!valueKind) continue\n if (value === undefined) continue\n kind ??= valueKind\n if (kind !== valueKind) continue\n if (result === undefined || compareRangeValues(value, result) > 0) {\n result = value\n }\n }\n return result\n },\n})\n\n/**\n * Finds the minimum and maximum numeric or Date values from the selected rows.\n * Empty inputs return\n * `[undefined, undefined]`, preserving the previous built-in result shape.\n */\nexport const aggregationFn_extent = constructAggregationFn<\n any,\n any,\n unknown,\n [RangeValue | undefined, RangeValue | undefined]\n>({\n aggregate: (context) => {\n const values = collectRangeValues(context)\n if (!values.length) return [undefined, undefined]\n let min = values[0]!\n let max = values[0]!\n for (let i = 1; i < values.length; i++) {\n const value = values[i]!\n if (compareRangeValues(value, min) < 0) min = value\n if (compareRangeValues(value, max) > 0) max = value\n }\n return [min, max]\n },\n merge: ({ subRowResults }) => {\n let result: [RangeValue | undefined, RangeValue | undefined] = [\n undefined,\n undefined,\n ]\n let kind: 'date' | 'number' | undefined\n for (let i = 0; i < subRowResults.length; i++) {\n const extent = subRowResults[i]!\n const min = extent[0]\n const max = extent[1]\n const valueKind = getRangeKind(min)\n if (!valueKind || min === undefined || max === undefined) continue\n kind ??= valueKind\n if (kind !== valueKind) continue\n if (result[0] === undefined) {\n result = [min, max]\n } else {\n if (compareRangeValues(min, result[0]) < 0) {\n result[0] = min\n }\n const currentMax = result[1]\n if (\n currentMax === undefined ||\n compareRangeValues(max, currentMax) > 0\n ) {\n result[1] = max\n }\n }\n }\n return result\n },\n})\n\n/**\n * Averages number and number-like row values. Nullish and non-numeric values\n * are ignored; other values retain the legacy unary-plus coercion behavior.\n */\nexport const aggregationFn_mean = constructAggregationFn<\n any,\n any,\n unknown,\n number | undefined\n>({\n aggregate: (context) => {\n let count = 0\n let sum = 0\n for (let i = 0; i < context.rows.length; i++) {\n const value = context.getValue(context.rows[i]!)\n if (value == null) continue\n const numberValue = typeof value === 'number' ? value : +value\n if (!Number.isNaN(numberValue)) {\n count++\n sum += numberValue\n }\n }\n return count ? sum / count : undefined\n },\n})\n\n/**\n * Computes the median when every row value is a number. Returns `undefined`\n * for empty inputs or when any value is non-numeric.\n */\nexport const aggregationFn_median = constructAggregationFn<\n any,\n any,\n unknown,\n number | undefined\n>({\n aggregate: (context) => {\n if (!context.rows.length) return undefined\n const values = new Array<number>(context.rows.length)\n for (let i = 0; i < context.rows.length; i++) {\n const value = context.getValue(context.rows[i]!)\n if (typeof value !== 'number') return undefined\n values[i] = value\n }\n values.sort((a, b) => a - b)\n const mid = Math.floor(values.length / 2)\n return values.length % 2\n ? values[mid]\n : (values[mid - 1]! + values[mid]!) / 2\n },\n})\n\n/** Collects distinct row values using JavaScript `Set` semantics. */\nexport const aggregationFn_unique = constructAggregationFn<\n any,\n any,\n unknown,\n Array<unknown>\n>({\n aggregate: (context) => {\n const values = new Set<unknown>()\n for (let i = 0; i < context.rows.length; i++) {\n values.add(context.getValue(context.rows[i]!))\n }\n return Array.from(values)\n },\n})\n\n/** Counts distinct row values using JavaScript `Set` semantics. */\nexport const aggregationFn_uniqueCount = constructAggregationFn<\n any,\n any,\n unknown,\n number\n>({\n aggregate: (context) => {\n const values = new Set<unknown>()\n for (let i = 0; i < context.rows.length; i++) {\n values.add(context.getValue(context.rows[i]!))\n }\n return values.size\n },\n})\n\n/** Counts rows, independently of the column's values. */\nexport const aggregationFn_count = constructAggregationFn<\n any,\n any,\n unknown,\n number\n>({\n aggregate: ({ rows }) => rows.length,\n merge: ({ subRowResults }) => {\n let count = 0\n for (let i = 0; i < subRowResults.length; i++) {\n const value = subRowResults[i]\n if (isNumber(value)) count += value\n }\n return count\n },\n})\n\n/** Returns the first row's value, including a nullish value. */\nexport const aggregationFn_first = constructAggregationFn<\n any,\n any,\n unknown,\n unknown\n>({\n aggregate: (context) =>\n context.rows[0] ? context.getValue(context.rows[0]) : undefined,\n merge: ({ subRowResults }) => subRowResults[0],\n})\n\n/** Returns the last row's value, including a nullish value. */\nexport const aggregationFn_last = constructAggregationFn<\n any,\n any,\n unknown,\n unknown\n>({\n aggregate: (context) => {\n const row = context.rows[context.rows.length - 1]\n return row ? context.getValue(row) : undefined\n },\n merge: ({ subRowResults }) => subRowResults[subRowResults.length - 1],\n})\n\n/**\n * Full built-in registry. Register individual definitions for tree-shaking.\n *\n * @deprecated Import individual `aggregationFn_*` definitions instead for a\n * smaller bundle. This registry remains available for compatibility.\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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"}
|
|
1
|
+
{"version":3,"file":"aggregationFns.cjs","names":["constructAggregationFn"],"sources":["../../../src/features/row-aggregation/aggregationFns.ts"],"sourcesContent":["import { constructAggregationFn } from './rowAggregationFeature.types'\n\ntype RangeValue = Date | number\n\nfunction isNumber(value: unknown): value is number {\n return typeof value === 'number'\n}\n\nfunction isValidDate(value: unknown): value is Date {\n return value instanceof Date && !Number.isNaN(value.getTime())\n}\n\nfunction getRangeKind(value: unknown): 'date' | 'number' | undefined {\n if (isNumber(value)) return 'number'\n if (isValidDate(value)) return 'date'\n return undefined\n}\n\nfunction compareRangeValues(left: RangeValue, right: RangeValue) {\n const leftValue = left instanceof Date ? left.getTime() : left\n const rightValue = right instanceof Date ? right.getTime() : right\n return leftValue - rightValue\n}\n\n/** Comparable representation of a range value; `Date`s compare by time. */\nfunction toRangeNumber(value: RangeValue): number {\n return value instanceof Date ? value.getTime() : value\n}\n\n/**\n * Sums numeric selected-row values. Non-number values contribute zero. As in\n * the previous API, `NaN` is a number and therefore propagates through the sum.\n */\nexport const aggregationFn_sum = constructAggregationFn<\n any,\n any,\n unknown,\n number\n>({\n aggregate: (context) => {\n const rows = context.rows\n let sum = 0\n for (let i = 0; i < rows.length; i++) {\n const value = context.getValue(rows[i]!)\n sum += typeof value === 'number' ? value : 0\n }\n return sum\n },\n merge: ({ subRowResults }) => {\n let sum = 0\n for (let i = 0; i < subRowResults.length; i++) {\n const value = subRowResults[i]\n if (isNumber(value)) sum += value\n }\n return sum\n },\n})\n\n/**\n * Finds the minimum numeric or Date value from the selected rows. Invalid value\n * types are ignored; `NaN` preserves the legacy numeric seeding behavior.\n */\nexport const aggregationFn_min = constructAggregationFn<\n any,\n any,\n unknown,\n RangeValue | undefined\n>({\n aggregate: (context) => {\n const rows = context.rows\n let kind: 'date' | 'number' | undefined\n let result: RangeValue | undefined\n let resultNumber = 0\n for (let i = 0; i < rows.length; i++) {\n const value = context.getValue(rows[i]!)\n const valueKind = getRangeKind(value)\n if (!valueKind || (kind !== undefined && valueKind !== kind)) continue\n const valueNumber = toRangeNumber(value as RangeValue)\n if (kind === undefined) {\n kind = valueKind\n result = value as RangeValue\n resultNumber = valueNumber\n } else if (valueNumber - resultNumber < 0) {\n result = value as RangeValue\n resultNumber = valueNumber\n }\n }\n return result\n },\n merge: ({ subRowResults }) => {\n let result: RangeValue | undefined\n let kind: 'date' | 'number' | undefined\n for (let i = 0; i < subRowResults.length; i++) {\n const value = subRowResults[i]\n const valueKind = getRangeKind(value)\n if (!valueKind) continue\n if (value === undefined) continue\n kind ??= valueKind\n if (kind !== valueKind) continue\n if (result === undefined || compareRangeValues(value, result) < 0) {\n result = value\n }\n }\n return result\n },\n})\n\n/**\n * Finds the maximum numeric or Date value from the selected rows. Invalid value\n * types are ignored; `NaN` preserves the legacy numeric seeding behavior.\n */\nexport const aggregationFn_max = constructAggregationFn<\n any,\n any,\n unknown,\n RangeValue | undefined\n>({\n aggregate: (context) => {\n const rows = context.rows\n let kind: 'date' | 'number' | undefined\n let result: RangeValue | undefined\n let resultNumber = 0\n for (let i = 0; i < rows.length; i++) {\n const value = context.getValue(rows[i]!)\n const valueKind = getRangeKind(value)\n if (!valueKind || (kind !== undefined && valueKind !== kind)) continue\n const valueNumber = toRangeNumber(value as RangeValue)\n if (kind === undefined) {\n kind = valueKind\n result = value as RangeValue\n resultNumber = valueNumber\n } else if (valueNumber - resultNumber > 0) {\n result = value as RangeValue\n resultNumber = valueNumber\n }\n }\n return result\n },\n merge: ({ subRowResults }) => {\n let result: RangeValue | undefined\n let kind: 'date' | 'number' | undefined\n for (let i = 0; i < subRowResults.length; i++) {\n const value = subRowResults[i]\n const valueKind = getRangeKind(value)\n if (!valueKind) continue\n if (value === undefined) continue\n kind ??= valueKind\n if (kind !== valueKind) continue\n if (result === undefined || compareRangeValues(value, result) > 0) {\n result = value\n }\n }\n return result\n },\n})\n\n/**\n * Finds the minimum and maximum numeric or Date values from the selected rows.\n * Empty inputs return\n * `[undefined, undefined]`, preserving the previous built-in result shape.\n */\nexport const aggregationFn_extent = constructAggregationFn<\n any,\n any,\n unknown,\n [RangeValue | undefined, RangeValue | undefined]\n>({\n aggregate: (context) => {\n const rows = context.rows\n let kind: 'date' | 'number' | undefined\n let min: RangeValue | undefined\n let max: RangeValue | undefined\n let minNumber = 0\n let maxNumber = 0\n for (let i = 0; i < rows.length; i++) {\n const value = context.getValue(rows[i]!)\n const valueKind = getRangeKind(value)\n if (!valueKind || (kind !== undefined && valueKind !== kind)) continue\n const valueNumber = toRangeNumber(value as RangeValue)\n if (kind === undefined) {\n kind = valueKind\n min = max = value as RangeValue\n minNumber = maxNumber = valueNumber\n } else {\n if (valueNumber - minNumber < 0) {\n min = value as RangeValue\n minNumber = valueNumber\n }\n if (valueNumber - maxNumber > 0) {\n max = value as RangeValue\n maxNumber = valueNumber\n }\n }\n }\n if (kind === undefined) return [undefined, undefined]\n return [min, max]\n },\n merge: ({ subRowResults }) => {\n let result: [RangeValue | undefined, RangeValue | undefined] = [\n undefined,\n undefined,\n ]\n let kind: 'date' | 'number' | undefined\n for (let i = 0; i < subRowResults.length; i++) {\n const extent = subRowResults[i]!\n const min = extent[0]\n const max = extent[1]\n const valueKind = getRangeKind(min)\n if (!valueKind || min === undefined || max === undefined) continue\n kind ??= valueKind\n if (kind !== valueKind) continue\n if (result[0] === undefined) {\n result = [min, max]\n } else {\n if (compareRangeValues(min, result[0]) < 0) {\n result[0] = min\n }\n const currentMax = result[1]\n if (\n currentMax === undefined ||\n compareRangeValues(max, currentMax) > 0\n ) {\n result[1] = max\n }\n }\n }\n return result\n },\n})\n\n/**\n * Averages number and number-like row values. Nullish and non-numeric values\n * are ignored; other values retain the legacy unary-plus coercion behavior.\n */\nexport const aggregationFn_mean = constructAggregationFn<\n any,\n any,\n unknown,\n number | undefined\n>({\n aggregate: (context) => {\n const rows = context.rows\n let count = 0\n let sum = 0\n for (let i = 0; i < rows.length; i++) {\n const value = context.getValue(rows[i]!)\n if (value == null) continue\n const numberValue = typeof value === 'number' ? value : +value\n if (!Number.isNaN(numberValue)) {\n count++\n sum += numberValue\n }\n }\n return count ? sum / count : undefined\n },\n})\n\n/**\n * Computes the median when every row value is a number. Returns `undefined`\n * for empty inputs or when any value is non-numeric.\n */\nexport const aggregationFn_median = constructAggregationFn<\n any,\n any,\n unknown,\n number | undefined\n>({\n aggregate: (context) => {\n const rows = context.rows\n if (!rows.length) return undefined\n const values = new Array<number>(rows.length)\n for (let i = 0; i < rows.length; i++) {\n const value = context.getValue(rows[i]!)\n if (typeof value !== 'number') return undefined\n values[i] = value\n }\n values.sort((a, b) => a - b)\n const mid = Math.floor(values.length / 2)\n return values.length % 2\n ? values[mid]\n : (values[mid - 1]! + values[mid]!) / 2\n },\n})\n\n/** Collects distinct row values using JavaScript `Set` semantics. */\nexport const aggregationFn_unique = constructAggregationFn<\n any,\n any,\n unknown,\n Array<unknown>\n>({\n aggregate: (context) => {\n const rows = context.rows\n const values = new Set<unknown>()\n for (let i = 0; i < rows.length; i++) {\n values.add(context.getValue(rows[i]!))\n }\n return Array.from(values)\n },\n})\n\n/** Counts distinct row values using JavaScript `Set` semantics. */\nexport const aggregationFn_uniqueCount = constructAggregationFn<\n any,\n any,\n unknown,\n number\n>({\n aggregate: (context) => {\n const rows = context.rows\n const values = new Set<unknown>()\n for (let i = 0; i < rows.length; i++) {\n values.add(context.getValue(rows[i]!))\n }\n return values.size\n },\n})\n\n/** Counts rows, independently of the column's values. */\nexport const aggregationFn_count = constructAggregationFn<\n any,\n any,\n unknown,\n number\n>({\n aggregate: ({ rows }) => rows.length,\n merge: ({ subRowResults }) => {\n let count = 0\n for (let i = 0; i < subRowResults.length; i++) {\n const value = subRowResults[i]\n if (isNumber(value)) count += value\n }\n return count\n },\n})\n\n/** Returns the first row's value, including a nullish value. */\nexport const aggregationFn_first = constructAggregationFn<\n any,\n any,\n unknown,\n unknown\n>({\n aggregate: (context) =>\n context.rows[0] ? context.getValue(context.rows[0]) : undefined,\n merge: ({ subRowResults }) => subRowResults[0],\n})\n\n/** Returns the last row's value, including a nullish value. */\nexport const aggregationFn_last = constructAggregationFn<\n any,\n any,\n unknown,\n unknown\n>({\n aggregate: (context) => {\n const row = context.rows[context.rows.length - 1]\n return row ? context.getValue(row) : undefined\n },\n merge: ({ subRowResults }) => subRowResults[subRowResults.length - 1],\n})\n\n/**\n * Full built-in registry. Register individual definitions for tree-shaking.\n *\n * @deprecated Import individual `aggregationFn_*` definitions instead for a\n * smaller bundle. This registry remains available for compatibility.\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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"}
|