diff --git a/utils/helpers.js b/utils/helpers.js new file mode 100644 index 00000000..4fecdc2f --- /dev/null +++ b/utils/helpers.js @@ -0,0 +1,24 @@ +/** + * @format + */ + +/** + * @template T + * @typedef {(value: T) => Promise} AsyncFilterCallback + */ + +/** + * @template T + * @param {T[]} arr + * @param {AsyncFilterCallback} cb + * @returns {Promise} + */ +const asyncFilter = async (arr, cb) => { + const results = await Promise.all(arr.map(item => cb(item))) + + return arr.filter((_, i) => results[i]) +} + +module.exports = { + asyncFilter +} diff --git a/utils/helpers.spec.js b/utils/helpers.spec.js new file mode 100644 index 00000000..409f2264 --- /dev/null +++ b/utils/helpers.spec.js @@ -0,0 +1,49 @@ +/** + * @format + */ + +const { asyncFilter } = require('./helpers') + +const numbers = [1, 2, 3, 4] +const odds = [1, 3] +const evens = [2, 4] + +describe('asyncFilter()', () => { + it('returns an empty array when given one', async () => { + expect.hasAssertions() + const result = await asyncFilter([], () => true) + + expect(result).toStrictEqual([]) + }) + + it('rejects', async () => { + expect.hasAssertions() + + const result = await asyncFilter(numbers, () => false) + + expect(result).toStrictEqual([]) + }) + + it('rejects via calling with the correct value', async () => { + expect.hasAssertions() + + const result = await asyncFilter(numbers, v => v % 2 !== 0) + + expect(result).toStrictEqual(odds) + }) + + it('filters via calling with the correct value', async () => { + expect.hasAssertions() + + const result = await asyncFilter(numbers, v => v % 2 === 0) + + expect(result).toStrictEqual(evens) + }) + + it('handles promises', async () => { + expect.hasAssertions() + + const result = await asyncFilter(numbers, v => Promise.resolve(v % 2 === 0)) + expect(result).toStrictEqual(evens) + }) +}) diff --git a/utils/index.js b/utils/index.js new file mode 100644 index 00000000..90e80eee --- /dev/null +++ b/utils/index.js @@ -0,0 +1,9 @@ +/** + * @format + */ + +const { asyncFilter } = require('./helpers') + +module.exports = { + asyncFilter +}