Skip to content

Commit

Permalink
Merge pull request #76 from TomMuijsers/feature/column-sort
Browse files Browse the repository at this point in the history
Added column sort.
  • Loading branch information
pat310 committed Mar 15, 2019
2 parents eb9ad8f + 8b4bb2c commit 7c2f395
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 10 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ The `data` value returns an object with keys `table` and `rawData`. `table` is
```js
import Pivot from 'quick-pivot';

const pivot = new Pivot(dataArray, rows, columns, [aggregationDimension or CBfunction], [aggregator or initialValue], rowHeader, sortFunction);
const pivot = new Pivot(dataArray, rows, columns, [aggregationDimension or CBfunction], [aggregator or initialValue], rowHeader, sortFunction, columnSortFunction);
```

#### First way to use it:
Expand All @@ -173,6 +173,9 @@ const pivot = new Pivot(dataArray, rows, columns, [aggregationDimension or CBfun
* Sort Function should be in the form `(row) => (a,b) => Number`. This Function will be called for each row pivoted on (right to left) and must return
a traditional Array.sort function as a result.
A Function equaling `() => {}` will direct the Pivot to skip the sorting phase.
* `columnSortFunction` is a custom sorting function for columns. No sorting used if undefined
* Column Sort Function should be in the form `(data, columns, columnIndex) => (a,b) => Number`. This Function will be called for each column pivoted on and must return
a traditional Array.sort function as a result.

#### Second way to use it:
Parameters are the same as the first except for two, `aggregationDimension` and `aggregator`. Instead of `aggregationDimension` and `aggregator`, you can use the following:
Expand Down
49 changes: 44 additions & 5 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,24 @@ export default class Pivot {
* @param {string} type Aggregation type, enumerated value
* @param {string} header Table header (displayed at hte top left)
* @param {Function} custom sort function. will skip sort stage if equal to () => {}
* @param {Function} columnSortFunc custom sort function for the columns
* @returns {Object} instantiated pivot object
*/
constructor(data, rows, cols, agg, type, header, sortFunc) {
constructor(data, rows, cols, agg, type, header, sortFunc, columnSortFunc) {
if (!data) this.originalData = {};
else {
data = fixDataFormat(data, rows, sortFunc);
this.columnSortFunc = columnSortFunc;
this.originalArgs = {data, rows, cols, agg, type, header};
this.originalData = tableCreator(data, rows, cols, agg, type, header);
this.originalData = tableCreator(
data,
rows,
cols,
agg,
type,
header,
this.columnSortFunc
);
this.uniqueValues = createUniqueValues(data);
}

Expand All @@ -41,17 +51,37 @@ export default class Pivot {
* @param {string} header Table header (displayed at hte top left)
* @param {boolean} isFiltering If the method is being called by the filter method
* @param {Function} custom sort function. will skip sort stage if equal to () => {}
* @param {Function} columnSortFunc custom sort function for the columns
* @returns {Object} instantiated pivot object
*/
update(data, rows, cols, agg, type, header, isFiltering, sortFunc) {
update(
data,
rows,
cols,
agg,
type,
header,
isFiltering,
sortFunc,
columnSortFunc
) {
data = fixDataFormat(data, rows, sortFunc);
/** if update isn't being used by filter, need to reset the original arguments */
if (!isFiltering) {
this.originalArgs = {data, rows, cols, agg, type, header};
this.uniqueValues = createUniqueValues(data);
}

this.originalData = tableCreator(data, rows, cols, agg, type, header);
this.columnSortFunc = columnSortFunc;
this.originalData = tableCreator(
data,
rows,
cols,
agg,
type,
header,
this.columnSortFunc
);
this.data = this.originalData;
this.originalArgs.data = data;
this.collapsedRows = {};
Expand Down Expand Up @@ -192,7 +222,16 @@ export default class Pivot {
});

/** update the pivot table with the new filtered data */
this.update(filteredData, rows, cols, agg, type, header, true);
this.update(
filteredData,
rows,
cols,
agg,
type,
header,
true,
this.columnSortFunc
);

/**
* set a pointer to end of table length
Expand Down
14 changes: 10 additions & 4 deletions src/logic.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,15 @@ export function groupByCategories(data, groups = [], acc = {}) {
* @param {!Array<Object>} data Array of objects
* @param {Array} cols Columns to pivot on
* @param {string} firstColumn A string to place in the first column header
* @param {Function} columnSortFunc A sort function to sort the column headers
* @returns {Object} columnHeaders (array of arrays) and mapToHeader (object)
*/
export function createColumnHeaders(data, cols = [], firstColumn = '') {
export function createColumnHeaders(
data,
cols = [],
firstColumn = '',
columnSortFunc = () => () => {}
) {
if (cols.length === 0) {
return {
columnHeaders: [firstColumn],
Expand All @@ -124,7 +130,7 @@ export function createColumnHeaders(data, cols = [], firstColumn = '') {
/** base case - at actual data as opposed to another grouping */
if (typeof data !== 'object' || Array.isArray(data)) return 1;

const currKeys = Object.keys(data);
const currKeys = Object.keys(data).sort(columnSortFunc(data, cols, pos));
let sumLength = 0;

for (let i = 0; i < currKeys.length; i++) {
Expand Down Expand Up @@ -229,7 +235,7 @@ export function checkPivotCategories(actualCats, selectedCats) {
}

export function tableCreator(data, rows = [], cols = [], accCatOrCB,
accTypeOrInitVal, rowHeader) {
accTypeOrInitVal, rowHeader, columnSortFunc) {

/** if data is empty, return empty array */
if (data.length === 0) {
Expand All @@ -253,7 +259,7 @@ export function tableCreator(data, rows = [], cols = [], accCatOrCB,
'Custom Agg';
}

const columnData = createColumnHeaders(data, cols, rowHeader);
const columnData = createColumnHeaders(data, cols, rowHeader, columnSortFunc);
const columnHeaders = Array.isArray(columnData.columnHeaders[0]) ?
columnData.columnHeaders :
[columnData.columnHeaders.concat(rowHeader)];
Expand Down
71 changes: 71 additions & 0 deletions test/index/constructor.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,75 @@ export default () => {

expect(pivot.data.table).to.have.length.above(0);
});

it('should create a pivot with sorted columns when passed data', () => {
const expected = [
{ value: [ 'sum age', 'Baratheon', 'Lannister', 'Stark', 'Totals' ],
depth: 0,
type: 'colHeader',
row: 0,
},
{ value: [ 'f', 38, '', 22, '' ], depth: 0, type: 'rowHeader', row: 1 },
{ value: [ 'Arya', '', '', 10, 10 ], type: 'data', depth: 1, row: 2 },
{ value: [ 'Cersei', 38, '', '', 38 ], type: 'data', depth: 1, row: 3 },
{ value: [ 'Sansa', '', '', 12, 12 ], type: 'data', depth: 1, row: 4 },
{ value: [ 'm', 18, 133, 22, '' ], depth: 0, type: 'rowHeader', row: 5 },
{ value: [ 'Bran', '', '', 8, 8 ], type: 'data', depth: 1, row: 6 },
{ value: [ 'Jaime', '', 32, '', 32 ], type: 'data', depth: 1, row: 7 },
{ value: [ 'Joffrey', 18, '', '', 18 ], type: 'data', depth: 1, row: 8 },
{ value: [ 'Jon', '', '', 14, 14 ], type: 'data', depth: 1, row: 9 },
{ value: [ 'Tyrion', '', 34, '', 34 ], type: 'data', depth: 1, row: 10 },
{ value: [ 'Tywin', '', 67, '', 67 ], type: 'data', depth: 1, row: 11 },
{ type: 'aggregated', value: ['Totals', 56, 133, 44, ''] },
];

const pivot = new Pivot(
dataArray,
rowsToPivotTestOne,
colsToPivotTestOne,
aggregationCategory,
aggregationType,
undefined,
undefined,
(data, cols, pos) => (a, b) => a < b ? -1 : 1
);

expect(pivot.data.table).to.deep.equal(expected);
});

it('should create a pivot with reverse sorted columns when passed data',
() => {
const expected = [
{ value: [ 'sum age', 'Stark', 'Lannister', 'Baratheon', 'Totals' ],
depth: 0,
type: 'colHeader',
row: 0,
},
{ value: [ 'f', 22, '', 38, '' ], depth: 0, type: 'rowHeader', row: 1 },
{ value: [ 'Arya', 10, '', '', 10 ], type: 'data', depth: 1, row: 2 },
{ value: [ 'Cersei', '', '', 38, 38 ], type: 'data', depth: 1, row: 3 },
{ value: [ 'Sansa', 12, '', '', 12 ], type: 'data', depth: 1, row: 4 },
{ value: [ 'm', 22, 133, 18, '' ], depth: 0, type: 'rowHeader', row: 5 },
{ value: [ 'Bran', 8, '', '', 8 ], type: 'data', depth: 1, row: 6 },
{ value: [ 'Jaime', '', 32, '', 32 ], type: 'data', depth: 1, row: 7 },
{ value: [ 'Joffrey', '', '', 18, 18 ], type: 'data', depth: 1, row: 8 },
{ value: [ 'Jon', 14, '', '', 14 ], type: 'data', depth: 1, row: 9 },
{ value: [ 'Tyrion', '', 34, '', 34 ], type: 'data', depth: 1, row: 10 },
{ value: [ 'Tywin', '', 67, '', 67 ], type: 'data', depth: 1, row: 11 },
{ type: 'aggregated', value: ['Totals', 44, 133, 56, ''] },
];

const pivot = new Pivot(
dataArray,
rowsToPivotTestOne,
colsToPivotTestOne,
aggregationCategory,
aggregationType,
undefined,
undefined,
(data, cols, pos) => (a, b) => a < b ? 1 : -1
);

expect(pivot.data.table).to.deep.equal(expected);
});
};

0 comments on commit 7c2f395

Please sign in to comment.