1.0.6 • Published 3 years ago

bplus-composer v1.0.6

Weekly downloads
3
License
GPL-3.0-or-later
Repository
gitlab
Last release
3 years ago

BPLUS-COMPOSER

A functional composition library for TypeScript based on F# and Linq. The Linq implementation is fully lazy with the exception of the few functions that require a full iterable evaluation.

pipeline coverage

Note

This project is maintained over at GitLab: https://gitlab.com/adleatherwood/bplus-composer

Install

https://www.npmjs.com/package/bplus-composer

npm i bplus-composer

Option

An option is defined as either having a value or not.

export type Option<T> = T | undefined | null

You can deconstruct an option with either the match function...

let option = "some value"
let result = Option.match(option,
    success => success.split(" "),
    failure => [])

expect(result.length).toBe(2)

Or you can use the query function to enumerate the result. Undefined & null will result in an empty enumeration.

let option = "some value"
let result = Option.query(option)
    .select(text => text.split(" "))
    .single()

expect(result.length).toBe(2)

A typical example of how an option would appear in code.

let map = new Map([
    [1, { id: 1, first: "Larry", last: "Fine" }],
    [2, { id: 2, first: "Curly", last: "Howard" }],
    [3, { id: 3, first: "Moe", last: "Howard" }]
])

let result = map.get(2)
let initials = Option.query(result)
    .select(s => `${s.first[0]}.${s.last[0]}.`)
    .singleOrUndefined()

expect(initials).toBe("C.H.")

You can also test results for some or none.

let option = "test"
let success = Option.isSome(option)
let failure = Option.isNone(option)

expect(success).toBe(true)
expect(failure).toBe(false)

Result

A result either has a value or an error. Unlike the option, you need to construct a result as either a success or a failure.

let success = Result.success("test")
let failure = Result.failure("something went wrong")

You can deconstruct a result either the match function...

let result = Result.success("test")
let value = Result.match(result,
    success => "successful " + success,
    failure => "epic failure")

expect(value).toBe("successful test")

Or you can use the query function to enumerate the result. Failures will result in an empty enumeration.

let result = Result.success("test")
let value = Result.query(result)
    .select(text => "successful " + text)
    .select(text => text.toUpperCase())
    .single()

expect(value).toBe("SUCCESSFUL TEST")

You can also test results for success or failure.

let result = Result.success("test")
let success = Result.isSuccess(result)
let failure = Result.isFailure(result)

expect(success).toBe(true)
expect(failure).toBe(false)

Linq

I won't list all of the Linq functions that are implemented and how to use them. They are mostly all there and are used in a similar and intuitive manner as in C#. There are some differences worth mentioning. Although TypeScript offers enough flexibility for function overloads, they are generally very cumbersome and this library would have had an unmanageable number of them. Here are some of the more different arrangements:

OrderBy

In C#, you would use multiple subsequent Linq statements to sort data with secondary sorts. In this library, you will do it all in one statement.

let input = [5, 2, 4, 3, 1]
let actual = Linq.query(input)
    .orderBy(Asc.self())
    .toArray()
    .join()

expect(actual).toBe("1,2,3,4,5")

let input = [5, 2, 4, 3, 1]
let actual = Linq.query(input)
    .orderBy(Desc.self())
    .toArray()
    .join()

expect(actual).toBe("5,4,3,2,1")

Note the helper types of Asc and Desc. There are other functions on those type that will allow you to pass through custom key selectors and comparers. Like so:

let input = [[2, 1], [3, 2], [2, 3], [2, 2], [1, 3], [1, 2], [3, 3], [1, 1], [3, 1]]
let actual = Linq.query(input)
    .orderBy(Desc.by(t => t[0]), Asc.by(t => t[1]))
    .select(t => `${t[0]}${t[1]}`)
    .toArray()
    .join()

expect(actual).toBe("31,32,33,21,22,23,11,12,13")

MinOf & MaxOf

In C#, type specific extension methods either show or hide these functions base on specific types that this function can be performed on. In TypeScript we have no such luxury, so the function is always available. In this construct, you have to tell the function what you want to be matched.

let input = [3, 5, 1]
let actual = Linq.query(input)
    .maxOf(Compare.self())

expect(actual).toBe(5)

Again, there's a new helper called Compare that you can use to make these moments more readable. There are other functions on Compare that will allow you to pass through custom selectors and comparers.

DistinctBy & toMap & toSet

These function use the native Map & Set types. These types have restrictions on what types of value can be used as keys, etc. So the Linq functions are also restricted to these types.

let input = ["a", "b", "a", "c", "b", "a"]
let actual = Linq.query(input)
    .distinctBy(self)
    .toArray()
    .join()

expect(actual).toBe("a,b,c")

Notice the helper function self that can be used to select and return the item itself. This function is not necessary, but can make code more readable.

Icons made by Freepik from www.flaticon.com

1.0.6

3 years ago

1.0.5

3 years ago

1.0.4

4 years ago

1.0.3

4 years ago

1.0.2

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago