@adaptabletools/adaptable
Version:
Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
101 lines (100 loc) • 3.58 kB
JavaScript
import { DeepMap } from './deepMap';
function DEFAULT_TO_KEY(value) {
return value;
}
export function group(groupParams, data) {
const { groupBy, defaultToKey = DEFAULT_TO_KEY, reducers } = groupParams;
const groupByLength = groupBy.length;
const deepMap = new DeepMap();
let currentGroupKeys = [];
const initialReducerValue = initReducers(reducers);
const globalReducerResults = { ...initialReducerValue };
for (let i = 0, len = data.length; i < len; i++) {
let item = data[i];
for (let groupByIndex = 0; groupByIndex < groupByLength; groupByIndex++) {
const { field: groupByProperty, toKey: groupToKey } = groupBy[groupByIndex];
const key = (groupToKey || defaultToKey)(item[groupByProperty], item);
currentGroupKeys.push(key);
if (!deepMap.has(currentGroupKeys)) {
const deepMapGroupValue = {
items: [],
reducerResults: { ...initialReducerValue },
};
deepMap.set(currentGroupKeys, deepMapGroupValue);
}
const { items: currentGroupItems, reducerResults } = deepMap.get(currentGroupKeys);
currentGroupItems.push(item);
if (reducers) {
computeReducersFor(item, reducers, reducerResults);
}
}
if (reducers) {
computeReducersFor(item, reducers, globalReducerResults);
}
currentGroupKeys.length = 0;
}
const hasReducersWithDoneFn = reducers && Object.values(reducers).some((reducer) => reducer.done);
if (hasReducersWithDoneFn) {
deepMap.visitDepthFirst((deepMapValue, _keys, _indexInGroup, next) => {
completeReducers(reducers, deepMapValue.reducerResults, deepMapValue.items);
next?.();
});
}
if (hasReducersWithDoneFn) {
completeReducers(reducers, globalReducerResults, data);
}
const result = {
deepMap,
groupParams,
initialData: data,
reducerResults: globalReducerResults,
};
return result;
}
function initReducers(reducers) {
if (!reducers || !Object.keys(reducers).length) {
return {};
}
const result = {};
for (let key in reducers)
if (reducers.hasOwnProperty(key)) {
result[key] = reducers[key].initialValue;
}
return result;
}
/**
*
* This fn mutates the reducerResults array!!!
*
* @param data data item
* @param reducers an array of reducers
* @param reducerResults the results on which to operate
*
*/
function computeReducersFor(data, reducers, reducerResults) {
if (!reducers || !Object.keys(reducers).length) {
return;
}
for (let key in reducers)
if (reducers.hasOwnProperty(key)) {
const reducer = reducers[key];
if (typeof reducer.reducer !== 'function') {
continue;
}
const currentValue = reducerResults[key];
const value = reducer.field ? data[reducer.field] : reducer.getter?.(data) ?? null;
reducerResults[key] = reducer.reducer(currentValue, value, data);
}
}
function completeReducers(reducers, reducerResults, items) {
if (reducers) {
for (let key in reducers)
if (reducers.hasOwnProperty(key)) {
const reducer = reducers[key];
if (reducer.done) {
reducerResults[key] = reducer.done(reducerResults[key], items);
}
}
}
return reducerResults;
}