Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/muthuishere/declarative-optional

A Declarative way to deal with null , undefined and promises via optional and streams
https://github.com/muthuishere/declarative-optional

async javascript optional promise

Last synced: 16 days ago
JSON representation

A Declarative way to deal with null , undefined and promises via optional and streams

Awesome Lists containing this project

README

        

![Coverage](https://img.shields.io/codecov/c/github/muthuishere/declarative-optional)
![License](https://img.shields.io/npm/l/declarative-optional)
![Version](https://img.shields.io/npm/v/declarative-optional)

Declarative-Optional
===================

A Javascript library to write concise functional code.Combined with features of Java Optional & Javascripts Promise chaining

##### Features

> Lazily evaluated

> chaining async and sync functions

> Most of the Java Optional Features

> Some of the Java Stream Features


##### Installation

```
npm install declarative-optional
```

##### Usage
To Import
```
// Common JS
const {Optional} = require( "declarative-optional");

//ES6
import {Optional} from "declarative-optional";

```

Common Usages

```

//Increment By 5
function incrementByFive(input) {
return Optional.of(input)
.map(i=>i+5)
.orElse(0)
}

// incrementByFive(41) => 46
// incrementByFive(null) => 0
// incrementByFive(undefined) => 0

// All the expressions will be evaluated only after you specified get()

//Increment a Number by 5, Only if its dividable by 5
Optional.of(input)
.filter(val=>val % 5 == 0)
.map(val=>val+5)
.get()


```

On Asynchronous code

```javascript
// Consider the async function

function getFromUserService({username, password}) {
return new Promise((function (resolve) {
resolve({name: "user", isAdmin: true})
}))
}

async function login({username, password}) {

if (null == username || null == password) {
throw new Error("Cannot be Null")
}

const result = await getFromUserService(username, password)

if (result.isAdmin) {
redirectTo("adminPage")
} else {
redirectTo("userPage")
}

}

// With Declarative Optional
async function login({username, password}) {

const page = await Optional.of({username: user, password: pass})
.filter(({username, password}) => (null != username && null != password))
.map(getFromUserService)
.map(result => result.isAdmin ? "adminPage" : "userPage")
.toAsync();

page.ifPresentOrElse(redirectTo, () => {
throw new Error("Cannot be Null")
})
}
```

#### fetch Api with Optional

```javascript

// Typical code

const url ='https://jsonplaceholder.typicode.com/todos/' + item
const rawResults = await fetch(url);
const response = await rawResults.json();

if (response.completed) {
return response.title
} else {
return null
}


// Can be rewritten with optional as
return await Optional.of('https://jsonplaceholder.typicode.com/todos/' + item)
.map(fetch)
.map(response => response.json())
.filter(response => response.completed == true)
.map(response => response.title)
.getAsync();


```
There are so much you can play with declarative suite. It does have some features similar to Java Optional & RX libraries, except the code is small (one file around 4 Kb original source) and simple.

It also features a stream library, a wrapper for array , with lazy evaluation and functional programming features.

```javascript

//commonjs
const {Stream} = require("declarative-optional");

//ES6
import {Stream} from "declarative-optional";


```

```javascript

const results = Stream.of([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
.filter(val => val % 2 == 0)
.map(val => val * 2)
.get();

console.log(stream) // [4,8,12,16,20]


// first
Stream.of([45,46,80])
.first()
.get()
// [45]



// last
Stream.of([45,46,80])
.last()
.get()
// [80]

//The first and last methods are useful when you want to get the first or last element of a stream and also you can chain up map operations.

Stream.of([45,46,80])
.last()
.map(val=>val*2)
.get()
// [160]

// Async Stream
const input = [Promise.resolve(21),Promise.resolve(25),Promise.resolve(30)]
const result = await Stream.of(input)
.filter((value) => value %5 ==0)
.map(getFromUserService)
.getAsync()

// [25,30]


// handle async errors or empty values with default value

const input = [Promise.resolve(21),Promise.reject(25),Promise.resolve(30)]
const val = await Stream.of(input)
.filter((value) => value %5 ==0)
.map(getFromUserService)
.orElseAsync(["default"])

// ["default"]

```

### Documentation

Function Description Example

Optional.of
To create a new Optional .Can be value or promise or null or undefined


Optional.of(input)



map

convert from one form to other, returns optional instance, can return async functions as well



Optional.of(21)
.map(val => val + 1)



filter

apply a predicate function over a value



Optional.of(21)
.filter(val => val % 5 == 0)



flatmap

if an existing function returns Optional , it will flatten the value and pass it below


// Consider a function which will return Optional
//returns Optional
const powersOf = (name)=>Optional.of(['web-shooters','syntheitic-webbing'])

const superHeroById = (id) => "Spider-Man"


const res = Optional.of(52001)
.map(superHeroById)
.map(powersOf )
.flatten()
.get()

// results ['web-shooters','syntheitic-webbing']


const res = Optional.of(52001)
.map(superHeroById)
.flatmap(powersOf )
.get()

// results ['web-shooters','syntheitic-webbing']



get

evaluate all the chained functions and give the result. If no value is available , will return null



Optional.of(21)
.filter(val => val % 5 == 0)
.map(val => val + 5)
.get() ; // returns null


Optional.of(20)
.filter(val => val % 5 == 0)
.map(val => val + 5)
.get() ; // returns 25


***Error***

Optional.of(input)
.map(promiseFunctionToValidateUserDetails)
.map(promiseFunctionToValidateSomeOther)
.get() ;

// Error ? Use getAsync to deal with promises



orElse

Evaluate all the chained functions and if result exists, give the result. If no value is available , will return value passed by



Optional.of(21)
.filter(val => val % 5 == 0)
.map(val => val + 5)
.orElse(45) ; // returns 45 , as the evaluation will return null


Optional.of(20)
.filter(val => val % 5 == 0)
.map(val => val + 5)
.orElse(45) ; // returns 25



stream

Evaluates all the chained functions and give an array object , if the result is already an array, it will provide as it is , if its single element, it converts to an array of single element



const res = Optional.of([23,45])
.stream()
.map(i=>i+1);

//returns [24,46]


const res = Optional.of(null)
.stream()
.map(i=>i+1);

//returns []


const res = Optional.of(23)
.stream()
.map(i=>i+1);

//returns [24]



getAsync



Evaluate all the chained functions combined with promises give another Promise<result>



const result = await Optional.of(input)
.map(promiseFunctionToValidateUserDetails)
.map(promiseFunctionToValidateRole)
.map(regularFunctionToFormatData)
.getAsync()



const result = await Optional.of('https://jsonplaceholder.typicode.com/todos/' + item)
.map(fetch)
.map(response => response.json())
.filter(response => response.completed == true)
.map(response => response.title)
.getAsync();


**The below will also work fine**

const result = await Optional.of(21)
.filter(val => val % 5 == 0)
.map(val => val + 5)
.getAsync()



toAsync



Evaluate all the chained functions combined with promises give another Promise<Optional> which hold the response.



All the async based results must use toAsync and then they can use the Optional consolidation functions , get ,orElse,stream etc..



Optional.of(input)
.map(promiseFunctionToValidateUserDetails)
.map(promiseFunctionToValidateSomeOther)
.toAsync()
.then(optionalData=>{
// optionalData.get() holds the result
})


const optionalData = await Optional.of(input)
.map(promiseFunctionToValidateUserDetails)
.map(promiseFunctionToValidateSomeOther)
.toAsync()

// optionalData.get() holds the result



###### Alternatives

There are some alternatives , Have a look into them as well

[Optional.js](https://github.com/spencerwi/Optional.js)

[amidevtech/optional.js](https://github.com/amidevtech/optional.js)