Pipeline
Signature
Section titled “Signature”function Pipeline<E, Ctx extends object>( ctx: Ctx, steps: ReadonlyArray<Step<E, Ctx>>, options: PipelineOptions<E, Ctx>,): EitherAsync<E, Readonly<Ctx>>;| Parameter | Description |
|---|---|
ctx |
The initial context. The pipeline works on a frozen copy of it. |
steps |
The steps, run one after the other in array order. |
options |
The hooks: onLeft (optional), onException and onConflictingKeys. See Hooks. |
Execution model
Section titled “Execution model”- The pipeline freezes a shallow copy of
ctx. That is the current context. - Each step receives the current context. Depending on what it returns:
right(next): ifnextchanged or removed a value that was already written,onConflictingKeysruns. Otherwise a frozen copy ofnextbecomes the current context.left(error):onLeftruns. WithoutonLeft, the pipeline stops withleft(error).- it throws, or its promise rejects:
onExceptionruns.
- A hook that returns
right(ctx)makes the pipeline continue with the next step, using that context. A hook that returnsleft(error)stops the pipeline: later steps do not run and the result is thatleft. - After the last step the result is
rightof the current context. With no steps it isrightof the copy ofctx, and no hook runs.
The result is an EitherAsync
Section titled “The result is an EitherAsync”Pipeline returns a mini-fp EitherAsync<E, Readonly<Ctx>>. You can await it to get the Either, or keep chaining (map, mapLeft, onLeft, match, …) before awaiting:
import { left, right } from "@ngwes/mini-fp";import { Pipeline } from "@ngwes/groucho-fp";import type { PipelineOptions, Step } from "@ngwes/groucho-fp";
type Ctx = { input: string; shout?: string };type Err = { message: string };
const shout: Step<Err, Ctx> = (ctx) => right({ ...ctx, shout: ctx.input.toUpperCase() });
const options: PipelineOptions<Err, Ctx> = { onException: (exception) => left({ message: `crashed: ${String(exception)}` }), onConflictingKeys: (keys) => left({ message: `conflict on ${keys.join(", ")}` }),};
// await it: an Eitherconst result = await Pipeline({ input: "hello" }, [shout], options);console.log(result.isRight()); // true
// or chain firstconst message = await Pipeline({ input: "hello" }, [shout], options) .map((ctx) => ctx.shout) .onLeft((error) => console.error(error.message)) .match( (shouted) => `got ${shouted}`, (error) => `failed: ${error.message}`, );console.log(message); // "got HELLO"onLeft is left out here, so a step’s left would stop the pipeline as is. The next section explains the hooks.