UNPKG

@effect-ts/system

Version:

Effect-TS is a zero dependency set of libraries to write highly productive, purely functional TypeScript at scale.

1,192 lines (1,092 loc) 31.8 kB
// ets_tracing: off import "../../Operator/index.js" import { RuntimeError } from "../../Cause/index.js" import * as T from "../../Effect/index.js" import * as E from "../../Either/index.js" import type { Predicate, Refinement } from "../../Function/index.js" import { constVoid, identity } from "../../Function/index.js" import { NoSuchElementException } from "../../GlobalExceptions/index.js" import * as O from "../../Option/index.js" import { AtomicBoolean } from "../../Support/AtomicBoolean/index.js" import * as P from "./_internal/primitives.js" import { tryCommit, tryCommitAsync } from "./Journal/index.js" import { DoneTypeId, SuspendTypeId } from "./TryCommit/index.js" import { makeTxnId } from "./TxnId/index.js" export { catchAll, catchAll_, chain, chain_, ensuring, ensuring_, fail, failWith, foldM, foldM_, map, map_, provideSome, provideSome_, retry, STM, STMEffect, STMFailException, STMRetryException, succeed, succeedWith, unit, die, dieWith } from "./_internal/primitives.js" export { _catch as catch } export const MaxFrames = 200 /** * Accesses the environment of the transaction. */ export function access<R, A>(f: (r: R) => A): P.STM<R, never, A> { return P.map_(environment<R>(), f) } /** * Accesses the environment of the transaction to perform a transaction. */ export function accessM<R0, R, E, A>(f: (r: R0) => P.STM<R, E, A>) { return P.chain_(environment<R0>(), f) } /** * Submerges the error case of an `Either` into the `STM`. The inverse * operation of `STM.either`. */ export function absolve<R, E, E1, A>( z: P.STM<R, E, E.Either<E1, A>> ): P.STM<R, E | E1, A> { return P.chain_(z, fromEither) } /** * Propagates the given environment to self. */ export function andThen_<R, E, A, E1, B>( self: P.STM<R, E, A>, that: P.STM<A, E1, B> ): P.STM<R, E | E1, B> { return P.chain_(self, (a) => provideAll_(that, a)) } /** * Propagates the given environment to self. * * @ets_data_first andThen_ */ export function andThen<A, E1, B>( that: P.STM<A, E1, B> ): <R, E>(self: P.STM<R, E, A>) => P.STM<R, E | E1, B> { return (self) => andThen_(self, that) } /** * Maps the success value of this effect to the specified constant value. */ export function as_<R, E, A, B>(self: P.STM<R, E, A>, b: B): P.STM<R, E, B> { return P.map_(self, () => b) } /** * Maps the success value of this effect to the specified constant value. * * @ets_data_first as_ */ export function as<A, B>(b: B): <R, E>(self: P.STM<R, E, A>) => P.STM<R, E, B> { return (self) => as_(self, b) } /** * Maps the success value of this effect to an optional value. */ export function asSome<R, E, A>(self: P.STM<R, E, A>): P.STM<R, E, O.Option<A>> { return P.map_(self, O.some) } /** * Maps the error value of this effect to an optional value. */ export function asSomeError<R, E, A>(self: P.STM<R, E, A>): P.STM<R, O.Option<E>, A> { return mapError_(self, O.some) } /** * Returns an `STM` effect whose P.failure and success channels have been mapped by * the specified pair of functions, `f` and `g`. */ export function bimap_<R, E, A, E1, B>( self: P.STM<R, E, A>, g: (e: E) => E1, f: (a: A) => B ): P.STM<R, E1, B> { return P.foldM_( self, (e) => P.fail(g(e)), (a) => P.succeed(f(a)) ) } /** * Returns an `STM` effect whose P.failure and success channels have been mapped by * the specified pair of functions, `f` and `g`. * * @ets_data_first bimap_ */ export function bimap<R, E, A, E1, B>( g: (e: E) => E1, f: (a: A) => B ): (self: P.STM<R, E, A>) => P.STM<R, E1, B> { return (self) => bimap_(self, g, f) } /** * Recovers from specified error. * * @ets_data_first catch_ */ function _catch<N extends keyof E, K extends E[N] & string, E, R1, E1, A1>( tag: N, k: K, f: (e: Extract<E, { [n in N]: K }>) => P.STM<R1, E1, A1>, __trace?: string ) { return <R, A>( self: P.STM<R, E, A> ): P.STM<R & R1, Exclude<E, { [n in N]: K }> | E1, A | A1> => P.catchAll_(self, (e) => { if (typeof e === "object" && e !== null && tag in e && e[tag] === k) { return f(e as any) } return P.fail(e as any) }) } /** * Recovers from specified error. */ export function catch_<N extends keyof E, K extends E[N] & string, E, R, A, R1, E1, A1>( self: P.STM<R, E, A>, tag: N, k: K, f: (e: Extract<E, { [n in N]: K }>) => P.STM<R1, E1, A1> ): P.STM<R & R1, Exclude<E, { [n in N]: K }> | E1, A | A1> { return P.catchAll_(self, (e) => { if (typeof e === "object" && e !== null && tag in e && e[tag] === k) { return f(e as any) } return P.fail(e as any) }) } /** * Recovers from specified error. * * @ets_data_first catchTag_ */ export function catchTag< K extends E["_tag"] & string, E extends { _tag: string }, R1, E1, A1 >(k: K, f: (e: Extract<E, { _tag: K }>) => P.STM<R1, E1, A1>, __trace?: string) { return <R, A>( self: P.STM<R, E, A> ): P.STM<R & R1, Exclude<E, { _tag: K }> | E1, A | A1> => catchTag_(self, k, f) } /** * Recovers from specified error. */ export function catchTag_< K extends E["_tag"] & string, E extends { _tag: string }, R, A, R1, E1, A1 >( self: P.STM<R, E, A>, k: K, f: (e: Extract<E, { _tag: K }>) => P.STM<R1, E1, A1> ): P.STM<R & R1, Exclude<E, { _tag: K }> | E1, A | A1> { return P.catchAll_(self, (e) => { if ("_tag" in e && e["_tag"] === k) { return f(e as any) } return P.fail(e as any) }) } /** * Recovers from some or all of the error cases. */ export function catchSome_<R, E, A, R1, E1, B>( self: P.STM<R, E, A>, f: (e: E) => O.Option<P.STM<R1, E1, B>> ): P.STM<R1 & R, E | E1, A | B> { return P.catchAll_( self, (e): P.STM<R1, E | E1, A | B> => O.fold_(f(e), () => P.fail(e), identity) ) } /** * Recovers from some or all of the error cases. * * @ets_data_first catchSome_ */ export function catchSome<E, R1, E1, B>( f: (e: E) => O.Option<P.STM<R1, E1, B>> ): <R, A>(self: P.STM<R, E, A>) => P.STM<R1 & R, E | E1, A | B> { return (self) => catchSome_(self, f) } /** * Simultaneously filters and flatMaps the value produced by this effect. * Continues on the effect returned from pf. */ export function continueOrRetryM_<R, E, A, R2, E2, A2>( fa: P.STM<R, E, A>, pf: (a: A) => O.Option<P.STM<R2, E2, A2>> ): P.STM<R2 & R, E | E2, A2> { return P.chain_(fa, (a): P.STM<R2, E2, A2> => O.getOrElse_(pf(a), () => P.retry)) } /** * Simultaneously filters and flatMaps the value produced by this effect. * Continues on the effect returned from pf. * * @ets_data_first continueOrRetryM_ */ export function continueOrRetryM<A, R2, E2, A2>( pf: (a: A) => O.Option<P.STM<R2, E2, A2>> ): <R, E>(fa: P.STM<R, E, A>) => P.STM<R2 & R, E | E2, A2> { return (fa) => continueOrRetryM_(fa, pf) } /** * Fail with `e` if the supplied `PartialFunction` does not match, otherwise * succeed with the returned value. */ export function continueOrRetry_<R, E, A, A2>( fa: P.STM<R, E, A>, pf: (a: A) => O.Option<A2> ) { return continueOrRetryM_(fa, (x) => O.map_(pf(x), P.succeed)) } /** * Fail with `e` if the supplied `PartialFunction` does not match, otherwise * succeed with the returned value. * * @ets_data_first continueOrRetry_ */ export function continueOrRetry<A, A2>(pf: (a: A) => O.Option<A2>) { return <R, E>(fa: P.STM<R, E, A>) => continueOrRetry_(fa, pf) } /** * Fail with `e` if the supplied `PartialFunction` does not match, otherwise * continue with the returned value. */ export function continueOrFailM_<R, E, E1, A, R2, E2, A2>( fa: P.STM<R, E, A>, e: E1, pf: (a: A) => O.Option<P.STM<R2, E2, A2>> ) { return P.chain_( fa, (a): P.STM<R2, E1 | E2, A2> => O.getOrElse_(pf(a), () => P.fail(e)) ) } /** * Fail with `e` if the supplied `PartialFunction` does not match, otherwise * continue with the returned value. * * @ets_data_first continueOrFailM_ */ export function continueOrFailM<E1, A, R2, E2, A2>( e: E1, pf: (a: A) => O.Option<P.STM<R2, E2, A2>> ) { return <R, E>(fa: P.STM<R, E, A>) => continueOrFailM_(fa, e, pf) } /** * Fail with `e` if the supplied `PartialFunction` does not match, otherwise * succeed with the returned value. */ export function continueOrFail_<R, E, E1, A, A2>( fa: P.STM<R, E, A>, e: E1, pf: (a: A) => O.Option<A2> ) { return continueOrFailM_(fa, e, (x) => O.map_(pf(x), P.succeed)) } /** * Fail with `e` if the supplied `PartialFunction` does not match, otherwise * succeed with the returned value. * * @ets_data_first continueOrFail_ */ export function continueOrFail<E1, A, A2>(e: E1, pf: (a: A) => O.Option<A2>) { return <R, E>(fa: P.STM<R, E, A>) => continueOrFail_(fa, e, pf) } /** * Fail with `e` if the supplied `PartialFunction` does not match, otherwise * continue with the returned value. */ export function continueOrFailWithM_<R, E, E1, A, R2, E2, A2>( fa: P.STM<R, E, A>, e: () => E1, pf: (a: A) => O.Option<P.STM<R2, E2, A2>> ) { return P.chain_( fa, (a): P.STM<R2, E1 | E2, A2> => O.getOrElse_(pf(a), () => P.failWith(e)) ) } /** * Fail with `e` if the supplied `PartialFunction` does not match, otherwise * continue with the returned value. * * @ets_data_first continueOrFailWithM_ */ export function continueOrFailWithM<E1, A, R2, E2, A2>( e: () => E1, pf: (a: A) => O.Option<P.STM<R2, E2, A2>> ) { return <R, E>(fa: P.STM<R, E, A>) => continueOrFailWithM_(fa, e, pf) } /** * Fail with `e` if the supplied `PartialFunction` does not match, otherwise * succeed with the returned value. */ export function continueOrFailWith_<R, E, E1, A, A2>( fa: P.STM<R, E, A>, e: () => E1, pf: (a: A) => O.Option<A2> ) { return continueOrFailWithM_(fa, e, (x) => O.map_(pf(x), P.succeed)) } /** * Fail with `e` if the supplied `PartialFunction` does not match, otherwise * succeed with the returned value. * * @ets_data_first continueOrFailWith_ */ export function continueOrFailWith<E1, A, A2>(e: () => E1, pf: (a: A) => O.Option<A2>) { return <R, E>(fa: P.STM<R, E, A>) => continueOrFailWith_(fa, e, pf) } /** * Creates a composite effect that represents this effect followed by another * one that may depend on the error produced by this one. * * @ets_data_first chainError_ */ export function chainError<E, R2, E2>(f: (e: E) => P.STM<R2, never, E2>) { return <R, A>(self: P.STM<R, E, A>) => chainError_(self, f) } /** * Creates a composite effect that represents this effect followed by another * one that may depend on the error produced by this one. */ export function chainError_<R, E, A, R2, E2>( self: P.STM<R, E, A>, f: (e: E) => P.STM<R2, never, E2> ) { return flipWith_(self, (x) => P.chain_(x, f)) } /** * Checks the condition, and if it's true, returns unit, otherwise, retries. */ export function checkWith(predicate: () => boolean) { return suspend(() => (predicate() ? P.unit : P.retry)) } /** * Checks the condition, and if it's true, returns unit, otherwise, retries. */ export function check(predicate: boolean) { return checkWith(() => predicate) } /** * Propagates self environment to that. */ export function compose_<R, E, A, R1, E1>( self: P.STM<R, E, A>, that: P.STM<R1, E1, R> ) { return andThen_(that, self) } /** * Propagates self environment to that. * * @ets_data_first compose_ */ export function compose<R, R1, E1>(that: P.STM<R1, E1, R>) { return <E, A>(self: P.STM<R, E, A>) => andThen_(that, self) } /** * Commits this transaction atomically. */ export function commit<R, E, A>(self: P.STM<R, E, A>) { return T.accessM((r: R) => T.suspend((_, fiberId) => { const v = tryCommit(fiberId, self, r) switch (v._typeId) { case DoneTypeId: { return v.io } case SuspendTypeId: { const txnId = makeTxnId() const done = new AtomicBoolean(false) const interrupt = T.succeedWith(() => done.set(true)) const io = T.effectAsync( tryCommitAsync(v.journal, fiberId, self, txnId, done, r) ) return T.ensuring_(io, interrupt) } } }) ) } /** * Commits this transaction atomically, regardless of whether the transaction * is a success or a failure. */ export function commitEither<R, E, A>(self: P.STM<R, E, A>): T.Effect<R, E, A> { return T.absolve(commit(either(self))) } /** * Kills the fiber running the effect with a `RuntimeError` that contains * the specified message. */ export function dieMessage(message: string): P.STM<unknown, never, never> { return P.dieWith(() => new RuntimeError(message)) } /** * Kills the fiber running the effect with a `RuntimeError` that contains * the specified message. */ export function dieMessageWith(message: () => string): P.STM<unknown, never, never> { return P.succeedWith(() => { throw new RuntimeError(message()) }) } /** * Converts the failure channel into an `Either`. */ export function either<R, E, A>(self: P.STM<R, E, A>): P.STM<R, never, E.Either<E, A>> { return fold_( self, (x) => E.left(x), (x) => E.right(x) ) } /** * Retrieves the environment inside an stm. */ export function environment<R>(): P.STM<R, never, R> { return new P.STMEffect((_, __, r: R) => r) } /** * Returns an effect that ignores errors and runs repeatedly until it eventually succeeds. */ export function eventually<R, E, A>(self: P.STM<R, E, A>): P.STM<R, never, A> { return P.foldM_(self, () => eventually(self), P.succeed) } /** * Dies with specified `unknown` if the predicate fails. * * @ets_data_first filterOrDie_ */ export function filterOrDie<A, B extends A>( p: Refinement<A, B>, dieWith: (a: Exclude<A, B>) => unknown ): <R, E>(fa: P.STM<R, E, A>) => P.STM<R, E, B> export function filterOrDie<A>( p: Predicate<A>, dieWith: (a: A) => unknown ): <R, E>(fa: P.STM<R, E, A>) => P.STM<R, E, A> export function filterOrDie<A>(p: Predicate<A>, dieWith: unknown) { return <R, E>(fa: P.STM<R, E, A>): P.STM<R, E, A> => filterOrDie_(fa, p, dieWith as (a: A) => unknown) } /** * Dies with specified `unknown` if the predicate fails. */ export function filterOrDie_<R, E, A, B extends A>( fa: P.STM<R, E, A>, p: Refinement<A, B>, dieWith: (a: Exclude<A, B>) => unknown ): P.STM<R, E, B> export function filterOrDie_<R, E, A>( fa: P.STM<R, E, A>, p: Predicate<A>, dieWith: (a: A) => unknown ): P.STM<R, E, A> export function filterOrDie_<R, E, A>( fa: P.STM<R, E, A>, p: Predicate<A>, dieWith: unknown ) { return filterOrElse_(fa, p, (x) => P.dieWith(() => (dieWith as (a: A) => unknown)(x))) } /** * Fails with `failWith` if the predicate fails. * * @ets_data_first filterOrFail_ */ export function filterOrFail<A, B extends A, E1>( p: Refinement<A, B>, failWith: (a: Exclude<A, B>) => E1 ): <R, E>(fa: P.STM<R, E, A>) => P.STM<R, E | E1, B> export function filterOrFail<A, E1>( p: Predicate<A>, failWith: (a: A) => E1 ): <R, E>(fa: P.STM<R, E, A>) => P.STM<R, E | E1, A> export function filterOrFail<A, E1>(p: Predicate<A>, failWith: unknown) { return <R, E>(fa: P.STM<R, E, A>): P.STM<R, E | E1, A> => filterOrFail_(fa, p, failWith as (a: A) => E1) } /** * Fails with `failWith` if the predicate fails. */ export function filterOrFail_<R, E, E1, A, B extends A>( fa: P.STM<R, E, A>, p: Refinement<A, B>, failWith: (a: Exclude<A, B>) => E1 ): P.STM<R, E | E1, B> export function filterOrFail_<R, E, E1, A>( fa: P.STM<R, E, A>, p: Predicate<A>, failWith: (a: A) => E1 ): P.STM<R, E | E1, A> export function filterOrFail_<R, E, E1, A>( fa: P.STM<R, E, A>, p: Predicate<A>, failWith: unknown ) { return filterOrElse_(fa, p, (x) => P.fail((failWith as (a: A) => E1)(x))) } /** * Applies `or` if the predicate fails. * * @ets_data_first filterOrElse_ */ export function filterOrElse<A, B extends A, R2, E2, A2>( p: Refinement<A, B>, or: (a: Exclude<A, B>) => P.STM<R2, E2, A2> ): <R, E>(fa: P.STM<R, E, A>) => P.STM<R & R2, E | E2, B | A2> export function filterOrElse<A, R2, E2, A2>( p: Predicate<A>, or: (a: A) => P.STM<R2, E2, A2> ): <R, E>(fa: P.STM<R, E, A>) => P.STM<R & R2, E | E2, A | A2> export function filterOrElse<A, R2, E2, A2>(p: Predicate<A>, or: unknown) { return <R, E>(fa: P.STM<R, E, A>) => filterOrElse_(fa, p, or as (a: A) => P.STM<R2, E2, A2>) } /** * Applies `or` if the predicate fails. */ export function filterOrElse_<R, E, A, B extends A, R2, E2, A2>( fa: P.STM<R, E, A>, p: Refinement<A, B>, or: (a: Exclude<A, B>) => P.STM<R2, E2, A2> ): P.STM<R & R2, E | E2, B | A2> export function filterOrElse_<R, E, A, R2, E2, A2>( fa: P.STM<R, E, A>, p: Predicate<A>, or: (a: A) => P.STM<R2, E2, A2> ): P.STM<R & R2, E | E2, A | A2> export function filterOrElse_<R, E, A, R2, E2, A2>( fa: P.STM<R, E, A>, p: Predicate<A>, or: unknown ): P.STM<R & R2, E | E2, A | A2> { return P.chain_( fa, (a): P.STM<R2, E2, A | A2> => p(a) ? P.succeed(a) : suspend(() => (or as (a: A) => P.STM<R2, E2, A2>)(a)) ) } /** * Dies with a `Error` having the specified text message * if the predicate fails. * * @ets_data_first filterOrDieMessage_ */ export function filterOrDieMessage<A, B extends A>( p: Refinement<A, B>, message: (a: Exclude<A, B>) => string ): <R, E>(fa: P.STM<R, E, A>) => P.STM<R, E, B> export function filterOrDieMessage<A>( p: Predicate<A>, message: (a: A) => string ): <R, E>(fa: P.STM<R, E, A>) => P.STM<R, E, A> export function filterOrDieMessage<A>(p: Predicate<A>, message: unknown) { return <R, E>(fa: P.STM<R, E, A>): P.STM<R, E, A> => filterOrDieMessage_(fa, p, message as (a: A) => string) } /** * Dies with a `Error` having the specified text message * if the predicate fails. */ export function filterOrDieMessage_<R, E, A, B extends A>( fa: P.STM<R, E, A>, p: Refinement<A, B>, message: (a: Exclude<A, B>) => string ): P.STM<R, E, B> export function filterOrDieMessage_<R, E, A>( fa: P.STM<R, E, A>, p: Predicate<A>, message: (a: A) => string ): P.STM<R, E, A> export function filterOrDieMessage_<R, E, A>( fa: P.STM<R, E, A>, p: Predicate<A>, message: unknown ) { return filterOrDie_(fa, p, (a) => new RuntimeError((message as (a: A) => string)(a))) } /** * Returns an effect that swaps the error/success cases. This allows you to * use all methods on the error channel, possibly before flipping back. */ export function flip<R, E, A>(self: P.STM<R, E, A>) { return P.foldM_(self, P.succeed, P.fail) } /** * Swaps the error/value parameters, applies the function `f` and flips the parameters back * * @ets_data_first flipWith_ */ export function flipWith<R, E, A, R2, E2, A2>( f: (self: P.STM<R, A, E>) => P.STM<R2, A2, E2> ) { return (self: P.STM<R, E, A>): P.STM<R2, E2, A2> => flipWith_(self, f) } /** * Swaps the error/value parameters, applies the function `f` and flips the parameters back */ export function flipWith_<R, E, A, R2, E2, A2>( self: P.STM<R, E, A>, f: (self: P.STM<R, A, E>) => P.STM<R2, A2, E2> ) { return flip(f(flip(self))) } /** * Folds over the `STM` effect, handling both P.failure and success, but not * retry. */ export function fold_<R, E, A, B, C>( self: P.STM<R, E, A>, g: (e: E) => C, f: (a: A) => B ): P.STM<R, never, B | C> { return P.foldM_( self, (e) => P.succeed(g(e)), (a) => P.succeed(f(a)) ) } /** * Folds over the `STM` effect, handling both P.failure and success, but not * retry. * * @ets_data_first fold_ */ export function fold<E, A, B, C>( g: (e: E) => C, f: (a: A) => B ): <R>(self: P.STM<R, E, A>) => P.STM<R, never, B | C> { return (self) => fold_(self, g, f) } /** * Flattens out a nested `STM` effect. */ export function flatten<R, E, R1, E1, B>( self: P.STM<R, E, P.STM<R1, E1, B>> ): P.STM<R1 & R, E | E1, B> { return P.chain_(self, identity) } /** * Unwraps the optional error, defaulting to the provided value. * * @ets_data_first flattenErrorOptionWith_ */ export function flattenErrorOptionWith<E2>(def: () => E2) { return <R, E, A>(self: P.STM<R, O.Option<E>, A>): P.STM<R, E | E2, A> => flattenErrorOptionWith_(self, def) } /** * Unwraps the optional error, defaulting to the provided value. */ export function flattenErrorOptionWith_<R, E, A, E2>( self: P.STM<R, O.Option<E>, A>, def: () => E2 ): P.STM<R, E | E2, A> { return mapError_(self, O.fold(def, identity)) } /** * Unwraps the optional error, defaulting to the provided value. * * @ets_data_first flattenErrorOption_ */ export function flattenErrorOption<E2>(def: E2) { return <R, E, A>(self: P.STM<R, O.Option<E>, A>): P.STM<R, E | E2, A> => flattenErrorOption_(self, def) } /** * Unwraps the optional error, defaulting to the provided value. */ export function flattenErrorOption_<R, E, A, E2>( self: P.STM<R, O.Option<E>, A>, def: E2 ): P.STM<R, E | E2, A> { return mapError_( self, O.fold(() => def, identity) ) } /** * Applies the function `f` to each element of the `Iterable<A>` and * returns a transactional effect that produces a new `ReadonlyArray<B>`. */ export function forEach_<A, R, E, B>( it: Iterable<A>, f: (a: A) => P.STM<R, E, B> ): P.STM<R, E, readonly B[]> { return suspend(() => { let stm = P.succeed([]) as P.STM<R, E, B[]> for (const a of it) { stm = zipWith_(stm, f(a), (acc, b) => { acc.push(b) return acc }) } return stm }) } /** * Applies the function `f` to each element of the `Iterable<A>` and * returns a transactional effect that produces a new `ReadonlyArray<B>`. * * @ets_data_first forEach_ */ export function forEach<A, R, E, B>( f: (a: A) => P.STM<R, E, B> ): (it: Iterable<A>) => P.STM<R, E, readonly B[]> { return (self) => forEach_(self, f) } /** * Lifts an `Either` into a `STM`. */ export function fromEitherWith<E, A>(e: () => E.Either<E, A>): P.STM<unknown, E, A> { return suspend(() => { return E.fold_(e(), P.fail, P.succeed) }) } /** * Lifts an `Either` into a `STM`. */ export function fromEither<E, A>(e: E.Either<E, A>): P.STM<unknown, E, A> { return E.fold_(e, P.fail, P.succeed) } /** * Unwraps the optional success of this effect, but can fail with an None value. */ export function get<R, E, A>(self: P.STM<R, E, O.Option<A>>): P.STM<R, O.Option<E>, A> { return P.foldM_( self, (x) => P.fail(O.some(x)), O.fold(() => P.fail(O.none), P.succeed) ) } /** * Returns a successful effect with the head of the list if the list is * non-empty or fails with the error `None` if the list is empty. */ export function head<R, E, A>( self: P.STM<R, E, Iterable<A>> ): P.STM<R, O.Option<E>, A> { return P.foldM_( self, (x) => P.fail(O.some(x)), (x) => { const it = x[Symbol.iterator]() const next = it.next() return next.done ? P.fail(O.none) : P.succeed(next.value) } ) } /** * Returns a new effect that ignores the success or failure of this effect. */ export function ignore<R, E, A>(self: P.STM<R, E, A>): P.STM<R, never, void> { return fold_(self, constVoid, constVoid) } /** * Returns whether this effect is a failure. */ export function isFailure<R, E, A>(self: P.STM<R, E, A>) { return fold_( self, () => true, () => false ) } /** * Returns whether this effect is a success. */ export function isSuccess<R, E, A>(self: P.STM<R, E, A>) { return fold_( self, () => false, () => true ) } /** * Returns a successful effect if the value is `Left`, or fails with the error `None`. */ export function left<R, E, B, C>( self: P.STM<R, E, E.Either<B, C>> ): P.STM<R, O.Option<E>, B> { return P.foldM_( self, (e) => P.fail(O.some(e)), E.fold(P.succeed, () => P.fail(O.none)) ) } /** * Returns a successful effect if the value is `Left`, or fails with the error e. */ export function leftOrFail_<R, E, B, C, E1>( self: P.STM<R, E, E.Either<B, C>>, orFail: (c: C) => E1 ) { return P.chain_( self, E.fold(P.succeed, (x) => P.failWith(() => orFail(x))) ) } /** * Returns a successful effect if the value is `Left`, or fails with the error e. * * @ets_data_first leftOrFail_ */ export function leftOrFail<C, E1>(orFail: (c: C) => E1) { return <R, E, B>(self: P.STM<R, E, E.Either<B, C>>) => leftOrFail_(self, orFail) } /** * Returns a successful effect if the value is `Left`, or fails with a `NoSuchElementException`. */ export function leftOrFailException<R, E, B, C>(self: P.STM<R, E, E.Either<B, C>>) { return leftOrFail_(self, () => new NoSuchElementException()) } /** * Depending on provided environment returns either this one or the other effect. * * @ets_data_first join_ */ export function join<R1, E1, A1>(that: P.STM<R1, E1, A1>) { return <R, E, A>(self: P.STM<R, E, A>): P.STM<E.Either<R, R1>, E | E1, A | A1> => { return join_(self, that) } } /** * Depending on provided environment returns either this one or the other effect. */ export function join_<R, E, A, R1, E1, A1>( self: P.STM<R, E, A>, that: P.STM<R1, E1, A1> ): P.STM<E.Either<R, R1>, E | E1, A | A1> { return accessM( (_: E.Either<R, R1>): P.STM<unknown, E | E1, A | A1> => E.fold_( _, (r) => provideAll_(self, r), (r1) => provideAll_(that, r1) ) ) } /** * Depending on provided environment returns either this one or the other effect. */ export function joinEither_<R, E, A, R1, E1, A1>( self: P.STM<R, E, A>, that: P.STM<R1, E1, A1> ): P.STM<E.Either<R, R1>, E | E1, E.Either<A, A1>> { return accessM( (_: E.Either<R, R1>): P.STM<unknown, E | E1, E.Either<A, A1>> => E.fold_( _, (r) => P.map_(provideAll_(self, r), E.left), (r1) => P.map_(provideAll_(that, r1), E.right) ) ) } /** * Depending on provided environment returns either this one or the other effect. */ export function joinEither<R, E, A, R1, E1, A1>( that: P.STM<R1, E1, A1> ): (self: P.STM<R, E, A>) => P.STM<E.Either<R, R1>, E | E1, E.Either<A, A1>> { return (self) => joinEither_(self, that) } /** * Maps from one error type to another. */ export function mapError_<R, E, A, E1>( self: P.STM<R, E, A>, f: (a: E) => E1 ): P.STM<R, E1, A> { return P.foldM_(self, (e) => P.fail(f(e)), P.succeed) } /** * Maps from one error type to another. * * @ets_data_first mapError_ */ export function mapError<E, E1>( f: (a: E) => E1 ): <R, A>(self: P.STM<R, E, A>) => P.STM<R, E1, A> { return (self) => mapError_(self, f) } /** * Provides the transaction its required environment, which eliminates * its dependency on `R`. */ export function provideAll_<R, E, A>(self: P.STM<R, E, A>, r: R): P.STM<unknown, E, A> { return P.provideSome_(self, () => r) } /** * Provides the transaction its required environment, which eliminates * its dependency on `R`. * * @ets_data_first provideAll_ */ export function provideAll<R>( r: R ): <E, A>(self: P.STM<R, E, A>) => P.STM<unknown, E, A> { return (self) => provideAll_(self, r) } /** * Repeats this `STM` effect until its result satisfies the specified predicate. * * WARNING: * `repeatUntil` uses a busy loop to repeat the effect and will consume a thread until * it completes (it cannot yield). This is because STM describes a single atomic * transaction which must either complete, retry or fail a transaction before * yielding back to the Effect Runtime. * * - Use `retryUntil` instead if you don't need to maintain transaction state for repeats. * - Ensure repeating the STM effect will eventually satisfy the predicate. */ export function repeatUntil_<R, E, A>( self: P.STM<R, E, A>, f: (a: A) => boolean ): P.STM<R, E, A> { return P.chain_(self, (a) => (f(a) ? P.succeed(a) : repeatUntil_(self, f))) } /** * Repeats this `STM` effect until its result satisfies the specified predicate. * * WARNING: * `repeatUntil` uses a busy loop to repeat the effect and will consume a thread until * it completes (it cannot yield). This is because STM describes a single atomic * transaction which must either complete, retry or fail a transaction before * yielding back to the Effect Runtime. * * - Use `retryUntil` instead if you don't need to maintain transaction state for repeats. * - Ensure repeating the STM effect will eventually satisfy the predicate. * * @ets_data_first repeatUntil_ */ export function repeatUntil<A>( f: (a: A) => boolean ): <R, E>(self: P.STM<R, E, A>) => P.STM<R, E, A> { return (self) => repeatUntil_(self, f) } /** * Repeats this `STM` effect while its result satisfies the specified predicate. * * WARNING: * `repeatWhile` uses a busy loop to repeat the effect and will consume a thread until * it completes (it cannot yield). This is because STM describes a single atomic * transaction which must either complete, retry or fail a transaction before * yielding back to the Effect Runtime. * * - Use `retryWhile` instead if you don't need to maintain transaction state for repeats. * - Ensure repeating the STM effect will eventually not satisfy the predicate. */ export function repeatWhile_<R, E, A>( self: P.STM<R, E, A>, f: (a: A) => boolean ): P.STM<R, E, A> { return P.chain_(self, (a) => (f(a) ? repeatWhile_(self, f) : P.succeed(a))) } /** * Repeats this `STM` effect while its result satisfies the specified predicate. * * WARNING: * `repeatWhile` uses a busy loop to repeat the effect and will consume a thread until * it completes (it cannot yield). This is because STM describes a single atomic * transaction which must either complete, retry or fail a transaction before * yielding back to the Effect Runtime. * * - Use `retryWhile` instead if you don't need to maintain transaction state for repeats. * - Ensure repeating the STM effect will eventually not satisfy the predicate. * * @ets_data_first repeatWhile_ */ export function repeatWhile<R, E, A>( f: (a: A) => boolean ): (self: P.STM<R, E, A>) => P.STM<R, E, A> { return (self) => repeatWhile_(self, f) } /** * Suspends creation of the specified transaction lazily. */ export function suspend<R, E, A>(f: () => P.STM<R, E, A>): P.STM<R, E, A> { return flatten(P.succeedWith(f)) } /** * "Peeks" at the success of transactional effect. */ export function tap_<R, E, A, R1, E1, B>( self: P.STM<R, E, A>, f: (a: A) => P.STM<R1, E1, B> ): P.STM<R1 & R, E | E1, A> { return P.chain_(self, (a) => as_(f(a), a)) } /** * "Peeks" at the success of transactional effect. * * @ets_data_first tap_ */ export function tap<A, R1, E1, B>( f: (a: A) => P.STM<R1, E1, B> ): <R, E>(self: P.STM<R, E, A>) => P.STM<R1 & R, E | E1, A> { return (self) => tap_(self, f) } /** * Returns an effect with the value on the left part. */ export function toLeftWith<A>(a: () => A): P.STM<unknown, never, E.Either<A, never>> { return P.chain_(P.succeedWith(a), (x) => P.succeed(E.left(x))) } /** * Returns an effect with the value on the left part. */ export function toLeft<A>(a: A): P.STM<unknown, never, E.Either<A, never>> { return P.succeed(E.left(a)) } /** * Sequentially zips this value with the specified one, combining the values * using the specified combiner function. */ export function zipWith_<R, E, A, R1, E1, B, C>( self: P.STM<R, E, A>, that: P.STM<R1, E1, B>, f: (a: A, b: B) => C ): P.STM<R1 & R, E | E1, C> { return P.chain_(self, (a) => P.map_(that, (b) => f(a, b))) } /** * Sequentially zips this value with the specified one, combining the values * using the specified combiner function. * * @ets_data_first zipWith_ */ export function zipWith<A, R1, E1, B, C>( that: P.STM<R1, E1, B>, f: (a: A, b: B) => C ): <R, E>(self: P.STM<R, E, A>) => P.STM<R1 & R, E | E1, C> { return (self) => P.chain_(self, (a) => P.map_(that, (b) => f(a, b))) }