@hrforte/react-pivottable 2.1.2 → 2.2.0
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/README.md +5 -3
- package/dist/PivotDataWorker.js +11 -16
- package/dist/PivotDataWorker.js.map +1 -1
- package/dist/PivotTableUI.js +59 -70
- package/dist/PivotTableUI.js.map +1 -1
- package/dist/PlotlyRenderers.js +9 -5
- package/dist/PlotlyRenderers.js.map +1 -1
- package/dist/TableRenderers.js +0 -1
- package/dist/TableRenderers.js.map +1 -1
- package/dist/Utilities.js +2 -20
- package/dist/Utilities.js.map +1 -1
- package/dist/__tests__/PivotDataWorker-test.js +7 -8
- package/dist/__tests__/PivotDataWorker-test.js.map +1 -1
- package/dist/__tests__/PivotTableUI-processing-test.js +104 -9
- package/dist/__tests__/PivotTableUI-processing-test.js.map +1 -1
- package/dist/__tests__/pivotCompute-test.js +7 -7
- package/dist/__tests__/pivotCompute-test.js.map +1 -1
- package/dist/pivot-worker.js +8 -60
- package/dist/pivotCompute.js +5 -22
- package/dist/pivotCompute.js.map +1 -1
- package/dist/pivotWorker.js +2 -18
- package/dist/pivotWorker.js.map +1 -1
- package/dist/pivottable.css +0 -20
- package/package.json +1 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
4
|
+
|
|
3
5
|
var _react = require('react');
|
|
4
6
|
|
|
5
7
|
var _react2 = _interopRequireDefault(_react);
|
|
@@ -10,8 +12,12 @@ var _PivotTableUI = require('../PivotTableUI');
|
|
|
10
12
|
|
|
11
13
|
var _PivotTableUI2 = _interopRequireDefault(_PivotTableUI);
|
|
12
14
|
|
|
15
|
+
var _pivotCompute = require('../pivotCompute');
|
|
16
|
+
|
|
13
17
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
14
18
|
|
|
19
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
20
|
+
|
|
15
21
|
/* eslint-disable no-magic-numbers */
|
|
16
22
|
|
|
17
23
|
// React 19 needs to be told that this environment supports `act`.
|
|
@@ -89,26 +95,115 @@ describe(' PivotTableUI isShowProcessing', function () {
|
|
|
89
95
|
expect(overlay).not.toBeNull();
|
|
90
96
|
// The overlay is layered on top of the table: the table must survive.
|
|
91
97
|
expect(node.querySelector('.pvtTable')).not.toBeNull();
|
|
92
|
-
//
|
|
93
|
-
//
|
|
98
|
+
// Only a spinner and a label: progress percentages were removed, the
|
|
99
|
+
// overlay simply stays until the worker posts its result event.
|
|
94
100
|
expect(overlay.querySelector('.pvtLoadingSpinner')).not.toBeNull();
|
|
95
|
-
expect(overlay.querySelector('.
|
|
96
|
-
expect(overlay.querySelector('.
|
|
101
|
+
expect(overlay.querySelector('.pvtLoadingText').textContent).toBe('Processing…');
|
|
102
|
+
expect(overlay.querySelector('.pvtLoadingBar')).toBeNull();
|
|
103
|
+
expect(overlay.querySelector('.pvtLoadingPercent')).toBeNull();
|
|
97
104
|
|
|
98
105
|
// Turning the flag back off removes the overlay.
|
|
99
106
|
rerenderPivot(root, baseProps);
|
|
100
107
|
expect(node.querySelector('.pvtLoadingOverlay')).toBeNull();
|
|
101
108
|
});
|
|
102
109
|
|
|
103
|
-
it('renders
|
|
110
|
+
it('renders a spinner without any percentage markup', function () {
|
|
104
111
|
var node = document.createElement('div');
|
|
105
112
|
(0, _react.act)(function () {
|
|
106
|
-
(0, _client.createRoot)(node).render(_react2.default.createElement(_PivotTableUI.PivotLoadingOverlay,
|
|
107
|
-
progress: { phase: 'aggregate' }
|
|
108
|
-
}));
|
|
113
|
+
(0, _client.createRoot)(node).render(_react2.default.createElement(_PivotTableUI.PivotLoadingOverlay, null));
|
|
109
114
|
});
|
|
115
|
+
expect(node.querySelector('.pvtLoadingOverlay')).not.toBeNull();
|
|
116
|
+
expect(node.querySelector('.pvtLoadingSpinner')).not.toBeNull();
|
|
110
117
|
expect(node.querySelector('.pvtLoadingBarWrap')).toBeNull();
|
|
111
|
-
expect(node.querySelector('.
|
|
118
|
+
expect(node.querySelector('.pvtLoadingPercent')).toBeNull();
|
|
119
|
+
expect(node.querySelector('.pvtLoadingText').textContent).toBe('Processing…');
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('hides the overlay only after the worker responds and the table renders', function () {
|
|
123
|
+
var wait = function wait(ms) {
|
|
124
|
+
return new Promise(function (resolve) {
|
|
125
|
+
return setTimeout(resolve, ms);
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
// React's act() returns a non-standard thenable whose .then() does not
|
|
129
|
+
// return a promise, so it cannot be chained directly - wrap it first.
|
|
130
|
+
var actAsync = function actAsync(callback) {
|
|
131
|
+
return new Promise(function (resolve, reject) {
|
|
132
|
+
return (0, _react.act)(callback).then(resolve, reject);
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
var workerInstances = [];
|
|
136
|
+
|
|
137
|
+
var FakeWorker = function () {
|
|
138
|
+
function FakeWorker(url) {
|
|
139
|
+
_classCallCheck(this, FakeWorker);
|
|
140
|
+
|
|
141
|
+
this.url = url;
|
|
142
|
+
this.posted = [];
|
|
143
|
+
this.onmessage = null;
|
|
144
|
+
workerInstances.push(this);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
_createClass(FakeWorker, [{
|
|
148
|
+
key: 'postMessage',
|
|
149
|
+
value: function postMessage(message) {
|
|
150
|
+
this.posted.push(message);
|
|
151
|
+
}
|
|
152
|
+
}, {
|
|
153
|
+
key: 'terminate',
|
|
154
|
+
value: function terminate() {}
|
|
155
|
+
}]);
|
|
156
|
+
|
|
157
|
+
return FakeWorker;
|
|
158
|
+
}();
|
|
159
|
+
|
|
160
|
+
var previousWorker = global.Worker;
|
|
161
|
+
global.Worker = FakeWorker;
|
|
162
|
+
|
|
163
|
+
// workerThreshold: 2 makes this small dataset worker-eligible.
|
|
164
|
+
var props = Object.assign({}, baseProps, { workerThreshold: 2 });
|
|
165
|
+
|
|
166
|
+
var _mount3 = mount(props),
|
|
167
|
+
node = _mount3.node;
|
|
168
|
+
|
|
169
|
+
var restore = function restore() {
|
|
170
|
+
global.Worker = previousWorker;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// The overlay is up while the computation is pending.
|
|
174
|
+
expect(node.querySelector('.pvtLoadingOverlay')).not.toBeNull();
|
|
175
|
+
|
|
176
|
+
// Wait out the dispatch debounce so the request reaches the worker.
|
|
177
|
+
return actAsync(function () {
|
|
178
|
+
return wait(80);
|
|
179
|
+
}).then(function () {
|
|
180
|
+
var worker = workerInstances[0];
|
|
181
|
+
expect(worker).toBeDefined();
|
|
182
|
+
var computeMsg = worker.posted.find(function (m) {
|
|
183
|
+
return m.type === 'pivot:compute';
|
|
184
|
+
});
|
|
185
|
+
expect(computeMsg).toBeDefined();
|
|
186
|
+
// The worker has not answered yet: the overlay must stay up.
|
|
187
|
+
expect(node.querySelector('.pvtLoadingOverlay')).not.toBeNull();
|
|
188
|
+
|
|
189
|
+
// Worker finishes and posts its result event.
|
|
190
|
+
var result = (0, _pivotCompute.computePivotState)((0, _pivotCompute.materializeData)(records, {}), (0, _pivotCompute.createWorkerConfig)(props));
|
|
191
|
+
return actAsync(function () {
|
|
192
|
+
worker.onmessage({
|
|
193
|
+
data: { type: 'pivot:result', id: computeMsg.id, result: result }
|
|
194
|
+
});
|
|
195
|
+
return wait(0);
|
|
196
|
+
});
|
|
197
|
+
}).then(function () {
|
|
198
|
+
// The overlay is gone only now - and the freshly computed table is
|
|
199
|
+
// already on screen in the same state where the overlay disappeared.
|
|
200
|
+
expect(node.querySelector('.pvtLoadingOverlay')).toBeNull();
|
|
201
|
+
expect(node.querySelector('.pvtTable')).not.toBeNull();
|
|
202
|
+
restore();
|
|
203
|
+
}).catch(function (error) {
|
|
204
|
+
restore();
|
|
205
|
+
throw error;
|
|
206
|
+
});
|
|
112
207
|
});
|
|
113
208
|
});
|
|
114
209
|
//# sourceMappingURL=PivotTableUI-processing-test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/__tests__/PivotTableUI-processing-test.js"],"names":["global","IS_REACT_ACT_ENVIRONMENT","records","name","gender","colour","trials","baseProps","data","rows","cols","aggregatorName","vals","rendererName","rerenderPivot","root","props","render","React","createElement","PivotTableUI","describe","containers","beforeEach","afterEach","forEach","container","unmount","node","remove","mount","document","body","appendChild","entry","push","it","expect","querySelector","toBeNull","not","Object","assign","isShowProcessing","overlay","style","width","toBe","textContent","PivotLoadingOverlay","progress","phase"],"mappings":"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","file":"PivotTableUI-processing-test.js","sourcesContent":["import React, {act} from 'react';\nimport {createRoot} from 'react-dom/client';\nimport PivotTableUI, {PivotLoadingOverlay} from '../PivotTableUI';\n/* eslint-disable no-magic-numbers */\n\n// React 19 needs to be told that this environment supports `act`.\nglobal.IS_REACT_ACT_ENVIRONMENT = true;\n\n// `isShowProcessing` is a debugging/testing hook that forces the loading\n// overlay on top of the rendered table without running a real worker\n// computation, so the overlay can be inspected while consuming the package.\nconst records = [\n {name: 'Nick', gender: 'male', colour: 'blue', trials: 103},\n {name: 'Jane', gender: 'female', colour: 'red', trials: 95},\n {name: 'John', gender: 'male', colour: 'blue', trials: 112},\n {name: 'Carol', gender: 'female', colour: 'yellow', trials: 102},\n];\n\nconst baseProps = {\n data: records,\n rows: ['name'],\n cols: [],\n aggregatorName: 'Count',\n vals: [],\n rendererName: 'Table',\n};\n\nfunction rerenderPivot(root, props) {\n act(() => {\n root.render(React.createElement(PivotTableUI, props));\n });\n}\n\ndescribe(' PivotTableUI isShowProcessing', function() {\n let containers;\n\n beforeEach(function() {\n containers = [];\n });\n\n afterEach(function() {\n containers.forEach(container => {\n act(() => {\n container.root.unmount();\n });\n container.node.remove();\n });\n });\n\n const mount = props => {\n const node = document.createElement('div');\n document.body.appendChild(node);\n const root = createRoot(node);\n act(() => {\n root.render(React.createElement(PivotTableUI, props));\n });\n const entry = {node, root};\n containers.push(entry);\n return entry;\n };\n\n it('does not render the overlay by default', function() {\n const {node} = mount(baseProps);\n expect(node.querySelector('.pvtLoadingOverlay')).toBeNull();\n expect(node.querySelector('.pvtTable')).not.toBeNull();\n });\n\n it('renders the overlay on top of the table when isShowProcessing is true', function() {\n const {node, root} = mount(baseProps);\n // Table is rendered from the real data first (no overlay).\n expect(node.querySelector('.pvtTable')).not.toBeNull();\n expect(node.querySelector('.pvtLoadingOverlay')).toBeNull();\n\n rerenderPivot(root, Object.assign({}, baseProps, {isShowProcessing: true}));\n\n const overlay = node.querySelector('.pvtLoadingOverlay');\n expect(overlay).not.toBeNull();\n // The overlay is layered on top of the table: the table must survive.\n expect(node.querySelector('.pvtTable')).not.toBeNull();\n // Nothing was actually being computed, so a sample progress is supplied\n // to exercise the progress bar/percentage branch of the overlay.\n expect(overlay.querySelector('.pvtLoadingSpinner')).not.toBeNull();\n expect(overlay.querySelector('.pvtLoadingBar').style.width).toBe('60%');\n expect(overlay.querySelector('.pvtLoadingPercent').textContent).toBe('60%');\n\n // Turning the flag back off removes the overlay.\n rerenderPivot(root, baseProps);\n expect(node.querySelector('.pvtLoadingOverlay')).toBeNull();\n });\n\n it('renders an indeterminate overlay when progress.total is unavailable', function() {\n const node = document.createElement('div');\n act(() => {\n createRoot(node).render(\n React.createElement(PivotLoadingOverlay, {\n progress: {phase: 'aggregate'},\n })\n );\n });\n expect(node.querySelector('.pvtLoadingBarWrap')).toBeNull();\n expect(node.querySelector('.pvtLoadingText').textContent).toBe(\n 'Aggregating data…'\n );\n });\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/__tests__/PivotTableUI-processing-test.js"],"names":["global","IS_REACT_ACT_ENVIRONMENT","records","name","gender","colour","trials","baseProps","data","rows","cols","aggregatorName","vals","rendererName","rerenderPivot","root","props","render","React","createElement","PivotTableUI","describe","containers","beforeEach","afterEach","forEach","container","unmount","node","remove","mount","document","body","appendChild","entry","push","it","expect","querySelector","toBeNull","not","Object","assign","isShowProcessing","overlay","textContent","toBe","PivotLoadingOverlay","wait","Promise","setTimeout","resolve","ms","actAsync","reject","callback","then","workerInstances","FakeWorker","url","posted","onmessage","message","previousWorker","Worker","workerThreshold","restore","worker","toBeDefined","computeMsg","find","m","type","result","id","catch","error"],"mappings":"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","file":"PivotTableUI-processing-test.js","sourcesContent":["import React, {act} from 'react';\nimport {createRoot} from 'react-dom/client';\nimport PivotTableUI, {PivotLoadingOverlay} from '../PivotTableUI';\nimport {\n computePivotState,\n createWorkerConfig,\n materializeData,\n} from '../pivotCompute';\n/* eslint-disable no-magic-numbers */\n\n// React 19 needs to be told that this environment supports `act`.\nglobal.IS_REACT_ACT_ENVIRONMENT = true;\n\n// `isShowProcessing` is a debugging/testing hook that forces the loading\n// overlay on top of the rendered table without running a real worker\n// computation, so the overlay can be inspected while consuming the package.\nconst records = [\n {name: 'Nick', gender: 'male', colour: 'blue', trials: 103},\n {name: 'Jane', gender: 'female', colour: 'red', trials: 95},\n {name: 'John', gender: 'male', colour: 'blue', trials: 112},\n {name: 'Carol', gender: 'female', colour: 'yellow', trials: 102},\n];\n\nconst baseProps = {\n data: records,\n rows: ['name'],\n cols: [],\n aggregatorName: 'Count',\n vals: [],\n rendererName: 'Table',\n};\n\nfunction rerenderPivot(root, props) {\n act(() => {\n root.render(React.createElement(PivotTableUI, props));\n });\n}\n\ndescribe(' PivotTableUI isShowProcessing', function() {\n let containers;\n\n beforeEach(function() {\n containers = [];\n });\n\n afterEach(function() {\n containers.forEach(container => {\n act(() => {\n container.root.unmount();\n });\n container.node.remove();\n });\n });\n\n const mount = props => {\n const node = document.createElement('div');\n document.body.appendChild(node);\n const root = createRoot(node);\n act(() => {\n root.render(React.createElement(PivotTableUI, props));\n });\n const entry = {node, root};\n containers.push(entry);\n return entry;\n };\n\n it('does not render the overlay by default', function() {\n const {node} = mount(baseProps);\n expect(node.querySelector('.pvtLoadingOverlay')).toBeNull();\n expect(node.querySelector('.pvtTable')).not.toBeNull();\n });\n\n it('renders the overlay on top of the table when isShowProcessing is true', function() {\n const {node, root} = mount(baseProps);\n // Table is rendered from the real data first (no overlay).\n expect(node.querySelector('.pvtTable')).not.toBeNull();\n expect(node.querySelector('.pvtLoadingOverlay')).toBeNull();\n\n rerenderPivot(root, Object.assign({}, baseProps, {isShowProcessing: true}));\n\n const overlay = node.querySelector('.pvtLoadingOverlay');\n expect(overlay).not.toBeNull();\n // The overlay is layered on top of the table: the table must survive.\n expect(node.querySelector('.pvtTable')).not.toBeNull();\n // Only a spinner and a label: progress percentages were removed, the\n // overlay simply stays until the worker posts its result event.\n expect(overlay.querySelector('.pvtLoadingSpinner')).not.toBeNull();\n expect(overlay.querySelector('.pvtLoadingText').textContent).toBe(\n 'Processing…'\n );\n expect(overlay.querySelector('.pvtLoadingBar')).toBeNull();\n expect(overlay.querySelector('.pvtLoadingPercent')).toBeNull();\n\n // Turning the flag back off removes the overlay.\n rerenderPivot(root, baseProps);\n expect(node.querySelector('.pvtLoadingOverlay')).toBeNull();\n });\n\n it('renders a spinner without any percentage markup', function() {\n const node = document.createElement('div');\n act(() => {\n createRoot(node).render(\n React.createElement(PivotLoadingOverlay, null)\n );\n });\n expect(node.querySelector('.pvtLoadingOverlay')).not.toBeNull();\n expect(node.querySelector('.pvtLoadingSpinner')).not.toBeNull();\n expect(node.querySelector('.pvtLoadingBarWrap')).toBeNull();\n expect(node.querySelector('.pvtLoadingPercent')).toBeNull();\n expect(node.querySelector('.pvtLoadingText').textContent).toBe(\n 'Processing…'\n );\n });\n\n it('hides the overlay only after the worker responds and the table renders', function() {\n const wait = ms => new Promise(resolve => setTimeout(resolve, ms));\n // React's act() returns a non-standard thenable whose .then() does not\n // return a promise, so it cannot be chained directly - wrap it first.\n const actAsync = callback =>\n new Promise((resolve, reject) => act(callback).then(resolve, reject));\n const workerInstances = [];\n class FakeWorker {\n constructor(url) {\n this.url = url;\n this.posted = [];\n this.onmessage = null;\n workerInstances.push(this);\n }\n\n postMessage(message) {\n this.posted.push(message);\n }\n\n terminate() {}\n }\n\n const previousWorker = global.Worker;\n global.Worker = FakeWorker;\n\n // workerThreshold: 2 makes this small dataset worker-eligible.\n const props = Object.assign({}, baseProps, {workerThreshold: 2});\n const {node} = mount(props);\n\n const restore = () => {\n global.Worker = previousWorker;\n };\n\n // The overlay is up while the computation is pending.\n expect(node.querySelector('.pvtLoadingOverlay')).not.toBeNull();\n\n // Wait out the dispatch debounce so the request reaches the worker.\n return actAsync(() => wait(80))\n .then(() => {\n const worker = workerInstances[0];\n expect(worker).toBeDefined();\n const computeMsg = worker.posted.find(m => m.type === 'pivot:compute');\n expect(computeMsg).toBeDefined();\n // The worker has not answered yet: the overlay must stay up.\n expect(node.querySelector('.pvtLoadingOverlay')).not.toBeNull();\n\n // Worker finishes and posts its result event.\n const result = computePivotState(\n materializeData(records, {}),\n createWorkerConfig(props)\n );\n return actAsync(() => {\n worker.onmessage({\n data: {type: 'pivot:result', id: computeMsg.id, result},\n });\n return wait(0);\n });\n })\n .then(() => {\n // The overlay is gone only now - and the freshly computed table is\n // already on screen in the same state where the overlay disappeared.\n expect(node.querySelector('.pvtLoadingOverlay')).toBeNull();\n expect(node.querySelector('.pvtTable')).not.toBeNull();\n restore();\n })\n .catch(error => {\n restore();\n throw error;\n });\n });\n});\n"]}
|
|
@@ -29,13 +29,13 @@ describe(' pivotCompute', function () {
|
|
|
29
29
|
expect(materialized.attrValues.gender).toEqual({ male: 2, female: 2 });
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
it('reports progress
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
expect(
|
|
32
|
+
it('reports no progress (percentages were removed)', function () {
|
|
33
|
+
// materializeData no longer accepts an onProgress callback: passing
|
|
34
|
+
// one is ignored and nothing is reported during the scan.
|
|
35
|
+
var maybeCallback = jest.fn();
|
|
36
|
+
var materialized = pivotCompute.materializeData(records, {}, maybeCallback);
|
|
37
|
+
expect(materialized.totalRecords).toBe(4);
|
|
38
|
+
expect(maybeCallback).not.toHaveBeenCalled();
|
|
39
39
|
});
|
|
40
40
|
});
|
|
41
41
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/__tests__/pivotCompute-test.js"],"names":["pivotCompute","records","name","gender","colour","trials","successes","multiAggregationConfig","key","aggregatorName","vals","describe","it","materialized","materializeData","expect","totalRecords","toBe","materializedInput","toEqual","attrValues","male","female","progressCalls","processed","total","phase","push","config","rows","cols","aggregations","serialized","computePivotState","direct","PivotData","Object","assign","data","hydrated","precomputedData","getRowKeys","getColKeys","compareCells","rowKey","colKey","forEach","getAggregator","agg","value","directFormat","format","hydratedFormat","filteredConfig","valueFilter","reverseSorter","a","b","sorters","keys","map","indexOf","toBeLessThan","props","first","createComputeSignature","second","different","not","localeCompare","signature","toContain","eligibleProps","aggregators","defaultProps","derivedAttributes","beforeAll","global","Worker","FakeWorker","canComputeInWorker","threshold","Count","extra","record","enabled"],"mappings":"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","file":"pivotCompute-test.js","sourcesContent":["import * as pivotCompute from '../pivotCompute';\nimport {PivotData} from '../Utilities';\n/* eslint-disable no-magic-numbers */\n\nconst records = [\n {name: 'Nick', gender: 'male', colour: 'blue', trials: 103, successes: 12},\n {name: 'Jane', gender: 'female', colour: 'red', trials: 95, successes: 25},\n {name: 'John', gender: 'male', colour: 'blue', trials: 112, successes: 30},\n {\n name: 'Carol',\n gender: 'female',\n colour: 'yellow',\n trials: 102,\n successes: 14,\n },\n];\n\nconst multiAggregationConfig = [\n {key: 'sum-trials', aggregatorName: 'Sum', vals: ['trials']},\n {key: 'count', aggregatorName: 'Count', vals: []},\n];\n\ndescribe(' pivotCompute', function() {\n describe('.materializeData()', function() {\n it('collects attribute values and materialized records', function() {\n const materialized = pivotCompute.materializeData(records, {});\n expect(materialized.totalRecords).toBe(4);\n expect(materialized.materializedInput).toEqual(records);\n expect(materialized.attrValues.gender).toEqual({male: 2, female: 2});\n });\n\n it('reports progress only in batches', function() {\n const progressCalls = [];\n pivotCompute.materializeData(records, {}, (processed, total, phase) => {\n progressCalls.push([processed, total, phase]);\n });\n // No batch boundary is crossed with only 4 records.\n expect(progressCalls).toEqual([]);\n });\n });\n\n describe('.computePivotState() with PivotData hydration', function() {\n const config = {\n rows: ['gender'],\n cols: ['colour'],\n aggregations: multiAggregationConfig,\n };\n\n it('hydrates to the same results as a direct PivotData build', function() {\n const materialized = pivotCompute.materializeData(records, {});\n const serialized = pivotCompute.computePivotState(materialized, config);\n const direct = new PivotData(Object.assign({}, config, {data: records}));\n const hydrated = new PivotData({\n data: materialized.materializedInput,\n precomputedData: serialized,\n aggregations: multiAggregationConfig,\n rows: ['gender'],\n cols: ['colour'],\n });\n\n expect(hydrated.getRowKeys()).toEqual(direct.getRowKeys());\n expect(hydrated.getColKeys()).toEqual(direct.getColKeys());\n\n const compareCells = (rowKey, colKey) => {\n multiAggregationConfig.forEach(agg => {\n expect(hydrated.getAggregator(rowKey, colKey, agg.key).value()).toBe(\n direct.getAggregator(rowKey, colKey, agg.key).value()\n );\n });\n };\n\n compareCells([], []);\n direct.getRowKeys().forEach(rowKey => {\n compareCells(rowKey, []);\n direct.getColKeys().forEach(colKey => {\n compareCells(rowKey, colKey);\n });\n });\n direct.getColKeys().forEach(colKey => {\n compareCells([], colKey);\n });\n });\n\n it('provides working format() on hydrated aggregators', function() {\n const materialized = pivotCompute.materializeData(records, {});\n const serialized = pivotCompute.computePivotState(materialized, config);\n const direct = new PivotData(Object.assign({}, config, {data: records}));\n const hydrated = new PivotData({\n data: materialized.materializedInput,\n precomputedData: serialized,\n aggregations: multiAggregationConfig,\n rows: ['gender'],\n cols: ['colour'],\n });\n\n const directFormat = direct\n .getAggregator([], [], 'sum-trials')\n .format(1234.5);\n const hydratedFormat = hydrated\n .getAggregator([], [], 'sum-trials')\n .format(1234.5);\n expect(hydratedFormat).toBe(directFormat);\n });\n\n it('respects valueFilter like the classic path', function() {\n const filteredConfig = Object.assign({}, config, {\n valueFilter: {gender: {male: true}},\n });\n const materialized = pivotCompute.materializeData(records, {});\n const serialized = pivotCompute.computePivotState(\n materialized,\n filteredConfig\n );\n const direct = new PivotData(\n Object.assign({}, filteredConfig, {data: records})\n );\n const hydrated = new PivotData({\n data: materialized.materializedInput,\n precomputedData: serialized,\n aggregations: multiAggregationConfig,\n rows: ['gender'],\n cols: ['colour'],\n valueFilter: {gender: {male: true}},\n });\n expect(hydrated.getRowKeys()).toEqual(direct.getRowKeys());\n expect(hydrated.getAggregator([], [], 'count').value()).toBe(\n direct.getAggregator([], [], 'count').value()\n );\n });\n\n it('re-sorts keys on the main thread for function sorters', function() {\n const materialized = pivotCompute.materializeData(records, {});\n const serialized = pivotCompute.computePivotState(materialized, config);\n const reverseSorter = (a, b) => (a < b ? 1 : a > b ? -1 : 0);\n const hydrated = new PivotData({\n data: materialized.materializedInput,\n precomputedData: serialized,\n aggregations: multiAggregationConfig,\n rows: ['gender'],\n cols: ['colour'],\n sorters: {gender: reverseSorter},\n });\n const keys = hydrated.getRowKeys().map(key => key[0]);\n expect(keys.indexOf('male')).toBeLessThan(keys.indexOf('female'));\n });\n });\n\n describe('.createComputeSignature()', function() {\n it('is stable for identical configs and differs otherwise', function() {\n const props = {\n rows: ['gender'],\n cols: [],\n aggregations: multiAggregationConfig,\n valueFilter: {},\n sorters: {},\n };\n const first = pivotCompute.createComputeSignature(props);\n const second = pivotCompute.createComputeSignature(\n Object.assign({}, props)\n );\n expect(first).toBe(second);\n const different = pivotCompute.createComputeSignature(\n Object.assign({}, props, {rows: ['colour']})\n );\n expect(different).not.toBe(first);\n });\n\n it('strips function-based sorters from the signature', function() {\n const props = {\n rows: ['gender'],\n sorters: {gender: (a, b) => a.localeCompare(b)},\n };\n const signature = pivotCompute.createComputeSignature(props);\n expect(signature).not.toContain('localeCompare');\n });\n });\n\n describe('.canComputeInWorker()', function() {\n const eligibleProps = {\n data: records,\n aggregators: PivotData.defaultProps.aggregators,\n derivedAttributes: {},\n };\n\n beforeAll(function() {\n // jsdom has no Worker implementation; simulate availability.\n global.Worker = function FakeWorker() {};\n });\n\n it('accepts plain-array datasets above the threshold', function() {\n expect(\n pivotCompute.canComputeInWorker(eligibleProps, {threshold: 2})\n ).toBe(true);\n });\n\n it('rejects datasets below the threshold', function() {\n expect(\n pivotCompute.canComputeInWorker(eligibleProps, {threshold: 1000})\n ).toBe(false);\n });\n\n it('rejects custom aggregator maps', function() {\n const props = Object.assign({}, eligibleProps, {\n aggregators: {Count: () => () => ({})},\n });\n expect(pivotCompute.canComputeInWorker(props, {threshold: 2})).toBe(\n false\n );\n });\n\n it('rejects custom derived attributes', function() {\n const props = Object.assign({}, eligibleProps, {\n derivedAttributes: {extra: record => record.name},\n });\n expect(pivotCompute.canComputeInWorker(props, {threshold: 2})).toBe(\n false\n );\n });\n\n it('rejects disabled mode', function() {\n expect(\n pivotCompute.canComputeInWorker(eligibleProps, {\n enabled: false,\n threshold: 2,\n })\n ).toBe(false);\n });\n });\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/__tests__/pivotCompute-test.js"],"names":["pivotCompute","records","name","gender","colour","trials","successes","multiAggregationConfig","key","aggregatorName","vals","describe","it","materialized","materializeData","expect","totalRecords","toBe","materializedInput","toEqual","attrValues","male","female","maybeCallback","jest","fn","not","toHaveBeenCalled","config","rows","cols","aggregations","serialized","computePivotState","direct","PivotData","Object","assign","data","hydrated","precomputedData","getRowKeys","getColKeys","compareCells","rowKey","colKey","forEach","getAggregator","agg","value","directFormat","format","hydratedFormat","filteredConfig","valueFilter","reverseSorter","a","b","sorters","keys","map","indexOf","toBeLessThan","props","first","createComputeSignature","second","different","localeCompare","signature","toContain","eligibleProps","aggregators","defaultProps","derivedAttributes","beforeAll","global","Worker","FakeWorker","canComputeInWorker","threshold","Count","extra","record","enabled"],"mappings":"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","file":"pivotCompute-test.js","sourcesContent":["import * as pivotCompute from '../pivotCompute';\nimport {PivotData} from '../Utilities';\n/* eslint-disable no-magic-numbers */\n\nconst records = [\n {name: 'Nick', gender: 'male', colour: 'blue', trials: 103, successes: 12},\n {name: 'Jane', gender: 'female', colour: 'red', trials: 95, successes: 25},\n {name: 'John', gender: 'male', colour: 'blue', trials: 112, successes: 30},\n {\n name: 'Carol',\n gender: 'female',\n colour: 'yellow',\n trials: 102,\n successes: 14,\n },\n];\n\nconst multiAggregationConfig = [\n {key: 'sum-trials', aggregatorName: 'Sum', vals: ['trials']},\n {key: 'count', aggregatorName: 'Count', vals: []},\n];\n\ndescribe(' pivotCompute', function() {\n describe('.materializeData()', function() {\n it('collects attribute values and materialized records', function() {\n const materialized = pivotCompute.materializeData(records, {});\n expect(materialized.totalRecords).toBe(4);\n expect(materialized.materializedInput).toEqual(records);\n expect(materialized.attrValues.gender).toEqual({male: 2, female: 2});\n });\n\n it('reports no progress (percentages were removed)', function() {\n // materializeData no longer accepts an onProgress callback: passing\n // one is ignored and nothing is reported during the scan.\n const maybeCallback = jest.fn();\n const materialized = pivotCompute.materializeData(\n records,\n {},\n maybeCallback\n );\n expect(materialized.totalRecords).toBe(4);\n expect(maybeCallback).not.toHaveBeenCalled();\n });\n });\n\n describe('.computePivotState() with PivotData hydration', function() {\n const config = {\n rows: ['gender'],\n cols: ['colour'],\n aggregations: multiAggregationConfig,\n };\n\n it('hydrates to the same results as a direct PivotData build', function() {\n const materialized = pivotCompute.materializeData(records, {});\n const serialized = pivotCompute.computePivotState(materialized, config);\n const direct = new PivotData(Object.assign({}, config, {data: records}));\n const hydrated = new PivotData({\n data: materialized.materializedInput,\n precomputedData: serialized,\n aggregations: multiAggregationConfig,\n rows: ['gender'],\n cols: ['colour'],\n });\n\n expect(hydrated.getRowKeys()).toEqual(direct.getRowKeys());\n expect(hydrated.getColKeys()).toEqual(direct.getColKeys());\n\n const compareCells = (rowKey, colKey) => {\n multiAggregationConfig.forEach(agg => {\n expect(hydrated.getAggregator(rowKey, colKey, agg.key).value()).toBe(\n direct.getAggregator(rowKey, colKey, agg.key).value()\n );\n });\n };\n\n compareCells([], []);\n direct.getRowKeys().forEach(rowKey => {\n compareCells(rowKey, []);\n direct.getColKeys().forEach(colKey => {\n compareCells(rowKey, colKey);\n });\n });\n direct.getColKeys().forEach(colKey => {\n compareCells([], colKey);\n });\n });\n\n it('provides working format() on hydrated aggregators', function() {\n const materialized = pivotCompute.materializeData(records, {});\n const serialized = pivotCompute.computePivotState(materialized, config);\n const direct = new PivotData(Object.assign({}, config, {data: records}));\n const hydrated = new PivotData({\n data: materialized.materializedInput,\n precomputedData: serialized,\n aggregations: multiAggregationConfig,\n rows: ['gender'],\n cols: ['colour'],\n });\n\n const directFormat = direct\n .getAggregator([], [], 'sum-trials')\n .format(1234.5);\n const hydratedFormat = hydrated\n .getAggregator([], [], 'sum-trials')\n .format(1234.5);\n expect(hydratedFormat).toBe(directFormat);\n });\n\n it('respects valueFilter like the classic path', function() {\n const filteredConfig = Object.assign({}, config, {\n valueFilter: {gender: {male: true}},\n });\n const materialized = pivotCompute.materializeData(records, {});\n const serialized = pivotCompute.computePivotState(\n materialized,\n filteredConfig\n );\n const direct = new PivotData(\n Object.assign({}, filteredConfig, {data: records})\n );\n const hydrated = new PivotData({\n data: materialized.materializedInput,\n precomputedData: serialized,\n aggregations: multiAggregationConfig,\n rows: ['gender'],\n cols: ['colour'],\n valueFilter: {gender: {male: true}},\n });\n expect(hydrated.getRowKeys()).toEqual(direct.getRowKeys());\n expect(hydrated.getAggregator([], [], 'count').value()).toBe(\n direct.getAggregator([], [], 'count').value()\n );\n });\n\n it('re-sorts keys on the main thread for function sorters', function() {\n const materialized = pivotCompute.materializeData(records, {});\n const serialized = pivotCompute.computePivotState(materialized, config);\n const reverseSorter = (a, b) => (a < b ? 1 : a > b ? -1 : 0);\n const hydrated = new PivotData({\n data: materialized.materializedInput,\n precomputedData: serialized,\n aggregations: multiAggregationConfig,\n rows: ['gender'],\n cols: ['colour'],\n sorters: {gender: reverseSorter},\n });\n const keys = hydrated.getRowKeys().map(key => key[0]);\n expect(keys.indexOf('male')).toBeLessThan(keys.indexOf('female'));\n });\n });\n\n describe('.createComputeSignature()', function() {\n it('is stable for identical configs and differs otherwise', function() {\n const props = {\n rows: ['gender'],\n cols: [],\n aggregations: multiAggregationConfig,\n valueFilter: {},\n sorters: {},\n };\n const first = pivotCompute.createComputeSignature(props);\n const second = pivotCompute.createComputeSignature(\n Object.assign({}, props)\n );\n expect(first).toBe(second);\n const different = pivotCompute.createComputeSignature(\n Object.assign({}, props, {rows: ['colour']})\n );\n expect(different).not.toBe(first);\n });\n\n it('strips function-based sorters from the signature', function() {\n const props = {\n rows: ['gender'],\n sorters: {gender: (a, b) => a.localeCompare(b)},\n };\n const signature = pivotCompute.createComputeSignature(props);\n expect(signature).not.toContain('localeCompare');\n });\n });\n\n describe('.canComputeInWorker()', function() {\n const eligibleProps = {\n data: records,\n aggregators: PivotData.defaultProps.aggregators,\n derivedAttributes: {},\n };\n\n beforeAll(function() {\n // jsdom has no Worker implementation; simulate availability.\n global.Worker = function FakeWorker() {};\n });\n\n it('accepts plain-array datasets above the threshold', function() {\n expect(\n pivotCompute.canComputeInWorker(eligibleProps, {threshold: 2})\n ).toBe(true);\n });\n\n it('rejects datasets below the threshold', function() {\n expect(\n pivotCompute.canComputeInWorker(eligibleProps, {threshold: 1000})\n ).toBe(false);\n });\n\n it('rejects custom aggregator maps', function() {\n const props = Object.assign({}, eligibleProps, {\n aggregators: {Count: () => () => ({})},\n });\n expect(pivotCompute.canComputeInWorker(props, {threshold: 2})).toBe(\n false\n );\n });\n\n it('rejects custom derived attributes', function() {\n const props = Object.assign({}, eligibleProps, {\n derivedAttributes: {extra: record => record.name},\n });\n expect(pivotCompute.canComputeInWorker(props, {threshold: 2})).toBe(\n false\n );\n });\n\n it('rejects disabled mode', function() {\n expect(\n pivotCompute.canComputeInWorker(eligibleProps, {\n enabled: false,\n threshold: 2,\n })\n ).toBe(false);\n });\n });\n});\n"]}
|
package/dist/pivot-worker.js
CHANGED
|
@@ -346,15 +346,7 @@ self.addEventListener('message', function (event) {
|
|
|
346
346
|
var startedAt = Date.now();
|
|
347
347
|
log('#' + message.id + ' setData received: ' + (message.data || []).length + ' records (dataKey=' + message.dataKey + ')');
|
|
348
348
|
try {
|
|
349
|
-
var dataset = cacheDataset(message.dataKey, Object(__WEBPACK_IMPORTED_MODULE_0__pivotCompute__["b" /* materializeData */])(message.data, {}
|
|
350
|
-
postToMain({
|
|
351
|
-
type: 'pivot:progress',
|
|
352
|
-
id: message.id,
|
|
353
|
-
processed: processed,
|
|
354
|
-
total: total,
|
|
355
|
-
phase: 'materialize'
|
|
356
|
-
});
|
|
357
|
-
}));
|
|
349
|
+
var dataset = cacheDataset(message.dataKey, Object(__WEBPACK_IMPORTED_MODULE_0__pivotCompute__["b" /* materializeData */])(message.data, {}));
|
|
358
350
|
log('#' + message.id + ' materialized ' + dataset.totalRecords + ' records in ' + (Date.now() - startedAt + 'ms (attributes: ' + Object.keys(dataset.attrValues).join(', ') + ')'));
|
|
359
351
|
} catch (error) {
|
|
360
352
|
log('#' + message.id + ' setData failed: ' + toErrorMessage(error));
|
|
@@ -376,15 +368,7 @@ self.addEventListener('message', function (event) {
|
|
|
376
368
|
throw new Error('no dataset staged for key ' + message.dataKey);
|
|
377
369
|
}
|
|
378
370
|
log('#' + message.id + ' compute received (rows=[' + (config.rows || []).join(', ') + '] cols=[' + (config.cols || []).join(', ') + '])');
|
|
379
|
-
var result = Object(__WEBPACK_IMPORTED_MODULE_0__pivotCompute__["a" /* computePivotState */])(_dataset, message.config
|
|
380
|
-
postToMain({
|
|
381
|
-
type: 'pivot:progress',
|
|
382
|
-
id: message.id,
|
|
383
|
-
processed: processed,
|
|
384
|
-
total: total,
|
|
385
|
-
phase: phase
|
|
386
|
-
});
|
|
387
|
-
});
|
|
371
|
+
var result = Object(__WEBPACK_IMPORTED_MODULE_0__pivotCompute__["a" /* computePivotState */])(_dataset, message.config);
|
|
388
372
|
log('#' + message.id + ' computed in ' + (Date.now() - _startedAt) + 'ms (rowKeys: ' + result.rowKeys.length + ', colKeys: ' + result.colKeys.length + ', aggregations: ' + result.aggregations.map(function (agg) {
|
|
389
373
|
return agg.key;
|
|
390
374
|
}).join(', ') + ')');
|
|
@@ -405,7 +389,6 @@ self.addEventListener('message', function (event) {
|
|
|
405
389
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
406
390
|
|
|
407
391
|
"use strict";
|
|
408
|
-
/* unused harmony export PROGRESS_BATCH_SIZE */
|
|
409
392
|
/* unused harmony export DEFAULT_WORKER_THRESHOLD */
|
|
410
393
|
/* unused harmony export WORKER_DEBOUNCE_MS */
|
|
411
394
|
/* harmony export (immutable) */ __webpack_exports__["b"] = materializeData;
|
|
@@ -433,30 +416,22 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
|
|
433
416
|
*/
|
|
434
417
|
|
|
435
418
|
|
|
436
|
-
// A progress callback fires every N processed records so the UI can render
|
|
437
|
-
// progress without adding measurable overhead to the per-record loop.
|
|
438
|
-
var PROGRESS_BATCH_SIZE = 200;
|
|
439
|
-
|
|
440
419
|
// Datasets smaller than this are computed synchronously on the main thread;
|
|
441
420
|
// larger ones are handed off to the Web Worker.
|
|
442
421
|
var DEFAULT_WORKER_THRESHOLD = 200;
|
|
443
422
|
|
|
444
423
|
// Trailing debounce before a worker computation is dispatched, so rapid
|
|
445
424
|
// interactions do not queue one full computation per single change.
|
|
446
|
-
var WORKER_DEBOUNCE_MS =
|
|
425
|
+
var WORKER_DEBOUNCE_MS = 100;
|
|
447
426
|
|
|
448
427
|
/*
|
|
449
428
|
* Walks the raw input once and computes the attribute-value inventory plus a
|
|
450
429
|
* "materialized" copy of the records (with derived attributes applied).
|
|
451
430
|
* This is an exact extraction of the historical PivotTableUI behavior.
|
|
452
|
-
*
|
|
453
|
-
* onProgress receives (processed, total, phase); total is null when it is
|
|
454
|
-
* unknown upfront (function-based data sources).
|
|
455
431
|
*/
|
|
456
|
-
function materializeData(data, derivedAttributes
|
|
432
|
+
function materializeData(data, derivedAttributes) {
|
|
457
433
|
var attrValues = {};
|
|
458
434
|
var materializedInput = [];
|
|
459
|
-
var total = Array.isArray(data) ? data.length : null;
|
|
460
435
|
var recordsProcessed = 0;
|
|
461
436
|
__WEBPACK_IMPORTED_MODULE_0__Utilities__["a" /* PivotData */].forEachRecord(data, derivedAttributes || {}, function (record) {
|
|
462
437
|
materializedInput.push(record);
|
|
@@ -498,9 +473,6 @@ function materializeData(data, derivedAttributes, onProgress) {
|
|
|
498
473
|
attrValues[_attr][value]++;
|
|
499
474
|
}
|
|
500
475
|
recordsProcessed++;
|
|
501
|
-
if (onProgress && recordsProcessed % PROGRESS_BATCH_SIZE === 0) {
|
|
502
|
-
onProgress(recordsProcessed, total, 'materialize');
|
|
503
|
-
}
|
|
504
476
|
});
|
|
505
477
|
return { attrValues: attrValues, materializedInput: materializedInput, totalRecords: recordsProcessed };
|
|
506
478
|
}
|
|
@@ -510,16 +482,10 @@ function materializeData(data, derivedAttributes, onProgress) {
|
|
|
510
482
|
* serializes the result into a plain (structured-cloneable) object that can
|
|
511
483
|
* cross the worker boundary and later hydrate PivotData on the main thread.
|
|
512
484
|
*/
|
|
513
|
-
function computePivotState(materialized, config
|
|
514
|
-
var total = materialized.totalRecords;
|
|
485
|
+
function computePivotState(materialized, config) {
|
|
515
486
|
var pivotData = new __WEBPACK_IMPORTED_MODULE_0__Utilities__["a" /* PivotData */](Object.assign({}, config, {
|
|
516
487
|
data: materialized.materializedInput,
|
|
517
|
-
derivedAttributes: {}
|
|
518
|
-
onRecordProcessed: function onRecordProcessed(processed) {
|
|
519
|
-
if (onProgress) {
|
|
520
|
-
onProgress(processed, total, 'aggregate');
|
|
521
|
-
}
|
|
522
|
-
}
|
|
488
|
+
derivedAttributes: {}
|
|
523
489
|
}));
|
|
524
490
|
// Force key sorting to happen while we are (possibly) inside the worker.
|
|
525
491
|
pivotData.getRowKeys();
|
|
@@ -1073,10 +1039,6 @@ var usFmtPct = numberFormat({
|
|
|
1073
1039
|
suffix: '%'
|
|
1074
1040
|
});
|
|
1075
1041
|
|
|
1076
|
-
// Emit a progress callback every N processed records without adding
|
|
1077
|
-
// measurable overhead to the per-record loop.
|
|
1078
|
-
var RECORD_PROGRESS_BATCH_SIZE = 200;
|
|
1079
|
-
|
|
1080
1042
|
// Returns true when the sorters prop itself, or any of its entries, is a
|
|
1081
1043
|
// function. Function-based sorters cannot be transferred to a Web Worker, so
|
|
1082
1044
|
// PivotData re-applies them on the main thread after worker hydration.
|
|
@@ -1563,24 +1525,11 @@ var PivotData = function () {
|
|
|
1563
1525
|
return;
|
|
1564
1526
|
}
|
|
1565
1527
|
|
|
1566
|
-
|
|
1567
|
-
var recordHandler = function recordHandler(record) {
|
|
1528
|
+
PivotData.forEachRecord(this.props.data, this.props.derivedAttributes, function (record) {
|
|
1568
1529
|
if (_this2.filter(record)) {
|
|
1569
1530
|
_this2.processRecord(record);
|
|
1570
1531
|
}
|
|
1571
|
-
};
|
|
1572
|
-
if (typeof progressHook === 'function') {
|
|
1573
|
-
var recordsProcessed = 0;
|
|
1574
|
-
PivotData.forEachRecord(this.props.data, this.props.derivedAttributes, function (record) {
|
|
1575
|
-
recordHandler(record);
|
|
1576
|
-
recordsProcessed++;
|
|
1577
|
-
if (recordsProcessed % RECORD_PROGRESS_BATCH_SIZE === 0) {
|
|
1578
|
-
progressHook(recordsProcessed);
|
|
1579
|
-
}
|
|
1580
|
-
});
|
|
1581
|
-
} else {
|
|
1582
|
-
PivotData.forEachRecord(this.props.data, this.props.derivedAttributes, recordHandler);
|
|
1583
|
-
}
|
|
1532
|
+
});
|
|
1584
1533
|
}
|
|
1585
1534
|
|
|
1586
1535
|
/*
|
|
@@ -2245,7 +2194,6 @@ PivotData.propTypes = {
|
|
|
2245
2194
|
sorters: __WEBPACK_IMPORTED_MODULE_0_prop_types___default.a.oneOfType([__WEBPACK_IMPORTED_MODULE_0_prop_types___default.a.func, __WEBPACK_IMPORTED_MODULE_0_prop_types___default.a.objectOf(__WEBPACK_IMPORTED_MODULE_0_prop_types___default.a.oneOfType([__WEBPACK_IMPORTED_MODULE_0_prop_types___default.a.func, __WEBPACK_IMPORTED_MODULE_0_prop_types___default.a.string, __WEBPACK_IMPORTED_MODULE_0_prop_types___default.a.array]))]),
|
|
2246
2195
|
derivedAttributes: __WEBPACK_IMPORTED_MODULE_0_prop_types___default.a.objectOf(__WEBPACK_IMPORTED_MODULE_0_prop_types___default.a.func),
|
|
2247
2196
|
precomputedData: __WEBPACK_IMPORTED_MODULE_0_prop_types___default.a.object,
|
|
2248
|
-
onRecordProcessed: __WEBPACK_IMPORTED_MODULE_0_prop_types___default.a.func,
|
|
2249
2197
|
rowOrder: __WEBPACK_IMPORTED_MODULE_0_prop_types___default.a.oneOf(['key_a_to_z', 'value_a_to_z', 'value_z_to_a']),
|
|
2250
2198
|
colOrder: __WEBPACK_IMPORTED_MODULE_0_prop_types___default.a.oneOf(['key_a_to_z', 'value_a_to_z', 'value_z_to_a']),
|
|
2251
2199
|
rowSorts: __WEBPACK_IMPORTED_MODULE_0_prop_types___default.a.objectOf(__WEBPACK_IMPORTED_MODULE_0_prop_types___default.a.oneOf(['ASC', 'DESC'])),
|
package/dist/pivotCompute.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.WORKER_DEBOUNCE_MS = exports.DEFAULT_WORKER_THRESHOLD =
|
|
6
|
+
exports.WORKER_DEBOUNCE_MS = exports.DEFAULT_WORKER_THRESHOLD = undefined;
|
|
7
7
|
|
|
8
8
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /* eslint-disable no-console */
|
|
9
9
|
/* eslint-disable valid-jsdoc */
|
|
@@ -30,30 +30,22 @@ exports.canComputeInWorker = canComputeInWorker;
|
|
|
30
30
|
|
|
31
31
|
var _Utilities = require('./Utilities');
|
|
32
32
|
|
|
33
|
-
// A progress callback fires every N processed records so the UI can render
|
|
34
|
-
// progress without adding measurable overhead to the per-record loop.
|
|
35
|
-
var PROGRESS_BATCH_SIZE = exports.PROGRESS_BATCH_SIZE = 200;
|
|
36
|
-
|
|
37
33
|
// Datasets smaller than this are computed synchronously on the main thread;
|
|
38
34
|
// larger ones are handed off to the Web Worker.
|
|
39
35
|
var DEFAULT_WORKER_THRESHOLD = exports.DEFAULT_WORKER_THRESHOLD = 200;
|
|
40
36
|
|
|
41
37
|
// Trailing debounce before a worker computation is dispatched, so rapid
|
|
42
38
|
// interactions do not queue one full computation per single change.
|
|
43
|
-
var WORKER_DEBOUNCE_MS = exports.WORKER_DEBOUNCE_MS =
|
|
39
|
+
var WORKER_DEBOUNCE_MS = exports.WORKER_DEBOUNCE_MS = 100;
|
|
44
40
|
|
|
45
41
|
/*
|
|
46
42
|
* Walks the raw input once and computes the attribute-value inventory plus a
|
|
47
43
|
* "materialized" copy of the records (with derived attributes applied).
|
|
48
44
|
* This is an exact extraction of the historical PivotTableUI behavior.
|
|
49
|
-
*
|
|
50
|
-
* onProgress receives (processed, total, phase); total is null when it is
|
|
51
|
-
* unknown upfront (function-based data sources).
|
|
52
45
|
*/
|
|
53
|
-
function materializeData(data, derivedAttributes
|
|
46
|
+
function materializeData(data, derivedAttributes) {
|
|
54
47
|
var attrValues = {};
|
|
55
48
|
var materializedInput = [];
|
|
56
|
-
var total = Array.isArray(data) ? data.length : null;
|
|
57
49
|
var recordsProcessed = 0;
|
|
58
50
|
_Utilities.PivotData.forEachRecord(data, derivedAttributes || {}, function (record) {
|
|
59
51
|
materializedInput.push(record);
|
|
@@ -95,9 +87,6 @@ function materializeData(data, derivedAttributes, onProgress) {
|
|
|
95
87
|
attrValues[_attr][value]++;
|
|
96
88
|
}
|
|
97
89
|
recordsProcessed++;
|
|
98
|
-
if (onProgress && recordsProcessed % PROGRESS_BATCH_SIZE === 0) {
|
|
99
|
-
onProgress(recordsProcessed, total, 'materialize');
|
|
100
|
-
}
|
|
101
90
|
});
|
|
102
91
|
return { attrValues: attrValues, materializedInput: materializedInput, totalRecords: recordsProcessed };
|
|
103
92
|
}
|
|
@@ -107,16 +96,10 @@ function materializeData(data, derivedAttributes, onProgress) {
|
|
|
107
96
|
* serializes the result into a plain (structured-cloneable) object that can
|
|
108
97
|
* cross the worker boundary and later hydrate PivotData on the main thread.
|
|
109
98
|
*/
|
|
110
|
-
function computePivotState(materialized, config
|
|
111
|
-
var total = materialized.totalRecords;
|
|
99
|
+
function computePivotState(materialized, config) {
|
|
112
100
|
var pivotData = new _Utilities.PivotData(Object.assign({}, config, {
|
|
113
101
|
data: materialized.materializedInput,
|
|
114
|
-
derivedAttributes: {}
|
|
115
|
-
onRecordProcessed: function onRecordProcessed(processed) {
|
|
116
|
-
if (onProgress) {
|
|
117
|
-
onProgress(processed, total, 'aggregate');
|
|
118
|
-
}
|
|
119
|
-
}
|
|
102
|
+
derivedAttributes: {}
|
|
120
103
|
}));
|
|
121
104
|
// Force key sorting to happen while we are (possibly) inside the worker.
|
|
122
105
|
pivotData.getRowKeys();
|
package/dist/pivotCompute.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/pivotCompute.js"],"names":["materializeData","computePivotState","serializePivotData","sortersHaveFunctions","sanitizeSorters","createWorkerConfig","createComputeSignature","canComputeInWorker","PROGRESS_BATCH_SIZE","DEFAULT_WORKER_THRESHOLD","WORKER_DEBOUNCE_MS","data","derivedAttributes","onProgress","attrValues","materializedInput","total","Array","isArray","length","recordsProcessed","PivotData","forEachRecord","record","push","Object","keys","attr","null","value","totalRecords","materialized","config","pivotData","assign","onRecordProcessed","processed","getRowKeys","getColKeys","serializeCell","values","aggregations","forEach","instance","cell","getInstance","agg","key","tree","rowBranch","flatRowKey","serializedRow","flatColKey","serializeTotals","serialized","totals","flatKey","rowKeys","map","slice","colKeys","rowTotals","colTotals","allTotal","sorters","some","clean","sorter","props","rows","cols","aggregatorName","vals","valueFilter","rowOrder","colOrder","rowSorts","colSorts","JSON","stringify","options","enabled","Worker","threshold"],"mappings":"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","file":"pivotCompute.js","sourcesContent":["/* eslint-disable no-console */\n/* eslint-disable valid-jsdoc */\n/*\n * Shared pivot-computation logic.\n *\n * This module contains the pure, DOM-free parts of the pivot computation so\n * that the exact same code paths can run:\n * - on the main thread (classic synchronous rendering path), and\n * - inside a Web Worker (src/pivotWorker.js) for large datasets.\n *\n * It must stay free of React and of any `window`/`document` references.\n */\nimport {PivotData} from './Utilities';\n\n// A progress callback fires every N processed records so the UI can render\n// progress without adding measurable overhead to the per-record loop.\nexport const PROGRESS_BATCH_SIZE = 200;\n\n// Datasets smaller than this are computed synchronously on the main thread;\n// larger ones are handed off to the Web Worker.\nexport const DEFAULT_WORKER_THRESHOLD = 200;\n\n// Trailing debounce before a worker computation is dispatched, so rapid\n// interactions do not queue one full computation per single change.\nexport const WORKER_DEBOUNCE_MS = 50;\n\n/*\n * Walks the raw input once and computes the attribute-value inventory plus a\n * \"materialized\" copy of the records (with derived attributes applied).\n * This is an exact extraction of the historical PivotTableUI behavior.\n *\n * onProgress receives (processed, total, phase); total is null when it is\n * unknown upfront (function-based data sources).\n */\nexport function materializeData(data, derivedAttributes, onProgress) {\n const attrValues = {};\n const materializedInput = [];\n const total = Array.isArray(data) ? data.length : null;\n let recordsProcessed = 0;\n PivotData.forEachRecord(data, derivedAttributes || {}, function(record) {\n materializedInput.push(record);\n for (const attr of Object.keys(record)) {\n if (!(attr in attrValues)) {\n attrValues[attr] = {};\n if (recordsProcessed > 0) {\n attrValues[attr].null = recordsProcessed;\n }\n }\n }\n for (const attr in attrValues) {\n const value = attr in record ? record[attr] : 'null';\n if (!(value in attrValues[attr])) {\n attrValues[attr][value] = 0;\n }\n attrValues[attr][value]++;\n }\n recordsProcessed++;\n if (onProgress && recordsProcessed % PROGRESS_BATCH_SIZE === 0) {\n onProgress(recordsProcessed, total, 'materialize');\n }\n });\n return {attrValues, materializedInput, totalRecords: recordsProcessed};\n}\n\n/*\n * Aggregates an already-materialized dataset into a PivotData instance and\n * serializes the result into a plain (structured-cloneable) object that can\n * cross the worker boundary and later hydrate PivotData on the main thread.\n */\nexport function computePivotState(materialized, config, onProgress) {\n const total = materialized.totalRecords;\n const pivotData = new PivotData(\n Object.assign({}, config, {\n data: materialized.materializedInput,\n derivedAttributes: {},\n onRecordProcessed: processed => {\n if (onProgress) {\n onProgress(processed, total, 'aggregate');\n }\n },\n })\n );\n // Force key sorting to happen while we are (possibly) inside the worker.\n pivotData.getRowKeys();\n pivotData.getColKeys();\n return serializePivotData(pivotData, materialized);\n}\n\n/*\n * Serializes a fully-built PivotData instance into plain data. Only the final\n * aggregated value of every cell is kept; `value()` and `format()` behavior\n * are reconstructed on the main thread by the PivotData hydration step.\n */\nexport function serializePivotData(pivotData, materialized) {\n const serializeCell = cell => {\n const values = {};\n pivotData.aggregations.forEach(agg => {\n const instance = cell.getInstance(agg.key);\n if (instance) {\n values[agg.key] = instance.value();\n }\n });\n return {values};\n };\n\n const tree = {};\n Object.keys(pivotData.tree).forEach(flatRowKey => {\n const rowBranch = pivotData.tree[flatRowKey];\n const serializedRow = {};\n Object.keys(rowBranch).forEach(flatColKey => {\n serializedRow[flatColKey] = serializeCell(rowBranch[flatColKey]);\n });\n tree[flatRowKey] = serializedRow;\n });\n\n const serializeTotals = totals => {\n const serialized = {};\n Object.keys(totals).forEach(flatKey => {\n serialized[flatKey] = serializeCell(totals[flatKey]);\n });\n return serialized;\n };\n\n return {\n rowKeys: pivotData.rowKeys.map(key => key.slice()),\n colKeys: pivotData.colKeys.map(key => key.slice()),\n tree,\n rowTotals: serializeTotals(pivotData.rowTotals),\n colTotals: serializeTotals(pivotData.colTotals),\n allTotal: serializeCell(pivotData.allTotal),\n aggregations: pivotData.aggregations.map(agg => Object.assign({}, agg)),\n attrValues: materialized.attrValues,\n materializedInput: materialized.materializedInput,\n totalRecords: materialized.totalRecords,\n };\n}\n\n/*\n * Sorters containing functions cannot be structured-cloned into a worker.\n * Returns true when the sorters prop itself, or any of its entries, is a\n * function. In that case PivotData re-sorts on the main thread after\n * hydration (distinct keys are few, so this stays cheap).\n */\nexport function sortersHaveFunctions(sorters) {\n if (typeof sorters === 'function') {\n return true;\n }\n if (!sorters || typeof sorters !== 'object') {\n return false;\n }\n return Object.keys(sorters).some(attr => typeof sorters[attr] === 'function');\n}\n\n/*\n * Returns a structured-cloneable subset of the sorters prop: data-type names\n * and sample-value arrays survive the worker boundary, functions do not.\n */\nexport function sanitizeSorters(sorters) {\n if (\n !sorters ||\n typeof sorters !== 'object' ||\n typeof sorters === 'function'\n ) {\n return {};\n }\n const clean = {};\n Object.keys(sorters).forEach(attr => {\n const sorter = sorters[attr];\n if (typeof sorter === 'string' || Array.isArray(sorter)) {\n clean[attr] = sorter;\n }\n });\n return clean;\n}\n\n/*\n * Extracts exactly the props PivotData needs to compute results, with\n * everything non-serializable stripped, so the object can be posted to the\n * worker and fed straight into PivotData.\n */\nexport function createWorkerConfig(props) {\n return {\n rows: props.rows,\n cols: props.cols,\n aggregatorName: props.aggregatorName,\n aggregations: props.aggregations,\n vals: props.vals,\n valueFilter: props.valueFilter,\n sorters: sanitizeSorters(props.sorters),\n rowOrder: props.rowOrder,\n colOrder: props.colOrder,\n rowSorts: props.rowSorts,\n colSorts: props.colSorts,\n };\n}\n\n/*\n * Stable string signature of everything that influences a worker computation.\n * Data identity is NOT part of it; callers append their own data version.\n */\nexport function createComputeSignature(props) {\n return JSON.stringify(createWorkerConfig(props));\n}\n\n/*\n * Decides whether the current props can be computed inside the Web Worker.\n * Anything that cannot be structured-cloned (function data sources, custom\n * derivedAttributes, custom aggregator maps) forces the classic path.\n * Function-based sorters are allowed: they are re-applied on the main thread.\n */\nexport function canComputeInWorker(props, options = {}) {\n if (options.enabled === false) {\n return false;\n }\n if (typeof Worker === 'undefined') {\n return false;\n }\n const threshold =\n typeof options.threshold === 'number'\n ? options.threshold\n : DEFAULT_WORKER_THRESHOLD;\n \n const data = props.data;\n if (!Array.isArray(data) || data.length < threshold) {\n return false;\n }\n return true;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/pivotCompute.js"],"names":["materializeData","computePivotState","serializePivotData","sortersHaveFunctions","sanitizeSorters","createWorkerConfig","createComputeSignature","canComputeInWorker","DEFAULT_WORKER_THRESHOLD","WORKER_DEBOUNCE_MS","data","derivedAttributes","attrValues","materializedInput","recordsProcessed","PivotData","forEachRecord","record","push","Object","keys","attr","null","value","totalRecords","materialized","config","pivotData","assign","getRowKeys","getColKeys","serializeCell","values","aggregations","forEach","instance","cell","getInstance","agg","key","tree","rowBranch","flatRowKey","serializedRow","flatColKey","serializeTotals","serialized","totals","flatKey","rowKeys","map","slice","colKeys","rowTotals","colTotals","allTotal","sorters","some","clean","sorter","Array","isArray","props","rows","cols","aggregatorName","vals","valueFilter","rowOrder","colOrder","rowSorts","colSorts","JSON","stringify","options","enabled","Worker","threshold","length"],"mappings":"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","file":"pivotCompute.js","sourcesContent":["/* eslint-disable no-console */\n/* eslint-disable valid-jsdoc */\n/*\n * Shared pivot-computation logic.\n *\n * This module contains the pure, DOM-free parts of the pivot computation so\n * that the exact same code paths can run:\n * - on the main thread (classic synchronous rendering path), and\n * - inside a Web Worker (src/pivotWorker.js) for large datasets.\n *\n * It must stay free of React and of any `window`/`document` references.\n */\nimport {PivotData} from './Utilities';\n\n// Datasets smaller than this are computed synchronously on the main thread;\n// larger ones are handed off to the Web Worker.\nexport const DEFAULT_WORKER_THRESHOLD = 200;\n\n// Trailing debounce before a worker computation is dispatched, so rapid\n// interactions do not queue one full computation per single change.\nexport const WORKER_DEBOUNCE_MS = 100;\n\n/*\n * Walks the raw input once and computes the attribute-value inventory plus a\n * \"materialized\" copy of the records (with derived attributes applied).\n * This is an exact extraction of the historical PivotTableUI behavior.\n */\nexport function materializeData(data, derivedAttributes) {\n const attrValues = {};\n const materializedInput = [];\n let recordsProcessed = 0;\n PivotData.forEachRecord(data, derivedAttributes || {}, function(record) {\n materializedInput.push(record);\n for (const attr of Object.keys(record)) {\n if (!(attr in attrValues)) {\n attrValues[attr] = {};\n if (recordsProcessed > 0) {\n attrValues[attr].null = recordsProcessed;\n }\n }\n }\n for (const attr in attrValues) {\n const value = attr in record ? record[attr] : 'null';\n if (!(value in attrValues[attr])) {\n attrValues[attr][value] = 0;\n }\n attrValues[attr][value]++;\n }\n recordsProcessed++;\n });\n return {attrValues, materializedInput, totalRecords: recordsProcessed};\n}\n\n/*\n * Aggregates an already-materialized dataset into a PivotData instance and\n * serializes the result into a plain (structured-cloneable) object that can\n * cross the worker boundary and later hydrate PivotData on the main thread.\n */\nexport function computePivotState(materialized, config) {\n const pivotData = new PivotData(\n Object.assign({}, config, {\n data: materialized.materializedInput,\n derivedAttributes: {},\n })\n );\n // Force key sorting to happen while we are (possibly) inside the worker.\n pivotData.getRowKeys();\n pivotData.getColKeys();\n return serializePivotData(pivotData, materialized);\n}\n\n/*\n * Serializes a fully-built PivotData instance into plain data. Only the final\n * aggregated value of every cell is kept; `value()` and `format()` behavior\n * are reconstructed on the main thread by the PivotData hydration step.\n */\nexport function serializePivotData(pivotData, materialized) {\n const serializeCell = cell => {\n const values = {};\n pivotData.aggregations.forEach(agg => {\n const instance = cell.getInstance(agg.key);\n if (instance) {\n values[agg.key] = instance.value();\n }\n });\n return {values};\n };\n\n const tree = {};\n Object.keys(pivotData.tree).forEach(flatRowKey => {\n const rowBranch = pivotData.tree[flatRowKey];\n const serializedRow = {};\n Object.keys(rowBranch).forEach(flatColKey => {\n serializedRow[flatColKey] = serializeCell(rowBranch[flatColKey]);\n });\n tree[flatRowKey] = serializedRow;\n });\n\n const serializeTotals = totals => {\n const serialized = {};\n Object.keys(totals).forEach(flatKey => {\n serialized[flatKey] = serializeCell(totals[flatKey]);\n });\n return serialized;\n };\n\n return {\n rowKeys: pivotData.rowKeys.map(key => key.slice()),\n colKeys: pivotData.colKeys.map(key => key.slice()),\n tree,\n rowTotals: serializeTotals(pivotData.rowTotals),\n colTotals: serializeTotals(pivotData.colTotals),\n allTotal: serializeCell(pivotData.allTotal),\n aggregations: pivotData.aggregations.map(agg => Object.assign({}, agg)),\n attrValues: materialized.attrValues,\n materializedInput: materialized.materializedInput,\n totalRecords: materialized.totalRecords,\n };\n}\n\n/*\n * Sorters containing functions cannot be structured-cloned into a worker.\n * Returns true when the sorters prop itself, or any of its entries, is a\n * function. In that case PivotData re-sorts on the main thread after\n * hydration (distinct keys are few, so this stays cheap).\n */\nexport function sortersHaveFunctions(sorters) {\n if (typeof sorters === 'function') {\n return true;\n }\n if (!sorters || typeof sorters !== 'object') {\n return false;\n }\n return Object.keys(sorters).some(attr => typeof sorters[attr] === 'function');\n}\n\n/*\n * Returns a structured-cloneable subset of the sorters prop: data-type names\n * and sample-value arrays survive the worker boundary, functions do not.\n */\nexport function sanitizeSorters(sorters) {\n if (\n !sorters ||\n typeof sorters !== 'object' ||\n typeof sorters === 'function'\n ) {\n return {};\n }\n const clean = {};\n Object.keys(sorters).forEach(attr => {\n const sorter = sorters[attr];\n if (typeof sorter === 'string' || Array.isArray(sorter)) {\n clean[attr] = sorter;\n }\n });\n return clean;\n}\n\n/*\n * Extracts exactly the props PivotData needs to compute results, with\n * everything non-serializable stripped, so the object can be posted to the\n * worker and fed straight into PivotData.\n */\nexport function createWorkerConfig(props) {\n return {\n rows: props.rows,\n cols: props.cols,\n aggregatorName: props.aggregatorName,\n aggregations: props.aggregations,\n vals: props.vals,\n valueFilter: props.valueFilter,\n sorters: sanitizeSorters(props.sorters),\n rowOrder: props.rowOrder,\n colOrder: props.colOrder,\n rowSorts: props.rowSorts,\n colSorts: props.colSorts,\n };\n}\n\n/*\n * Stable string signature of everything that influences a worker computation.\n * Data identity is NOT part of it; callers append their own data version.\n */\nexport function createComputeSignature(props) {\n return JSON.stringify(createWorkerConfig(props));\n}\n\n/*\n * Decides whether the current props can be computed inside the Web Worker.\n * Anything that cannot be structured-cloned (function data sources, custom\n * derivedAttributes, custom aggregator maps) forces the classic path.\n * Function-based sorters are allowed: they are re-applied on the main thread.\n */\nexport function canComputeInWorker(props, options = {}) {\n if (options.enabled === false) {\n return false;\n }\n if (typeof Worker === 'undefined') {\n return false;\n }\n const threshold =\n typeof options.threshold === 'number'\n ? options.threshold\n : DEFAULT_WORKER_THRESHOLD;\n\n const data = props.data;\n if (!Array.isArray(data) || data.length < threshold) {\n return false;\n }\n return true;\n}\n"]}
|
package/dist/pivotWorker.js
CHANGED
|
@@ -45,15 +45,7 @@ self.addEventListener('message', function (event) {
|
|
|
45
45
|
var startedAt = Date.now();
|
|
46
46
|
log('#' + message.id + ' setData received: ' + (message.data || []).length + ' records (dataKey=' + message.dataKey + ')');
|
|
47
47
|
try {
|
|
48
|
-
var dataset = cacheDataset(message.dataKey, (0, _pivotCompute.materializeData)(message.data, {}
|
|
49
|
-
postToMain({
|
|
50
|
-
type: 'pivot:progress',
|
|
51
|
-
id: message.id,
|
|
52
|
-
processed: processed,
|
|
53
|
-
total: total,
|
|
54
|
-
phase: 'materialize'
|
|
55
|
-
});
|
|
56
|
-
}));
|
|
48
|
+
var dataset = cacheDataset(message.dataKey, (0, _pivotCompute.materializeData)(message.data, {}));
|
|
57
49
|
log('#' + message.id + ' materialized ' + dataset.totalRecords + ' records in ' + (Date.now() - startedAt + 'ms (attributes: ' + Object.keys(dataset.attrValues).join(', ') + ')'));
|
|
58
50
|
} catch (error) {
|
|
59
51
|
log('#' + message.id + ' setData failed: ' + toErrorMessage(error));
|
|
@@ -75,15 +67,7 @@ self.addEventListener('message', function (event) {
|
|
|
75
67
|
throw new Error('no dataset staged for key ' + message.dataKey);
|
|
76
68
|
}
|
|
77
69
|
log('#' + message.id + ' compute received (rows=[' + (config.rows || []).join(', ') + '] cols=[' + (config.cols || []).join(', ') + '])');
|
|
78
|
-
var result = (0, _pivotCompute.computePivotState)(_dataset, message.config
|
|
79
|
-
postToMain({
|
|
80
|
-
type: 'pivot:progress',
|
|
81
|
-
id: message.id,
|
|
82
|
-
processed: processed,
|
|
83
|
-
total: total,
|
|
84
|
-
phase: phase
|
|
85
|
-
});
|
|
86
|
-
});
|
|
70
|
+
var result = (0, _pivotCompute.computePivotState)(_dataset, message.config);
|
|
87
71
|
log('#' + message.id + ' computed in ' + (Date.now() - _startedAt) + 'ms (rowKeys: ' + result.rowKeys.length + ', colKeys: ' + result.colKeys.length + ', aggregations: ' + result.aggregations.map(function (agg) {
|
|
88
72
|
return agg.key;
|
|
89
73
|
}).join(', ') + ')');
|