diff options
author | Sebastian <sebasjm@gmail.com> | 2023-10-26 11:15:45 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2023-10-26 11:15:45 -0300 |
commit | a4c7bc4b284fe7dc4c65ceaad96fc67c40c9a708 (patch) | |
tree | f407ad06733a3a82a7c5655d65a81fc3e5248cc1 /packages/taler-util/src/operation.ts | |
parent | e812eae32daddad372c7629867298ca28678a44c (diff) | |
download | wallet-core-a4c7bc4b284fe7dc4c65ceaad96fc67c40c9a708.tar.xz |
moving cli test to harness
Diffstat (limited to 'packages/taler-util/src/operation.ts')
-rw-r--r-- | packages/taler-util/src/operation.ts | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/packages/taler-util/src/operation.ts b/packages/taler-util/src/operation.ts new file mode 100644 index 000000000..aab5dc022 --- /dev/null +++ b/packages/taler-util/src/operation.ts @@ -0,0 +1,74 @@ +import { HttpResponse, readSuccessResponseJsonOrThrow, readTalerErrorResponse } from "./http-common.js"; +import { Codec, TalerError, TalerErrorCode, TalerErrorDetail } from "./index.js"; + +export type OperationResult<Body, ErrorEnum> = + | OperationOk<Body> + | OperationFail<ErrorEnum>; + +export interface OperationOk<T> { + type: "ok", + body: T; +} +export function isOperationOk<T, E>(c: OperationResult<T, E>): c is OperationOk<T> { + return c.type === "ok" +} +export function isOperationFail<T, E>(c: OperationResult<T, E>): c is OperationFail<E> { + return c.type === "fail" +} +export interface OperationFail<T> { + type: "fail", + case: T, + detail: TalerErrorDetail, +} + +export async function opSuccess<T>(resp: HttpResponse, codec: Codec<T>): Promise<OperationOk<T>> { + const body = await readSuccessResponseJsonOrThrow(resp, codec) + return { type: "ok" as const, body } +} +export function opFixedSuccess<T>(body: T): OperationOk<T> { + return { type: "ok" as const, body } +} +export function opEmptySuccess(): OperationOk<void> { + return { type: "ok" as const, body: void 0 } +} +export async function opKnownFailure<T extends string>(s: T, resp: HttpResponse): Promise<OperationFail<T>> { + const detail = await readTalerErrorResponse(resp) + return { type: "fail", case: s, detail } +} +export function opUnknownFailure(resp: HttpResponse, text: string): never { + throw TalerError.fromDetail( + TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR, + { + requestUrl: resp.requestUrl, + requestMethod: resp.requestMethod, + httpStatusCode: resp.status, + errorResponse: text, + }, + `Unexpected HTTP status ${resp.status} in response`, + ); +} +export async function succeedOrThrow<R, E>(cb: () => Promise<OperationResult<R, E>>): Promise<R> { + const resp = await cb() + if (resp.type === "ok") return resp.body + throw TalerError.fromUncheckedDetail({ ...resp.detail, case: resp.case }) +} +export async function failOrThrow<E>(s: E, cb: () => Promise<OperationResult<unknown, E>>): Promise<TalerErrorDetail> { + const resp = await cb() + if (resp.type === "ok") { + throw TalerError.fromException(new Error(`request succeed but failure "${s}" was expected`)) + } + if (resp.case === s) { + return resp.detail + } + throw TalerError.fromException(new Error(`request failed but case "${s}" was expected`)) +} + + + +export type ResultByMethod<TT extends object, p extends keyof TT> = TT[p] extends (...args: any[]) => infer Ret ? + Ret extends Promise<infer Result> ? + Result : + never : //api always use Promises + never; //error cases just for functions + +export type FailCasesByMethod<TT extends object, p extends keyof TT> = Exclude<ResultByMethod<TT, p>, OperationOk<any>> |