diff options
Diffstat (limited to 'lib/types/fn/either.ts')
-rw-r--r-- | lib/types/fn/either.ts | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/lib/types/fn/either.ts b/lib/types/fn/either.ts index 0f65859..ffe06d4 100644 --- a/lib/types/fn/either.ts +++ b/lib/types/fn/either.ts @@ -25,6 +25,7 @@ export interface IEither<E, T> extends Tagged<IEitherTag> { readonly flatMapAsync: <_T>(mapper: Mapper<T, Promise<IEither<E, _T>>>) => Promise<IEither<E, _T>>; readonly moveRight: <_T>(t: _T) => IEither<E, _T>; + readonly swap: Supplier<IEither<T, E>>; readonly fold: <_T>(leftFolder: Mapper<E, _T>, rightFolder: Mapper<T, _T>) => _T; readonly joinRight: <O, _T>(other: IEither<E, O>, mapper: (a: O, b: T) => _T) => IEither<E, _T>; readonly joinRightAsync: <O, _T>( @@ -119,6 +120,11 @@ export class Either<E, T> extends _Tagged implements IEither<E, T> { }); } + public swap(): IEither<T, E> { + if (isRight(this.self)) return Either.left(this.self.ok); + return Either.right(this.self.err); + } + static left<E, T>(e: E): IEither<E, T> { return new Either({ err: e, _tag: ELeftTag }); } @@ -140,4 +146,38 @@ export class Either<E, T> extends _Tagged implements IEither<E, T> { .then((t: T) => Either.right<E, T>(t)) .catch((e: E) => Either.left<E, T>(e)); } + + static async retrying<E, T>( + s: Supplier<Promise<IEither<E, T>>>, + attempts: number = 3, + interval: Mapper<number, Promise<void>> = (attempt) => Either.attemptWait(attempt), + ): Promise<IEither<E, T>> { + const res: IEither<T, E> = await Array(attempts) + .fill(0) + .reduce( + async (_result, _i, attempt) => { + await interval(attempt); + const result: IEither<T, E> = await _result; + return result.joinRightAsync( + () => s().then((s) => s.swap()), + (res, _prevError) => res, + ); + }, + Promise.resolve(Either.right<T, E>(<E>new Error('No attempts made'))), + ); + return res.swap(); + } + + static attemptWait( + attempt: number, + backoffFactor: number = 500, + jitter: number = 300, + exponent: number = 1.3, + ): Promise<void> { + if (attempt === 0) { + return Promise.resolve(); + } + const wait = Math.pow(exponent, attempt) * backoffFactor + jitter * Math.random() * Math.pow(exponent, attempt); + return new Promise((res) => setTimeout(res, wait)); + } } |