Skip to content

Commit

Permalink
Add collectMaybe() & collectResult() utilities (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
JackSpagnoli authored Jun 5, 2024
1 parent ea8ea36 commit bf711b9
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ Table of Contents
+ [tail](#tail)
+ [tryFind](#tryfind)
+ [parseDate](#parsedate)
+ [collectResult](#collectResult)
+ [collectMaybe](#collectMaybe)

### Changes from V1 to V2

Expand Down Expand Up @@ -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
})
```
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
78 changes: 75 additions & 3 deletions specs/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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', () => {

Expand Down Expand Up @@ -210,4 +211,75 @@ describe('utililties', () => {
done()
})

})
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<Result<any, any>> = []

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<Maybe<any>> = []

collectMaybe(data)
.cata({
Just: x => expect(x).toEqual([]),
Nothing: () => done.fail()
})

done()
})
32 changes: 32 additions & 0 deletions src/collect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Err, Ok, Result } from "./result"
import { Just, Maybe, Nothing } from "./maybe"

export const collectResult = <O, E>(results: Array<Result<O, E>>): Result<Array<O>, Array<E>> => {
const successes: Array<O> = []
const failures: Array<E> = []

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 = <O>(maybes: Array<Maybe<O>>): Maybe<Array<O>> => {
const values: Array<O> = []

for (const maybe of maybes) {
if (maybe.isNothing()) {
return Nothing
}
values.push(maybe.value() as O)
}

return Just(values)
}
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export * from './oks'
export * from './parseDate'
export * from './result'
export * from './tail'
export * from './tryFind'
export * from './tryFind'
export * from './collect'

0 comments on commit bf711b9

Please sign in to comment.