mirror of
https://github.com/strapi/strapi.git
synced 2025-09-25 16:29:34 +00:00
feat(core-utils): add mapAsync and reduceAsync utils
This commit is contained in:
parent
ea3f7fa37e
commit
0168a2758a
70
packages/core/utils/lib/__tests__/async.test.js
Normal file
70
packages/core/utils/lib/__tests__/async.test.js
Normal file
@ -0,0 +1,70 @@
|
||||
'use strict';
|
||||
|
||||
const { mapAsync, reduceAsync } = require('../async');
|
||||
|
||||
describe('Async utils', () => {
|
||||
describe('mapAsync', () => {
|
||||
test('Should return a simple array of numbers', async () => {
|
||||
const numberPromiseArray = [Promise.resolve(1), Promise.resolve(2)];
|
||||
|
||||
const mapFunc = mapAsync(numberPromiseArray);
|
||||
const result = await mapFunc((number) => number + 1);
|
||||
|
||||
expect(result).toEqual([2, 3]);
|
||||
});
|
||||
test('Should work with mix of promises and values', async () => {
|
||||
const numberMixArray = [1, Promise.resolve(2)];
|
||||
|
||||
const mapFunc = mapAsync(numberMixArray);
|
||||
const result = await mapFunc((number) => number + 1);
|
||||
|
||||
expect(result).toEqual([2, 3]);
|
||||
});
|
||||
test('Should throw an error', async () => {
|
||||
const numberPromiseArray = [Promise.resolve(1), Promise.resolve(2)];
|
||||
|
||||
const mapFunc = mapAsync(numberPromiseArray);
|
||||
|
||||
await expect(async () => {
|
||||
await mapFunc(() => {
|
||||
throw new Error('test');
|
||||
});
|
||||
}).rejects.toThrow('test');
|
||||
});
|
||||
});
|
||||
describe('reduceAsync', () => {
|
||||
test('Should return a incremented number', async () => {
|
||||
const numberPromiseArray = [Promise.resolve(1), Promise.resolve(2)];
|
||||
|
||||
const reduceFunc = reduceAsync(numberPromiseArray);
|
||||
const result = await reduceFunc(
|
||||
(previousValue, currentValue) => previousValue + currentValue,
|
||||
10
|
||||
);
|
||||
|
||||
expect(result).toEqual(13);
|
||||
});
|
||||
test('Should work with mix of promises and values', async () => {
|
||||
const numberMixArray = [1, Promise.resolve(2)];
|
||||
|
||||
const reduceFunc = reduceAsync(numberMixArray);
|
||||
const result = await reduceFunc(
|
||||
(previousValue, currentValue) => previousValue + currentValue,
|
||||
10
|
||||
);
|
||||
|
||||
expect(result).toEqual(13);
|
||||
});
|
||||
test('Should throw an error', async () => {
|
||||
const numberPromiseArray = [Promise.resolve(1), Promise.resolve(2)];
|
||||
|
||||
const reduceFunc = reduceAsync(numberPromiseArray);
|
||||
|
||||
await expect(async () => {
|
||||
await reduceFunc(() => {
|
||||
throw new Error('test');
|
||||
});
|
||||
}).rejects.toThrow('test');
|
||||
});
|
||||
});
|
||||
});
|
69
packages/core/utils/lib/async.js
Normal file
69
packages/core/utils/lib/async.js
Normal file
@ -0,0 +1,69 @@
|
||||
'use strict';
|
||||
|
||||
function pipeAsync(...methods) {
|
||||
return async (data) => {
|
||||
let res = data;
|
||||
|
||||
for (const method of methods) {
|
||||
res = await method(res);
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Map function callback.
|
||||
* @callback mapAsyncCallback
|
||||
* @param {*} value
|
||||
* @param {number} index
|
||||
*/
|
||||
/**
|
||||
* Async iteration over an array of promises
|
||||
* @param {promise<*>[]} promiseArray
|
||||
* @returns {function(callback: mapAsyncCallback): promise<*[]>}
|
||||
*/
|
||||
function mapAsync(promiseArray) {
|
||||
/**
|
||||
* @param {mapAsyncCallback} callback
|
||||
* @returns promise<*[]>
|
||||
*/
|
||||
return (callback) => {
|
||||
const transformedPromiseArray = promiseArray.map(async (promiseValue, index) => {
|
||||
const value = await promiseValue;
|
||||
return callback(value, index);
|
||||
});
|
||||
return Promise.all(transformedPromiseArray);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce function callback.
|
||||
* @callback reduceAsyncCallback
|
||||
* @param {*} previousValue
|
||||
* @param {*} currentValue
|
||||
* @param {number} index
|
||||
*/
|
||||
/**
|
||||
* Async chain over an array of promises
|
||||
* @param {promise<*>[]} promiseArray
|
||||
* @returns {function(callback: reduceAsyncCallback, initialValue?: *): promise<*>}
|
||||
*/
|
||||
function reduceAsync(promiseArray) {
|
||||
/**
|
||||
* @param {reduceAsyncCallback} callback
|
||||
* @param {*} [initialValue]
|
||||
* @returns promise<*>
|
||||
*/
|
||||
return (callback, initialValue) =>
|
||||
promiseArray.reduce(async (previousPromise, currentValue, index) => {
|
||||
const previousValue = await previousPromise;
|
||||
return callback(previousValue, await currentValue, index);
|
||||
}, Promise.resolve(initialValue));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mapAsync,
|
||||
reduceAsync,
|
||||
pipeAsync,
|
||||
};
|
@ -37,7 +37,7 @@ const providerFactory = require('./provider-factory');
|
||||
const pagination = require('./pagination');
|
||||
const sanitize = require('./sanitize');
|
||||
const traverseEntity = require('./traverse-entity');
|
||||
const pipeAsync = require('./pipe-async');
|
||||
const { pipeAsync } = require('./async');
|
||||
const convertQueryParams = require('./convert-query-params');
|
||||
const importDefault = require('./import-default');
|
||||
const template = require('./template');
|
||||
|
@ -1,13 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
module.exports =
|
||||
(...methods) =>
|
||||
async (data) => {
|
||||
let res = data;
|
||||
|
||||
for (const method of methods) {
|
||||
res = await method(res);
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
@ -4,7 +4,7 @@ const { isArray } = require('lodash/fp');
|
||||
|
||||
const traverseEntity = require('../traverse-entity');
|
||||
const { getNonWritableAttributes } = require('../content-types');
|
||||
const pipeAsync = require('../pipe-async');
|
||||
const { pipeAsync } = require('../async');
|
||||
|
||||
const visitors = require('./visitors');
|
||||
const sanitizers = require('./sanitizers');
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
const { curry } = require('lodash/fp');
|
||||
|
||||
const pipeAsync = require('../pipe-async');
|
||||
const { pipeAsync } = require('../async');
|
||||
const traverseEntity = require('../traverse-entity');
|
||||
|
||||
const { removePassword, removePrivate } = require('./visitors');
|
||||
|
Loading…
x
Reference in New Issue
Block a user