Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
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
- Host: GitHub
- URL: https://github.com/muthuishere/declarative-optional
- Owner: muthuishere
- License: mit
- Created: 2022-01-02T06:42:27.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2023-12-27T05:19:05.000Z (about 1 year ago)
- Last Synced: 2024-12-02T00:42:14.036Z (28 days ago)
- Topics: async, javascript, optional, promise
- Language: TypeScript
- Homepage:
- Size: 666 KB
- Stars: 2
- Watchers: 2
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
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 functionfunction 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 valueconst 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)