UNPKG

datamodel

Version:

Relational algebra compliant in-memory tabular data store

142 lines (131 loc) 4.89 kB
import { extend2 } from '../utils'; import { rowDiffsetIterator } from './row-diffset-iterator'; import DataModel from '../export'; import reducerStore from '../utils/reducer-store'; import { defaultReducerName } from './group-by-function'; import { FieldType } from '../enums'; /** * This function sanitize the user given field and return a common Array structure field * list * @param {DataModel} dataModel the dataModel operating on * @param {Array} fieldArr user input of field Array * @return {Array} arrays of field name */ function getFieldArr (dataModel, fieldArr) { const retArr = []; const fieldStore = dataModel.getFieldspace(); const dimensions = fieldStore.getDimension(); Object.entries(dimensions).forEach(([key]) => { if (fieldArr && fieldArr.length) { if (fieldArr.indexOf(key) !== -1) { retArr.push(key); } } else { retArr.push(key); } }); return retArr; } /** * This sanitize the reducer provide by the user and create a common type of object. * user can give function Also * @param {DataModel} dataModel dataModel to worked on * @param {Object|function} [reducers={}] reducer provided by the users * @return {Object} object containing reducer function for every measure */ function getReducerObj (dataModel, reducers = {}) { const retObj = {}; const fieldStore = dataModel.getFieldspace(); const measures = fieldStore.getMeasure(); const defReducer = reducerStore.defaultReducer(); Object.keys(measures).forEach((measureName) => { if (typeof reducers[measureName] !== 'string') { reducers[measureName] = measures[measureName].defAggFn(); } const reducerFn = reducerStore.resolve(reducers[measureName]); if (reducerFn) { retObj[measureName] = reducerFn; } else { retObj[measureName] = defReducer; reducers[measureName] = defaultReducerName; } }); return retObj; } /** * main function which perform the group-by operations which reduce the measures value is the * fields are common according to the reducer function provided * @param {DataModel} dataModel the dataModel to worked * @param {Array} fieldArr fields according to which the groupby should be worked * @param {Object|Function} reducers reducers function * @param {DataModel} existingDataModel Existing datamodel instance * @return {DataModel} new dataModel with the group by */ function groupBy (dataModel, fieldArr, reducers, existingDataModel) { const sFieldArr = getFieldArr(dataModel, fieldArr); const reducerObj = getReducerObj(dataModel, reducers); const fieldStore = dataModel.getFieldspace(); const fieldStoreObj = fieldStore.fieldsObj(); const dbName = fieldStore.name; const dimensionArr = []; const measureArr = []; const schema = []; const hashMap = {}; const data = []; let newDataModel; // Prepare the schema Object.entries(fieldStoreObj).forEach(([key, value]) => { if (sFieldArr.indexOf(key) !== -1 || reducerObj[key]) { schema.push(extend2({}, value.schema())); switch (value.schema().type) { case FieldType.MEASURE: measureArr.push(key); break; default: case FieldType.DIMENSION: dimensionArr.push(key); } } }); // Prepare the data let rowCount = 0; rowDiffsetIterator(dataModel._rowDiffset, (i) => { let hash = ''; dimensionArr.forEach((_) => { hash = `${hash}-${fieldStoreObj[_].partialField.data[i]}`; }); if (hashMap[hash] === undefined) { hashMap[hash] = rowCount; data.push({}); dimensionArr.forEach((_) => { data[rowCount][_] = fieldStoreObj[_].partialField.data[i]; }); measureArr.forEach((_) => { data[rowCount][_] = [fieldStoreObj[_].partialField.data[i]]; }); rowCount += 1; } else { measureArr.forEach((_) => { data[hashMap[hash]][_].push(fieldStoreObj[_].partialField.data[i]); }); } }); // reduction let cachedStore = {}; let cloneProvider = () => dataModel.detachedRoot(); data.forEach((row) => { const tuple = row; measureArr.forEach((_) => { tuple[_] = reducerObj[_](row[_], cloneProvider, cachedStore); }); }); if (existingDataModel) { existingDataModel.__calculateFieldspace(); newDataModel = existingDataModel; } else { newDataModel = new DataModel(data, schema, { name: dbName }); } return newDataModel; } export { groupBy, getFieldArr, getReducerObj };