From 8b441b3c66b334a62b58685a1624d875d547c703 Mon Sep 17 00:00:00 2001 From: bkiac <24522620+bkiac@users.noreply.github.com> Date: Sat, 4 Nov 2023 08:33:52 +0100 Subject: [PATCH] Add group (#8) --- src/helpers/group.test.ts | 99 +++++++++++++++++++++++++++++++++++++++ src/helpers/group.ts | 73 +++++++++++++++++++++++++++++ src/helpers/guard.ts | 15 +++--- src/index.ts | 1 + 4 files changed, 179 insertions(+), 9 deletions(-) create mode 100644 src/helpers/group.test.ts create mode 100644 src/helpers/group.ts diff --git a/src/helpers/group.test.ts b/src/helpers/group.test.ts new file mode 100644 index 0000000..485a896 --- /dev/null +++ b/src/helpers/group.test.ts @@ -0,0 +1,99 @@ +import {test, expect, vi} from "vitest" +import {ResultGroup, createGroup} from "./group" +import {ResultError} from ".." + +test("constructor", () => { + const handleError = vi.fn() + const result = createGroup(handleError) + expect(result).toBeInstanceOf(ResultGroup) + // @ts-expect-error + expect(result.handleError).toBe(handleError) +}) + +class FooError extends ResultError { + readonly tag = "foo" +} + +class BarError extends ResultError { + readonly tag = "bar" +} + +const m = createGroup(() => new FooError()) + +test("tryFn", () => { + const result = m.tryFn(() => { + throw new Error("error") + }) + expect(result.unwrapErr()).toBeInstanceOf(FooError) +}) + +test("tryFnWith", () => { + const result = m.tryFnWith( + () => { + throw new Error("error") + }, + () => new BarError(), + ) + expect(result.unwrapErr()).toBeInstanceOf(BarError) +}) + +test("tryPromise", async () => { + const result = m.tryPromise(Promise.reject(new Error("error"))) + await expect(result.unwrapErr()).resolves.toBeInstanceOf(FooError) +}) + +test("tryPromiseWith", async () => { + const result = m.tryPromiseWith(Promise.reject(new Error("error")), () => new BarError()) + await expect(result.unwrapErr()).resolves.toBeInstanceOf(BarError) +}) + +test("tryAsyncFn", async () => { + const result = m.tryAsyncFn(async () => { + throw new Error("error") + }) + await expect(result.unwrapErr()).resolves.toBeInstanceOf(FooError) +}) + +test("tryAsyncFnWith", async () => { + const result = m.tryAsyncFnWith( + async () => { + throw new Error("error") + }, + () => new BarError(), + ) + await expect(result.unwrapErr()).resolves.toBeInstanceOf(BarError) +}) + +test("guard", () => { + const f = m.guard(() => { + throw new Error("error") + }) + expect(f().unwrapErr()).toBeInstanceOf(FooError) +}) + +test("guardWith", () => { + const f = m.guardWith( + () => { + throw new Error("error") + }, + () => new BarError(), + ) + expect(f().unwrapErr()).toBeInstanceOf(BarError) +}) + +test("guardAsync", async () => { + const f = m.guardAsync(async () => { + throw new Error("error") + }) + await expect(f().unwrapErr()).resolves.toBeInstanceOf(FooError) +}) + +test("guardAsyncWith", async () => { + const f = m.guardAsyncWith( + async () => { + throw new Error("error") + }, + () => new BarError(), + ) + await expect(f().unwrapErr()).resolves.toBeInstanceOf(BarError) +}) diff --git a/src/helpers/group.ts b/src/helpers/group.ts new file mode 100644 index 0000000..ed58143 --- /dev/null +++ b/src/helpers/group.ts @@ -0,0 +1,73 @@ +import {tryAsyncFnWith, tryFnWith, tryPromiseWith} from "./try" +import type {ErrorHandler, ResultError} from "../error/result_error" +import type {Result} from "../result/interface" +import type {PromiseResult} from "../result/promise" + +export type ResultGroupErrorHandler = (error: E) => F + +type Fn = (...args: any[]) => any +type AsyncFn = (...args: any[]) => Promise + +export class ResultGroup { + private constructor(private readonly handleError: ErrorHandler) {} + + tryFn(f: () => T): Result { + return tryFnWith(f, this.handleError) + } + + tryFnWith( + f: () => T, + h: ResultGroupErrorHandler, + ): Result { + return tryFnWith(f, (error) => h(this.handleError(error))) + } + + tryPromise(promise: Promise): PromiseResult { + return tryPromiseWith(promise, this.handleError) + } + + tryPromiseWith( + promise: Promise, + h: ResultGroupErrorHandler, + ): PromiseResult { + return tryPromiseWith(promise, (error) => h(this.handleError(error))) + } + + tryAsyncFn(f: () => Promise): PromiseResult { + return tryAsyncFnWith(f, this.handleError) + } + + tryAsyncFnWith( + f: () => Promise, + h: ResultGroupErrorHandler, + ): PromiseResult { + return tryAsyncFnWith(f, (error) => h(this.handleError(error))) + } + + guard(f: T) { + return (...args: Parameters) => this.tryFn(() => f(...args)) + } + + guardWith(f: T, h: ResultGroupErrorHandler) { + return (...args: Parameters) => this.tryFnWith(() => f(...args), h) + } + + guardAsync(f: T) { + return (...args: Parameters) => this.tryAsyncFn(() => f(...args)) + } + + guardAsyncWith( + f: T, + h: ResultGroupErrorHandler, + ) { + return (...args: Parameters) => this.tryAsyncFnWith(() => f(...args), h) + } + + static with(handleError: ErrorHandler): ResultGroup { + return new ResultGroup(handleError) + } +} + +export function createGroup(handleError: ErrorHandler): ResultGroup { + return ResultGroup.with(handleError) +} diff --git a/src/helpers/guard.ts b/src/helpers/guard.ts index ab3f2ac..3103027 100644 --- a/src/helpers/guard.ts +++ b/src/helpers/guard.ts @@ -10,23 +10,20 @@ export function guard(f: T) { } } -export function guardWith(f: T, handleError: ErrorHandler) { +export function guardWith(f: T, h: ErrorHandler) { return function (...args: Parameters) { - return tryFnWith, E>(() => f(...args), handleError) + return tryFnWith, E>(() => f(...args), h) } } -export function guardAsync(fn: T) { +export function guardAsync(f: T) { return function (...args: Parameters) { - return tryAsyncFn>>(() => fn(...args)) + return tryAsyncFn>>(() => f(...args)) } } -export function guardAsyncWith( - fn: T, - handleError: ErrorHandler, -) { +export function guardAsyncWith(f: T, h: ErrorHandler) { return function (...args: Parameters) { - return tryAsyncFnWith>, E>(() => fn(...args), handleError) + return tryAsyncFnWith>, E>(() => f(...args), h) } } diff --git a/src/index.ts b/src/index.ts index f1fdcb0..a0ceac0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,7 @@ export * from "./error/panic" export * from "./error/result_error" export * from "./helpers/fn" +export * from "./helpers/group" export * from "./helpers/guard" export * from "./helpers/try"