From bf711b986df8a4396c885bc844a4be6a54e63807 Mon Sep 17 00:00:00 2001 From: JackSpagnoli Date: Wed, 5 Jun 2024 15:17:09 +0100 Subject: [PATCH] Add `collectMaybe()` & `collectResult()` utilities (#46) --- CHANGELOG.md | 4 +++ README.md | 48 ++++++++++++++++++++++++++++ package.json | 2 +- specs/utils.spec.ts | 78 +++++++++++++++++++++++++++++++++++++++++++-- src/collect.ts | 32 +++++++++++++++++++ src/index.ts | 3 +- 6 files changed, 162 insertions(+), 5 deletions(-) create mode 100644 src/collect.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 725f2d5..2f0a7b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ This document outlines the changes from version to version. +## 2.3.0 + +- Added `collectResult()` and `collectMaybe()` + ## 2.2.0 - Added ESM support diff --git a/README.md b/README.md index e1e2e83..7565c91 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,8 @@ Table of Contents + [tail](#tail) + [tryFind](#tryfind) + [parseDate](#parsedate) + + [collectResult](#collectResult) + + [collectMaybe](#collectMaybe) ### Changes from V1 to V2 @@ -690,3 +692,49 @@ tryFind(u => u.id === '123abc')(users) Nothing: () => 'Could not find user with id 123abc' // doesn't run }) ``` + +#### collectResult + +Safely collect values from an array of results. Returns a result. + +```js +import {collectResult} from 'pratica' + +const all_good = [Ok(1), Ok(2), Ok(3)] +const one_bad = [Ok(1), Err('Some error'), Ok(3)] + +collectResult(all_good) + .cata({ + Ok: x => expect(x).toEqual([1,2,3]), // true + Err: () => 'no values' // doesn't run + }) + +collectResult(one_bad) + .cata({ + Ok: x => x, // doesn't run + Err: err => expect(err).toEqual('Some error') // true + }) +``` + +#### collectMaybe + +Safely collect values from an array of maybes. Returns a maybe. + +```js +import {collectMaybe} from 'pratica' + +const all_good = [Just(1), Just(2), Just(3)] +const one_bad = [Just(1), Nothing, Just(3)] + +collectMaybe(all_good) + .cata({ + Just: x => expect(x).toEqual([1,2,3]), // true + Nothing: () => 'no values' // doesn't run + }) + +collectMaybe(one_bad) + .cata({ + Just: x => x, // doesn't run + Nothing: () => 'no values' // true + }) +``` diff --git a/package.json b/package.json index f8f034e..f3a9971 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pratica", - "version": "2.2.0", + "version": "2.3.0", "description": "Functional Programming for Pragmatists", "main": "dist/index.cjs", "module": "dist/index.esm.js", diff --git a/specs/utils.spec.ts b/specs/utils.spec.ts index c2d0129..01e8350 100644 --- a/specs/utils.spec.ts +++ b/specs/utils.spec.ts @@ -1,5 +1,5 @@ -import { Just, Nothing } from '../src/maybe' -import { Ok, Err } from '../src/result' +import { Just, Maybe, Nothing } from '../src/maybe' +import { Ok, Err, Result } from '../src/result' import { parseDate } from '../src/parseDate' import { justs } from '../src/justs' import { oks } from '../src/oks' @@ -9,6 +9,7 @@ import { head } from '../src/head' import { last } from '../src/last' import { tail } from '../src/tail' import { tryFind } from '../src/tryFind' +import { collectResult, collectMaybe } from '../src/collect' describe('utililties', () => { @@ -210,4 +211,75 @@ describe('utililties', () => { done() }) -}) \ No newline at end of file + it('collectResult: should collect an array of Oks into an Ok with an array of values', done => { + const data = [Ok(5), Ok(2), Ok(3)] + + collectResult(data) + .cata({ + Ok: x => expect(x).toEqual([5,2,3]), + Err: () => done.fail() + }) + + done() + }) + + it('collectResult: should collect an array of Oks and Errs into an Err with an array of errors', done => { + const data = [Ok(5), Err('nope'), Ok(3)] + + collectResult(data) + .cata({ + Ok: () => done.fail(), + Err: x => expect(x).toEqual(['nope']) + }) + + done() + }) + + it('collectResult: should collect an empty array into Ok([])', done => { + const data: Array> = [] + + collectResult(data) + .cata({ + Ok: x => expect(x).toEqual([]), + Err: () => done.fail() + }) + + done() + }) + + it('collectMaybe: should collect an array of Justs into a Just with an array of values', done => { + const data = [Just(5), Just(2), Just(3)] + + collectMaybe(data) + .cata({ + Just: x => expect(x).toEqual([5,2,3]), + Nothing: () => done.fail() + }) + + done() + }) + + it('collectMaybe: should return a Nothing if any Maybe is a Nothing', done => { + const data = [Just(5), Nothing, Just(3)] + + collectMaybe(data) + .cata({ + Just: () => done.fail(), + Nothing: () => done() + }) + + done() + }) +}) + +it('collectMaybe: should collect an empty array into Just([])', done => { + const data: Array> = [] + + collectMaybe(data) + .cata({ + Just: x => expect(x).toEqual([]), + Nothing: () => done.fail() + }) + + done() +}) diff --git a/src/collect.ts b/src/collect.ts new file mode 100644 index 0000000..85931a1 --- /dev/null +++ b/src/collect.ts @@ -0,0 +1,32 @@ +import { Err, Ok, Result } from "./result" +import { Just, Maybe, Nothing } from "./maybe" + +export const collectResult = (results: Array>): Result, Array> => { + const successes: Array = [] + const failures: Array = [] + + for (const result of results) { + result.cata({ + Ok: x => successes.push(x), + Err: x => failures.push(x) + }) + } + + if (failures.length > 0) { + return Err(failures) + } + return Ok(successes) +} + +export const collectMaybe = (maybes: Array>): Maybe> => { + const values: Array = [] + + for (const maybe of maybes) { + if (maybe.isNothing()) { + return Nothing + } + values.push(maybe.value() as O) + } + + return Just(values) +} diff --git a/src/index.ts b/src/index.ts index 24558f8..228d536 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,4 +8,5 @@ export * from './oks' export * from './parseDate' export * from './result' export * from './tail' -export * from './tryFind' \ No newline at end of file +export * from './tryFind' +export * from './collect'