@typed/fp
Version:
Data Structures and Resources for fp-ts
169 lines (150 loc) • 3.28 kB
text/typescript
/**
* RefMapM is a collection of helpers for working with Refs that manage a mutable Map.
* It utilizes standard JS reference-based keys.
* @since 0.13.4
*/
import { Endomorphism } from 'fp-ts/Endomorphism'
import * as O from 'fp-ts/Option'
import { Predicate } from 'fp-ts/Predicate'
import * as E from './Env'
import * as EO from './EnvOption'
import { pipe } from './function'
import * as Ref from './Ref'
/**
* @since 0.13.4
* @category Model
*/
export interface RefMapM<E, K, V> extends Ref.Ref<E, Map<K, V>> {}
/**
* @since 0.13.4
* @category Combinator
*/
export const deleteAt =
<K>(key: K) =>
<E, V>(rm: RefMapM<E, K, V>) =>
pipe(
rm.get,
E.tap((m) => m.delete(key)),
E.chainFirstW(rm.set),
)
/**
* @since 0.13.4
* @category Combinator
*/
export function filter<A>(predicate: Predicate<A>) {
return <E, K>(rm: RefMapM<E, K, A>) =>
rm.update((m) => {
m.forEach((value, key) => {
if (!predicate(value)) {
m.delete(key)
}
})
return E.of(m)
})
}
/**
* @since 0.13.4
* @category Combinator
*/
export function filterWithIndex<K, V>(predicate: (k: K, v: V) => boolean) {
return <E>(rm: RefMapM<E, K, V>) =>
rm.update((m) => {
m.forEach((value, key) => {
if (!predicate(key, value)) {
m.delete(key)
}
})
return E.of(m)
})
}
/**
* @since 0.13.4
* @category Combinator
*/
export const insertAt =
<K, V>(key: K, value: V) =>
<E>(rm: RefMapM<E, K, V>) =>
pipe(
rm.get,
E.chainW((map) =>
E.fromIO(() => {
if (map.has(key)) {
return O.none
}
map.set(key, value)
return O.some(map)
}),
),
EO.chainFirstEnvK(rm.set),
)
/**
* @since 0.13.4
* @category Combinator
*/
export const modifyAt = <K, V>(key: K, f: Endomorphism<V>) => {
return <E>(rm: RefMapM<E, K, V>) =>
pipe(
rm.get,
E.chainW((map) =>
E.fromIO(() => {
if (!map.has(key)) {
return O.none
}
const v = map.get(key)!
return O.some(map.set(key, f(v)))
}),
),
EO.chainFirstEnvK(rm.set),
)
}
/**
* @since 0.13.4
* @category Combinator
*/
export const updateAt = <K, V>(key: K, value: V) => {
return <E>(rm: RefMapM<E, K, V>) =>
pipe(
rm.get,
E.chainW((map) =>
E.fromIO(() => {
if (!map.has(key)) {
return O.none
}
return O.some(map.set(key, value))
}),
),
EO.chainFirstEnvK(rm.set),
)
}
/**
* @since 0.13.4
* @category Combinator
*/
export const upsertAt =
<K, V>(key: K, value: V) =>
<E>(rm: RefMapM<E, K, V>) =>
rm.update((map) =>
E.fromIO(() => {
map.set(key, value)
return map
}),
)
/**
* @since 0.13.4
* @category Combinator
*/
export const getOrCreate =
<K, E1, V>(key: K, create: E.Env<E1, V>) =>
<E2>(rm: RefMapM<E2, K, V>) =>
pipe(
rm.get,
E.map((map) => (map.has(key) ? O.some(map.get(key)!) : O.none)),
EO.matchEW(
() =>
pipe(
create,
E.chainFirstW((v) => pipe(rm, upsertAt(key, v))),
),
E.of,
),
)