dtable-utils 0.0.1 → 0.0.3-beta.1

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 (150) hide show
  1. package/README.md +30 -2
  2. package/dist/index.js +1 -1
  3. package/es/cell-value-get/cell-value.js +227 -19
  4. package/es/cell-value-get/collaborator.js +9 -3
  5. package/es/cell-value-get/digital-sign.js +1 -1
  6. package/es/cell-value-get/geolocation.js +41 -10
  7. package/es/cell-value-get/long-text.js +1 -1
  8. package/es/cell-value-get/number.js +42 -18
  9. package/es/cell-value-get/option.js +17 -7
  10. package/es/cell-value-get/rate.js +6 -0
  11. package/es/cell-value-set/date.js +20 -0
  12. package/es/cell-value-set/number.js +53 -1
  13. package/es/color/gradient-color.js +100 -0
  14. package/es/column/color.js +415 -0
  15. package/es/column/{common.js → core.js} +3 -15
  16. package/es/column/date.js +2 -3
  17. package/es/column/number.js +3 -5
  18. package/es/column/option.js +115 -0
  19. package/es/common.js +10 -1
  20. package/es/constants/color.js +16 -0
  21. package/es/constants/column-permission.js +7 -0
  22. package/es/constants/column.js +127 -2
  23. package/es/constants/filter/index.js +5 -1
  24. package/es/constants/grid-header.js +6 -0
  25. package/es/constants/group.js +23 -0
  26. package/es/constants/limit.js +3 -0
  27. package/es/constants/reg.js +4 -0
  28. package/es/constants/row-color.js +11 -0
  29. package/es/constants/sort.js +11 -0
  30. package/es/date.js +1 -1
  31. package/es/filter/core.js +287 -0
  32. package/es/filter/filter-column/array.js +82 -0
  33. package/es/filter/filter-column/checkbox.js +8 -0
  34. package/es/filter/filter-column/collaborator.js +67 -0
  35. package/es/filter/filter-column/creator.js +50 -0
  36. package/es/filter/filter-column/date.js +59 -0
  37. package/es/filter/filter-column/digital-sign.js +26 -0
  38. package/es/filter/filter-column/file.js +24 -0
  39. package/es/filter/filter-column/formula.js +49 -0
  40. package/es/filter/filter-column/geolocation.js +53 -0
  41. package/es/filter/filter-column/link.js +12 -0
  42. package/es/filter/filter-column/long-text.js +25 -0
  43. package/es/filter/filter-column/multiple-select.js +60 -0
  44. package/es/filter/filter-column/number.js +93 -0
  45. package/es/filter/filter-column/single-select.js +41 -0
  46. package/es/filter/filter-column/text.js +55 -0
  47. package/es/filter/filter-row.js +198 -0
  48. package/es/group/core.js +107 -0
  49. package/es/group/group-row.js +366 -0
  50. package/es/index.js +62 -10
  51. package/es/link/core.js +78 -0
  52. package/es/number.js +13 -0
  53. package/es/row/color.js +278 -0
  54. package/es/row/core.js +161 -0
  55. package/es/sort/core.js +32 -0
  56. package/es/sort/sort-column/array.js +63 -0
  57. package/es/sort/sort-column/checkbox.js +15 -0
  58. package/es/sort/sort-column/collaborator.js +9 -0
  59. package/es/sort/sort-column/date.js +25 -0
  60. package/es/sort/sort-column/formula.js +40 -0
  61. package/es/sort/sort-column/link.js +23 -0
  62. package/es/sort/sort-column/multiple-select.js +45 -0
  63. package/es/sort/sort-column/number.js +18 -0
  64. package/es/sort/sort-column/single-select.js +22 -0
  65. package/es/sort/sort-column/text.js +47 -0
  66. package/es/sort/sort-row.js +126 -0
  67. package/es/table/column.js +27 -0
  68. package/es/table/core.js +14 -0
  69. package/es/table/index.js +14 -0
  70. package/es/table/row.js +25 -0
  71. package/es/validate/filter.js +1 -1
  72. package/es/validate/geolocation.js +5 -0
  73. package/es/view/core.js +135 -0
  74. package/es/view/formula.js +143 -0
  75. package/es/view/group.js +32 -0
  76. package/es/view/summaries.js +179 -0
  77. package/lib/cell-value-get/cell-value.js +231 -18
  78. package/lib/cell-value-get/collaborator.js +9 -2
  79. package/lib/cell-value-get/digital-sign.js +1 -1
  80. package/lib/cell-value-get/geolocation.js +42 -10
  81. package/lib/cell-value-get/long-text.js +1 -1
  82. package/lib/cell-value-get/number.js +42 -17
  83. package/lib/cell-value-get/option.js +18 -6
  84. package/lib/cell-value-get/rate.js +10 -0
  85. package/lib/cell-value-set/date.js +24 -0
  86. package/lib/cell-value-set/number.js +53 -0
  87. package/lib/color/gradient-color.js +110 -0
  88. package/lib/column/color.js +424 -0
  89. package/lib/column/{common.js → core.js} +3 -16
  90. package/lib/column/date.js +2 -3
  91. package/lib/column/number.js +3 -5
  92. package/lib/column/option.js +123 -0
  93. package/lib/common.js +14 -0
  94. package/lib/constants/color.js +20 -0
  95. package/lib/constants/column-permission.js +11 -0
  96. package/lib/constants/column.js +134 -1
  97. package/lib/constants/filter/index.js +5 -0
  98. package/lib/constants/grid-header.js +10 -0
  99. package/lib/constants/group.js +36 -0
  100. package/lib/constants/limit.js +7 -0
  101. package/lib/constants/reg.js +9 -0
  102. package/lib/constants/row-color.js +17 -0
  103. package/lib/constants/sort.js +18 -0
  104. package/lib/filter/core.js +301 -0
  105. package/lib/filter/filter-column/array.js +86 -0
  106. package/lib/filter/filter-column/checkbox.js +12 -0
  107. package/lib/filter/filter-column/collaborator.js +75 -0
  108. package/lib/filter/filter-column/creator.js +54 -0
  109. package/lib/filter/filter-column/date.js +63 -0
  110. package/lib/filter/filter-column/digital-sign.js +30 -0
  111. package/lib/filter/filter-column/file.js +28 -0
  112. package/lib/filter/filter-column/formula.js +53 -0
  113. package/lib/filter/filter-column/geolocation.js +57 -0
  114. package/lib/filter/filter-column/link.js +16 -0
  115. package/lib/filter/filter-column/long-text.js +29 -0
  116. package/lib/filter/filter-column/multiple-select.js +68 -0
  117. package/lib/filter/filter-column/number.js +97 -0
  118. package/lib/filter/filter-column/single-select.js +45 -0
  119. package/lib/filter/filter-column/text.js +59 -0
  120. package/lib/filter/filter-row.js +204 -0
  121. package/lib/group/core.js +117 -0
  122. package/lib/group/group-row.js +377 -0
  123. package/lib/index.js +176 -6
  124. package/lib/link/core.js +90 -0
  125. package/lib/number.js +18 -0
  126. package/lib/row/color.js +286 -0
  127. package/lib/row/core.js +170 -0
  128. package/lib/sort/core.js +37 -0
  129. package/lib/sort/sort-column/array.js +67 -0
  130. package/lib/sort/sort-column/checkbox.js +19 -0
  131. package/lib/sort/sort-column/collaborator.js +13 -0
  132. package/lib/sort/sort-column/date.js +29 -0
  133. package/lib/sort/sort-column/formula.js +44 -0
  134. package/lib/sort/sort-column/link.js +27 -0
  135. package/lib/sort/sort-column/multiple-select.js +50 -0
  136. package/lib/sort/sort-column/number.js +22 -0
  137. package/lib/sort/sort-column/single-select.js +26 -0
  138. package/lib/sort/sort-column/text.js +52 -0
  139. package/lib/sort/sort-row.js +136 -0
  140. package/lib/table/column.js +32 -0
  141. package/lib/table/core.js +18 -0
  142. package/lib/table/index.js +18 -0
  143. package/lib/table/row.js +30 -0
  144. package/lib/validate/filter.js +3 -3
  145. package/lib/validate/geolocation.js +9 -0
  146. package/lib/view/core.js +144 -0
  147. package/lib/view/formula.js +150 -0
  148. package/lib/view/group.js +36 -0
  149. package/lib/view/summaries.js +185 -0
  150. package/package.json +4 -2
@@ -0,0 +1,135 @@
1
+ import { getValidFilters, getValidFiltersWithoutError } from '../filter/core.js';
2
+ import { getValidGroupbys } from '../group/core.js';
3
+ import { getValidSorts } from '../sort/core.js';
4
+ import { CellType } from '../constants/cell-type.js';
5
+
6
+ /**
7
+ * get view by id
8
+ * @param {array} views { _id: '', ... }
9
+ * @param {string} viewId
10
+ * @returns object
11
+ */
12
+ var getViewById = function getViewById(views, viewId) {
13
+ if (!Array.isArray(views) || !viewId) return null;
14
+ return views.find(function (view) {
15
+ return view._id === viewId;
16
+ });
17
+ };
18
+
19
+ /**
20
+ * check whether the view contains filters
21
+ * @param {object} view { filters: [], ... }
22
+ * @param {array} columns
23
+ * @returns boolean
24
+ */
25
+ var isFilterView = function isFilterView(view, columns) {
26
+ var validFilters = getValidFilters(view.filters, columns);
27
+ return validFilters.length > 0;
28
+ };
29
+
30
+ /**
31
+ * check whether the view contains groupbys
32
+ * @param {object} view { groupbys: [], ... }
33
+ * @param {array} columns
34
+ * @returns boolean
35
+ */
36
+ var isGroupView = function isGroupView(view, columns) {
37
+ var validGroupbys = getValidGroupbys(view.groupbys, columns);
38
+ return validGroupbys.length > 0;
39
+ };
40
+
41
+ /**
42
+ * check whether the view contains sorts
43
+ * @param {object} view { sorts: [], ... }
44
+ * @param {array} columns
45
+ * @returns boolean
46
+ */
47
+ var isSortView = function isSortView(view, columns) {
48
+ var sorts = view.sorts;
49
+ var validSorts = getValidSorts(sorts, columns);
50
+ return validSorts.length > 0;
51
+ };
52
+
53
+ /**
54
+ * check is default view which no contains filters, sorts, groupbys etc.
55
+ * @param {object} view { sorts: [], ... }
56
+ * @param {array} columns
57
+ * @returns boolean
58
+ */
59
+ var isDefaultView = function isDefaultView(view, columns) {
60
+ return !isFilterView(view, columns) && !isSortView(view, columns) && !isGroupView(view, columns);
61
+ };
62
+
63
+ /**
64
+ * get link columns which used either in filters, groupbys, sorts etc.
65
+ * @param {object} view { filters, groupbys, sorts, ... }
66
+ * @param {object} table
67
+ * @returns array, link columns
68
+ */
69
+ var getLinkColumnsUsedInFilters = function getLinkColumnsUsedInFilters(view, table) {
70
+ var filters = view.filters,
71
+ sorts = view.sorts,
72
+ groupbys = view.groupbys;
73
+ var columns = table.columns;
74
+ if (!Array.isArray(columns)) return [];
75
+ var validFilters = getValidFiltersWithoutError(filters, columns);
76
+ var validSorts = getValidSorts(sorts, columns);
77
+ var validGroupbys = getValidGroupbys(groupbys, columns);
78
+ var hasFilters = validFilters && validFilters.length > 0;
79
+ var hasSorts = validSorts && validSorts.length > 0;
80
+ var hasGroupbys = validGroupbys && validGroupbys.length > 0;
81
+ if (!hasFilters && !hasSorts && !hasGroupbys) return [];
82
+ var keyLinkColumnMap = {};
83
+ var keyExistLinkColumnMap = {};
84
+ var linkColumns = [];
85
+ columns.forEach(function (column) {
86
+ var key = column.key,
87
+ name = column.name,
88
+ type = column.type,
89
+ data = column.data,
90
+ width = column.width;
91
+ if (type === CellType.LINK) {
92
+ keyLinkColumnMap[column.key] = {
93
+ key: key,
94
+ name: name,
95
+ type: type,
96
+ data: data,
97
+ width: width
98
+ };
99
+ }
100
+ });
101
+ if (Object.keys(keyLinkColumnMap).length === 0) return [];
102
+ if (hasFilters) {
103
+ validFilters.forEach(function (filter) {
104
+ var filterColumnKey = filter.column_key;
105
+ var filterLinkColumn = keyLinkColumnMap[filterColumnKey];
106
+ if (filterLinkColumn && !keyExistLinkColumnMap[filterColumnKey]) {
107
+ linkColumns.push(filterLinkColumn);
108
+ keyExistLinkColumnMap[filterColumnKey] = true;
109
+ }
110
+ });
111
+ }
112
+ if (hasSorts) {
113
+ validSorts.forEach(function (sort) {
114
+ var sortColumnKey = sort.column_key;
115
+ var sortLinkColumn = keyLinkColumnMap[sortColumnKey];
116
+ if (sortLinkColumn && !keyExistLinkColumnMap[sortColumnKey]) {
117
+ linkColumns.push(sortLinkColumn);
118
+ keyExistLinkColumnMap[sortColumnKey] = true;
119
+ }
120
+ });
121
+ }
122
+ if (hasGroupbys) {
123
+ validGroupbys.forEach(function (groupby) {
124
+ var groupbyColumnKey = groupby.column_key;
125
+ var groupbyLinkColumn = keyLinkColumnMap[groupbyColumnKey];
126
+ if (groupbyLinkColumn && !keyExistLinkColumnMap[groupbyColumnKey]) {
127
+ linkColumns.push(groupbyLinkColumn);
128
+ keyExistLinkColumnMap[groupbyColumnKey] = true;
129
+ }
130
+ });
131
+ }
132
+ return linkColumns;
133
+ };
134
+
135
+ export { getLinkColumnsUsedInFilters, getViewById, isDefaultView, isFilterView, isGroupView, isSortView };
@@ -0,0 +1,143 @@
1
+ import { CellType } from '../constants/cell-type.js';
2
+ import { FORMULA_COLUMN_TYPES_MAP } from '../constants/formula.js';
3
+
4
+ /**
5
+ * transform the formats of link column to link-formula's
6
+ * @param {object} linkColumn { key, data: { display_column_key, ... }, ... }
7
+ * @returns object
8
+ */
9
+ var transLink2LinkFormula = function transLink2LinkFormula(linkColumn) {
10
+ var key = linkColumn.key,
11
+ name = linkColumn.name,
12
+ data = linkColumn.data;
13
+ var display_column_key = data.display_column_key;
14
+ return {
15
+ key: key,
16
+ name: name,
17
+ type: CellType.LINK_FORMULA,
18
+ data: {
19
+ formula: 'lookup',
20
+ link_column_key: key,
21
+ level1_linked_table_column_key: display_column_key,
22
+ level2_linked_table_column_key: null,
23
+ operated_columns: []
24
+ }
25
+ };
26
+ };
27
+
28
+ /**
29
+ * get sorted formula columns
30
+ * @param {array} formulaColumns
31
+ * @param {object} table
32
+ * @returns array
33
+ */
34
+ var getSortedFormulaColumns = function getSortedFormulaColumns(formulaColumns, table) {
35
+ if (!Array.isArray(formulaColumns) || !table || !Array.isArray(table.columns)) return [];
36
+ var keyColumnMap = {};
37
+ table.columns.forEach(function (column) {
38
+ var key = column.key,
39
+ type = column.type;
40
+ if (FORMULA_COLUMN_TYPES_MAP[type]) {
41
+ keyColumnMap[key] = column;
42
+ } else if (type === CellType.LINK && column.data) {
43
+ keyColumnMap[key] = transLink2LinkFormula(column);
44
+ }
45
+ });
46
+
47
+ // get none-repeating formulas
48
+ var key_sorting_formula_column = {};
49
+ var sorting_formula_column_keys = [];
50
+ formulaColumns.forEach(function (column) {
51
+ var columnKey = column.key;
52
+ if (!key_sorting_formula_column[columnKey]) {
53
+ key_sorting_formula_column[columnKey] = column;
54
+ sorting_formula_column_keys.push(columnKey);
55
+ }
56
+ });
57
+
58
+ /**
59
+ * e.g. formula1 = formula2 + formula3
60
+ * e.g. formula2 = 1 + 2
61
+ * e.g. formula3 = formula2 + 3
62
+ * edges: formula2 --> formula1, formula2 --> formula3; formula3 --> formula1
63
+ * keyInDegreeMap, the total number of formula columns that depend on: { formula1_key: 2, formula2_key: 0, formula3_key: 1 }
64
+ * keyEdgesMap: { formula2_key: [formula1_key, formula3_key], formula3_kye: [formula1_key]}
65
+ */
66
+ var keyInDegreeMap = {};
67
+ var keyEdgesMap = {};
68
+ sorting_formula_column_keys.forEach(function (formulaColumnKey) {
69
+ var formulaColumn = key_sorting_formula_column[formulaColumnKey];
70
+ var data = formulaColumn.data;
71
+ var operated_columns = data.operated_columns;
72
+ keyInDegreeMap[formulaColumnKey] = 0;
73
+ Array.isArray(operated_columns) && operated_columns.forEach(function (dependColumnKey) {
74
+ var dependColumn = keyColumnMap[dependColumnKey];
75
+ if (!dependColumn) {
76
+ return;
77
+ }
78
+ keyInDegreeMap[formulaColumnKey]++;
79
+ if (keyEdgesMap[dependColumnKey]) {
80
+ keyEdgesMap[dependColumnKey].push(formulaColumnKey);
81
+ } else {
82
+ keyEdgesMap[dependColumnKey] = [formulaColumnKey];
83
+ }
84
+ });
85
+ });
86
+ var sortedList = [];
87
+ var waitingQueue = [];
88
+ sorting_formula_column_keys.forEach(function (formulaColumnKey) {
89
+ if (keyInDegreeMap[formulaColumnKey] === 0) {
90
+ waitingQueue.push(formulaColumnKey);
91
+ }
92
+ });
93
+ while (waitingQueue.length) {
94
+ var columnKey = waitingQueue.shift();
95
+ var edges = keyEdgesMap[columnKey];
96
+ sortedList.push(columnKey);
97
+ Array.isArray(edges) && edges.forEach(function (edge) {
98
+ keyInDegreeMap[edge]--;
99
+ if (keyInDegreeMap[edge] === 0) {
100
+ waitingQueue.push(edge);
101
+ }
102
+ });
103
+ }
104
+ return sortedList.map(function (columnKey) {
105
+ return keyColumnMap[columnKey];
106
+ });
107
+ };
108
+
109
+ /**
110
+ * get formula columns and link columns from table
111
+ * @param {object} table { columns: [], ... }
112
+ * @returns array
113
+ */
114
+ var getFormulaColumnsContainLinks = function getFormulaColumnsContainLinks(table) {
115
+ var columns = table.columns;
116
+ var formulaColumns = columns.filter(function (column) {
117
+ var type = column.type,
118
+ data = column.data;
119
+ if (type === CellType.LINK) {
120
+ return !!data;
121
+ }
122
+ return FORMULA_COLUMN_TYPES_MAP[type] && data;
123
+ });
124
+ return formulaColumns.map(function (column) {
125
+ if (column.type === CellType.LINK) {
126
+ return transLink2LinkFormula(column);
127
+ }
128
+ return column;
129
+ });
130
+ };
131
+
132
+ /**
133
+ * get sorted formula columns and link columns from table
134
+ * @param {object} table { columns: [], ... }
135
+ * @returns array
136
+ */
137
+ var getSortedFormulaColumnsContainLinks = function getSortedFormulaColumnsContainLinks(table) {
138
+ var formulaColumns = getFormulaColumnsContainLinks(table);
139
+ if (formulaColumns.length === 0) return [];
140
+ return getSortedFormulaColumns(formulaColumns, table);
141
+ };
142
+
143
+ export { getFormulaColumnsContainLinks, getSortedFormulaColumns, getSortedFormulaColumnsContainLinks, transLink2LinkFormula };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * get group by paths.
3
+ * @param {array} paths e.g. [0, 1, 2]
4
+ * @param {array} groups
5
+ * @returns object
6
+ */
7
+ var getGroupByPath = function getGroupByPath(paths, groups) {
8
+ if (!Array.isArray(paths) || !Array.isArray(groups)) {
9
+ return null;
10
+ }
11
+ var level0GroupIndex = paths[0];
12
+ if (level0GroupIndex < 0 || level0GroupIndex >= groups.length) {
13
+ return null;
14
+ }
15
+ var level = 1;
16
+ var foundGroup = groups[level0GroupIndex];
17
+ while (level < paths.length) {
18
+ if (!foundGroup) {
19
+ break;
20
+ }
21
+ var subGroups = foundGroup.subgroups;
22
+ var currentLevelGroupIndex = paths[level];
23
+ if (!Array.isArray(subGroups) || currentLevelGroupIndex < 0 || currentLevelGroupIndex >= subGroups.length) {
24
+ break;
25
+ }
26
+ foundGroup = subGroups[currentLevelGroupIndex];
27
+ level += 1;
28
+ }
29
+ return foundGroup;
30
+ };
31
+
32
+ export { getGroupByPath };
@@ -0,0 +1,179 @@
1
+ import { getRowsByIds } from '../table/row.js';
2
+ import { isTableRows } from '../row/core.js';
3
+ import '@babel/runtime/helpers/defineProperty';
4
+ import '../constants/group.js';
5
+ import '../validate/filter.js';
6
+ import '../filter/core.js';
7
+ import '@babel/runtime/helpers/toConsumableArray';
8
+ import '../constants/filter/filter-column-options.js';
9
+ import '../constants/filter/filter-modifier.js';
10
+ import '../constants/filter/filter-predicate.js';
11
+ import '../constants/filter/filter-is-within.js';
12
+ import '../date.js';
13
+ import { isNumber } from '../number.js';
14
+ import '../cell-value-get/cell-value.js';
15
+ import { isNumericColumn } from '../column/number.js';
16
+ import '../constants/column.js';
17
+ import { FORMULA_COLUMN_TYPES_MAP } from '../constants/formula.js';
18
+ import '../constants/row-color.js';
19
+
20
+ /**
21
+ * calculate summaries of numeric columns from table
22
+ * @param {object} table
23
+ * @param {array} rows table's rows or rows ids
24
+ * @param {object} formulaRows support numeric formula columns
25
+ * @returns object, { [column.key]: { sum, average, median, max, min, ... }, ... }
26
+ */
27
+ var getSummaries = function getSummaries(table, rows, formulaRows) {
28
+ var numericColumns = table.columns.filter(function (column) {
29
+ return isNumericColumn(column);
30
+ });
31
+ if (numericColumns.length === 0) {
32
+ return {};
33
+ }
34
+ var summaryRows = isTableRows(rows) ? rows : getRowsByIds(table, rows);
35
+ var summaries = {};
36
+ numericColumns.forEach(function (column) {
37
+ var type = column.type,
38
+ key = column.key;
39
+ var validNumbersCount = 0;
40
+ var medianArr = [];
41
+ var sum = 0;
42
+ var min;
43
+ var max;
44
+ var median;
45
+ summaryRows.forEach(function (row) {
46
+ var cellValue = row[key];
47
+ if (FORMULA_COLUMN_TYPES_MAP[type]) {
48
+ var formulaRow = formulaRows && formulaRows[row._id];
49
+ cellValue = formulaRow && formulaRow[key];
50
+ if (Array.isArray(cellValue) && cellValue.length === 1) {
51
+ cellValue = cellValue[0];
52
+ }
53
+ }
54
+ if (isNumber(cellValue)) {
55
+ medianArr.push(cellValue);
56
+ validNumbersCount += 1;
57
+ sum += cellValue;
58
+ if (min === undefined) {
59
+ min = cellValue;
60
+ } else {
61
+ min = cellValue < min ? cellValue : min;
62
+ }
63
+ if (max === undefined) {
64
+ max = cellValue;
65
+ } else {
66
+ max = cellValue > max ? cellValue : max;
67
+ }
68
+ }
69
+ });
70
+ if (validNumbersCount > 0) {
71
+ medianArr.sort();
72
+ if (medianArr.length % 2 === 0) {
73
+ median = (medianArr[medianArr.length / 2 - 1] + medianArr[medianArr.length / 2]) / 2;
74
+ } else {
75
+ median = medianArr[parseInt(medianArr.length / 2)];
76
+ }
77
+ }
78
+ var average = validNumbersCount === 0 ? 0 : sum / validNumbersCount;
79
+ summaries[key] = {
80
+ sum: sum,
81
+ average: average,
82
+ median: median,
83
+ max: max,
84
+ min: min
85
+ };
86
+ });
87
+ return summaries;
88
+ };
89
+
90
+ /**
91
+ * calculate sub-group's summaries of numeric columns
92
+ * @param {array} subgroups { summaries, ... }
93
+ * @param {array} numericColumns
94
+ * @returns object, { [column.key]: { sum, average, median, max, min, ... } }
95
+ */
96
+ var getSummariesWithSubgroups = function getSummariesWithSubgroups(subgroups, numericColumns) {
97
+ var subgroupsLen = subgroups.length;
98
+ var summaries = {};
99
+ numericColumns.forEach(function (column) {
100
+ var medianArr = [];
101
+ var sum = 0;
102
+ var average = 0;
103
+ var median;
104
+ var max;
105
+ var min;
106
+ subgroups.forEach(function (subgroup) {
107
+ var summaries = subgroup.summaries;
108
+ var summary = summaries[column.key];
109
+ var subgroupSum = summary.sum,
110
+ subgroupAverage = summary.average,
111
+ subgroupMedian = summary.median,
112
+ subgroupMax = summary.max,
113
+ subgroupMin = summary.min;
114
+ sum += subgroupSum || 0;
115
+ average += subgroupAverage || 0;
116
+ if (isNumber(subgroupMedian)) {
117
+ medianArr.push(subgroupMedian);
118
+ }
119
+ if (isNumber(subgroupMax)) {
120
+ if (max === undefined) {
121
+ max = subgroupMax;
122
+ } else {
123
+ max = subgroupMax > max ? subgroupMax : max;
124
+ }
125
+ }
126
+ if (isNumber(subgroupMin)) {
127
+ if (min === undefined) {
128
+ min = subgroupMin;
129
+ } else {
130
+ min = subgroupMin < min ? subgroupMin : min;
131
+ }
132
+ }
133
+ });
134
+ if (medianArr.length > 0) {
135
+ medianArr.sort();
136
+ if (medianArr.length % 2 === 0) {
137
+ median = (medianArr[medianArr.length / 2 - 1] + medianArr[medianArr.length / 2]) / 2;
138
+ } else {
139
+ median = medianArr[parseInt(medianArr.length / 2)];
140
+ }
141
+ }
142
+ average = average / subgroupsLen;
143
+ summaries[column.key] = {
144
+ sum: sum,
145
+ average: average,
146
+ median: median,
147
+ max: max,
148
+ min: min
149
+ };
150
+ });
151
+ return summaries;
152
+ };
153
+
154
+ /**
155
+ * calculate group's summaries of numeric columns from table
156
+ * @param {array} groups { subgroups, row_ids, ... }
157
+ * @param {object} table
158
+ * @param {object} formulaRows support numeric formula columns
159
+ */
160
+ var updateGroupSummaries = function updateGroupSummaries(groups, table, formulaRows) {
161
+ var numericColumns = table.columns.filter(function (column) {
162
+ return isNumericColumn(column);
163
+ });
164
+ if (!Array.isArray(groups) || numericColumns.length === 0) {
165
+ return;
166
+ }
167
+ groups.forEach(function (group) {
168
+ var subgroups = group.subgroups,
169
+ row_ids = group.row_ids;
170
+ if (Array.isArray(subgroups) && subgroups.length > 0) {
171
+ updateGroupSummaries(subgroups, table, formulaRows);
172
+ group.summaries = getSummariesWithSubgroups(subgroups, numericColumns);
173
+ } else if (row_ids) {
174
+ group.summaries = getSummaries(table, row_ids, formulaRows);
175
+ }
176
+ });
177
+ };
178
+
179
+ export { getSummaries, getSummariesWithSubgroups, updateGroupSummaries };