
Request.pudu
Pudu76 lines3.6 KB
1/** @Mediator.Request.Kind — requests answered by exactly one handler */2module PuduLangMediator.Request34import PuduLangMediator.Context as Context5import PuduLangMediator.Message as Message6import PuduLangMediator as Messaging7import PuduLangMediator.Utils.Erasure as Erasure89/** @Mediator.Request.Handler — answers one request */10export type Handler[Q, R, E] = fn(Q, Context.Context) -> Messaging.Outcome[R, E]1112/** @Mediator.Request.Next — the rest of the pipeline, given the context to run it with */13export type Next[R, E] = fn(Context.Context) -> Messaging.Outcome[R, E]1415/** @Mediator.Request.Behavior — wraps the rest of the pipeline for one kind */16export type Behavior[Q, R, E] = fn(Q, Context.Context, Next[R, E]) -> Messaging.Outcome[R, E]1718/** @Mediator.Request.PreProcessor — runs before the handler; a failure stops the request */19export type PreProcessor[Q, E] = fn(Q, Context.Context) -> Messaging.Outcome[(), E]2021/** @Mediator.Request.PostProcessor — runs after a handler that answered a value */22export type PostProcessor[Q, R, E] = fn(Q, R, Context.Context) -> Messaging.Outcome[(), E]2324/** @Mediator.Request.ExceptionHandler — may answer a value in place of a failure */25export type ExceptionHandler[Q, R, E] = fn(Q, Messaging.Failure[E], Context.Context) -> Option[R]2627/** @Mediator.Request.ExceptionAction — observes a failure that keeps propagating */28export type ExceptionAction[Q, E] = fn(Q, Messaging.Failure[E], Context.Context) -> ()2930/** @Mediator.Request.Route — every component registered for one kind */31export type Route[Q, R, E] = {32 handlers: Array[Handler[Q, R, E]],33 behaviors: Array[Behavior[Q, R, E]],34 preProcessors: Array[PreProcessor[Q, E]],35 postProcessors: Array[PostProcessor[Q, R, E]],36 exceptionHandlers: Array[ExceptionHandler[Q, R, E]],37 exceptionActions: Array[ExceptionAction[Q, E]]38}3940/** @Mediator.Request.Kind — the typed identity of one request */41export type Kind[Q, R, E] = {42 info: Message.Info,43 routes: Erasure.Slot[Route[Q, R, E]],44 invokers: Erasure.Slot[Handler[Q, R, E]],45 requests: Erasure.Slot[Q],46 outcomes: Erasure.Slot[Messaging.Outcome[R, E]]47}48495051export fn kind[Q, R, E](name: Str) -> Kind[Q, R, E] { made(name, Message.Query) }525354export fn command[Q, E](name: Str) -> Kind[Q, (), E] { made(name, Message.Command) }555657fn made[Q, R, E](name: Str, shape: Message.Shape) -> Kind[Q, R, E] {58 Kind{info: Message.Info{name: name, shape: shape, tags: []}, routes: Erasure.slot(), invokers: Erasure.slot(), requests: Erasure.slot(), outcomes: Erasure.slot()}59}606162export fn tagged[Q, R, E](subject: &Kind[Q, R, E], tags: Array[Str]) -> Kind[Q, R, E] {63 Kind{..*subject, info: Message.Info{..subject.info, tags: subject.info.tags.concat(tags)}}64}656667export fn route[Q, R, E]() -> Route[Q, R, E] {68 Route{handlers: [], behaviors: [], preProcessors: [], postProcessors: [], exceptionHandlers: [], exceptionActions: []}69}707172export fn envelope[Q, R, E](subject: &Kind[Q, R, E], request: Q) -> Message.Envelope { Message.sealed(&subject.info, &subject.requests, request) }737475export fn answerOf[Q, R, E](subject: &Kind[Q, R, E], answer: &Message.Answer) -> Option[Messaging.Outcome[R, E]] { Message.read(&subject.outcomes, answer) }76