diff options
| author | Julien Mougenot <jum@odoo.com> | 2020-06-19 07:06:28 +0000 |
|---|---|---|
| committer | Aaron Bohy <aab@odoo.com> | 2020-06-22 13:04:00 +0000 |
| commit | a6cd6d5a892f5a0501c0e81fe583bd64befff5d0 (patch) | |
| tree | 428d4f7b10bcda2e08f3b15ae78f53e7f91ab92b | |
| parent | 669bba4694896e29c088d6ce69440d3bef8e9fe5 (diff) | |
[IMP] web: utils: add groupBy function
This commit introduces a new utility function: 'groupBy'. It is
similar in API and result as the underscore method of the same
name.
X-original-commit: 834a1967161dc537cb2d5543314a062dbac08f9c
| -rw-r--r-- | addons/web/static/src/js/core/utils.js | 64 | ||||
| -rw-r--r-- | addons/web/static/tests/core/util_tests.js | 53 |
2 files changed, 104 insertions, 13 deletions
diff --git a/addons/web/static/src/js/core/utils.js b/addons/web/static/src/js/core/utils.js index 560f3a94466..17ce0e080b2 100644 --- a/addons/web/static/src/js/core/utils.js +++ b/addons/web/static/src/js/core/utils.js @@ -205,6 +205,28 @@ var diacriticsMap = { const patchMap = new WeakMap(); +/** + * Helper function returning an extraction handler to use on array elements to + * return a certain attribute or mutated form of the element. + * + * @private + * @param {string | function} criterion + * @returns {(element: any) => any} + */ +function _getExtractorFrom(criterion) { + if (criterion) { + switch (typeof criterion) { + case 'string': return element => element[criterion]; + case 'function': return criterion; + default: throw new Error( + `Expected criterion of type 'string' or 'function' and got '${typeof criterion}'` + ); + } + } else { + return element => element; + } +} + var utils = { /** @@ -304,6 +326,31 @@ var utils = { }); }, /** + * Returns an object holding different groups defined by a given criterion + * or a default one. Each group is a subset of the original given list. + * The given criterion can either be: + * - a string: a property name on the list elements which value will be the + * group name, + * - a function: a handler that will return the group name from a given + * element. + * + * @param {any[]} list + * @param {string | function} [criterion] + * @returns {Object} + */ + groupBy: function (list, criterion) { + const extract = _getExtractorFrom(criterion); + const groups = {}; + for (const element of list) { + const group = String(extract(element)); + if (!(group in groups)) { + groups[group] = []; + } + groups[group].push(element); + } + return groups; + }, + /** * Returns a human readable number (e.g. 34000 -> 34k). * * @param {number} number @@ -656,22 +703,13 @@ var utils = { * - a function: a handler that will return the sortable primitive from a given element. * * @param {any[]} array - * @param {(string|function)} [criterion] + * @param {string | function} [criterion] */ sortBy: function (array, criterion) { - let getter; - if (criterion) { - switch (typeof criterion) { - case 'string': getter = element => element[criterion]; break; - case 'function': getter = criterion; break; - default: throw new Error(`Expected criterion of type 'string' or 'function' and got '${typeof criterion}'`); - } - } else { - getter = element => element; - } + const extract = _getExtractorFrom(criterion); return array.slice().sort((elA, elB) => { - const a = getter(elA); - const b = getter(elB); + const a = extract(elA); + const b = extract(elB); if (isNaN(a) && isNaN(b)) { return a > b ? 1 : a < b ? -1 : 0; } else { diff --git a/addons/web/static/tests/core/util_tests.js b/addons/web/static/tests/core/util_tests.js index da6ac0d7737..6115833e4f2 100644 --- a/addons/web/static/tests/core/util_tests.js +++ b/addons/web/static/tests/core/util_tests.js @@ -7,6 +7,59 @@ QUnit.module('core', {}, function () { QUnit.module('utils'); + QUnit.test('groupBy', function (assert) { + assert.expect(7); + + const { groupBy } = utils; + + // Invalid + assert.throws( + () => groupBy({}), + new TypeError(`list is not iterable`) + ); + assert.throws( + () => groupBy([], true), + new Error(`Expected criterion of type 'string' or 'function' and got 'boolean'`) + ); + assert.throws( + () => groupBy([], 3), + new Error(`Expected criterion of type 'string' or 'function' and got 'number'`) + ); + assert.throws( + () => groupBy([], {}), + new Error(`Expected criterion of type 'string' or 'function' and got 'object'`) + ); + + // criterion = default + assert.deepEqual( + groupBy(["a", "b", 1, true]), + { + 1: [1], + a: ["a"], + b: ["b"], + true: [true], + } + ); + // criterion = string + assert.deepEqual( + groupBy([{ x: "a" }, { x: "a" }, { x: "b" }], "x"), + { + a: [{ x: "a" }, { x: "a" }], + b: [{ x: "b" }], + } + ); + // criterion = function + assert.deepEqual( + groupBy(["a", "b", 1, true], (x) => `el${x}`), + { + ela: ["a"], + elb: ["b"], + el1: [1], + eltrue: [true], + } + ); + }); + QUnit.test('intersperse', function (assert) { assert.expect(27); |
