forked from business4s/workflows4s
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWIO.scala
147 lines (118 loc) · 5.74 KB
/
WIO.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package workflow4s.wio
import cats.effect.IO
import workflow4s.wio.internal.WorkflowConversionEvaluator.WorkflowEmbedding
import workflow4s.wio.internal.{EventHandler, QueryHandler, SignalHandler}
import scala.annotation.unused
import scala.language.implicitConversions
trait WorkflowContext { ctx: WorkflowContext =>
type Event
type State
type WIO[-In, +Err, +Out <: State] = workflow4s.wio.WIO[In, Err, Out, ctx.type]
object WIO extends WIOBuilderMethods[ctx.type] {
type Branch[-In, +Err, +Out <: State] = workflow4s.wio.WIO.Branch[In, Err, Out, ctx.type]
}
}
object WorkflowContext {
type AuxS[_S] = WorkflowContext { type State = _S }
type AuxE[_E] = WorkflowContext { type Event = _E }
type State[T <: WorkflowContext] = T match {
case AuxS[s] => s
}
type Event[T <: WorkflowContext] = T match {
case AuxE[s] => s
}
type AUX[St, Evt] = WorkflowContext { type State = St; type Event = Evt }
type WithDifferentState[Ctx <: WorkflowContext] = WorkflowContext { type Event = WCEvent[Ctx] }
}
sealed trait WIO[-In, +Err, +Out <: WCState[Ctx], Ctx <: WorkflowContext] extends WIOMethods[Ctx, In, Err, Out]
object WIO {
case class HandleSignal[Ctx <: WorkflowContext, -In, +Out <: WCState[Ctx], +Err, Sig, Resp, Evt](
sigDef: SignalDef[Sig, Resp],
sigHandler: SignalHandler[Sig, Evt, In],
evtHandler: EventHandler[In, (Either[Err, Out], Resp), WCEvent[Ctx], Evt],
errorCt: ErrorMeta[_],
) extends WIO[In, Err, Out, Ctx] {
def expects[Req1, Resp1](@unused signalDef: SignalDef[Req1, Resp1]): Option[HandleSignal[Ctx, In, Out, Err, Req1, Resp1, Evt]] = {
Some(this.asInstanceOf[HandleSignal[Ctx, In, Out, Err, Req1, Resp1, Evt]]) // TODO
}
}
case class HandleQuery[Ctx <: WorkflowContext, -In, +Err, +Out <: WCState[Ctx], -Qr, -QrState, +Resp](
queryHandler: QueryHandler[Qr, QrState, Resp],
inner: WIO[In, Err, Out, Ctx],
) extends WIO[In, Err, Out, Ctx]
// theoretically state is not needed, it could be State.extract.flatMap(RunIO)
case class RunIO[Ctx <: WorkflowContext, -In, +Err, +Out <: WCState[Ctx], Evt](
buildIO: In => IO[Evt],
evtHandler: EventHandler[In, Either[Err, Out], WCEvent[Ctx], Evt],
errorCt: ErrorMeta[_],
) extends WIO[In, Err, Out, Ctx]
case class FlatMap[Ctx <: WorkflowContext, Err1 <: Err2, Err2, Out1 <: WCState[Ctx], +Out2 <: WCState[Ctx], -In](
base: WIO[In, Err1, Out1, Ctx],
getNext: Out1 => WIO[Out1, Err2, Out2, Ctx],
errorCt: ErrorMeta[_],
) extends WIO[In, Err2, Out2, Ctx]
case class Map[Ctx <: WorkflowContext, In, Err, Out1 <: WCState[Ctx], -In2, +Out2 <: WCState[Ctx]](
base: WIO[In, Err, Out1, Ctx],
contramapInput: In2 => In,
mapValue: (In2, Out1) => Out2,
) extends WIO[In2, Err, Out2, Ctx]
case class Pure[Ctx <: WorkflowContext, -In, +Err, +Out <: WCState[Ctx]](
value: In => Either[Err, Out],
errorMeta: ErrorMeta[_],
) extends WIO[In, Err, Out, Ctx]
// TODO this should ne called `Never` or `Halt` or similar, as the workflow cant proceed from that point.
case class Noop[Ctx <: WorkflowContext]() extends WIO[Any, Nothing, Nothing, Ctx]
case class HandleError[Ctx <: WorkflowContext, -In, +Err, +Out <: WCState[Ctx], ErrIn, TempOut <: WCState[Ctx]](
base: WIO[In, ErrIn, Out, Ctx],
handleError: ErrIn => (TempOut, WIO[TempOut, Err, Out, Ctx]),
handledErrorMeta: ErrorMeta[_],
newErrorMeta: ErrorMeta[_],
) extends WIO[In, Err, Out, Ctx]
case class HandleErrorWith[Ctx <: WorkflowContext, -In, Err, +Out <: WCState[Ctx], +ErrOut](
base: WIO[In, Err, Out, Ctx],
handleError: WIO[(In, Err), ErrOut, Out, Ctx],
recoverState: (In, Err) => WCState[Ctx],
handledErrorMeta: ErrorMeta[_],
newErrorCt: ErrorMeta[_],
) extends WIO[In, ErrOut, Out, Ctx]
case class Named[Ctx <: WorkflowContext, -In, +Err, +Out <: WCState[Ctx]](
base: WIO[In, Err, Out, Ctx],
name: String,
description: Option[String],
errorMeta: ErrorMeta[_],
) extends WIO[In, Err, Out, Ctx]
case class AndThen[Ctx <: WorkflowContext, -In, +Err, Out1 <: WCState[Ctx], +Out2 <: WCState[Ctx]](
first: WIO[In, Err, Out1, Ctx],
second: WIO[Out1, Err, Out2, Ctx],
) extends WIO[In, Err, Out2, Ctx]
// TODO name for condition
case class DoWhile[Ctx <: WorkflowContext, -In, +Err, LoopOut <: WCState[Ctx], +Out <: WCState[Ctx]](
loop: WIO[LoopOut, Err, LoopOut, Ctx],
stopCondition: LoopOut => Option[Out],
current: WIO[In, Err, LoopOut, Ctx],
) extends WIO[In, Err, Out, Ctx]
case class Fork[Ctx <: WorkflowContext, -In, +Err, +Out <: WCState[Ctx]](branches: Vector[Branch[In, Err, Out, Ctx]]) extends WIO[In, Err, Out, Ctx]
case class Embedded[Ctx <: WorkflowContext, -In, +Err, InnerCtx <: WorkflowContext, InnerOut <: WCState[InnerCtx], MappingOutput[_ <: WCState[InnerCtx]] <: WCState[Ctx]](
inner: WIO[In, Err, InnerOut, InnerCtx],
embedding: WorkflowEmbedding.Aux[InnerCtx, Ctx, MappingOutput, In],
) extends WIO[In, Err, MappingOutput[InnerOut], Ctx]
// -----
def build[Ctx <: WorkflowContext]: WIOBuilderMethods[Ctx] = new WIOBuilderMethods[Ctx] {}
trait Branch[-In, +Err, +Out <: WCState[Ctx], Ctx <: WorkflowContext] {
type I // Intermediate
def condition: In => Option[I]
def wio: WIO[(In, I), Err, Out, Ctx]
}
object Branch {
def apply[Ctx <: WorkflowContext, In, T, Err, Out <: WCState[Ctx]](
cond: In => Option[T],
wio0: WIO[(In, T), Err, Out, Ctx],
): Branch[In, Err, Out, Ctx] = {
new Branch[In, Err, Out, Ctx] {
override type I = T
override def condition: In => Option[I] = cond
override def wio: WIO[(In, I), Err, Out, Ctx] = wio0
}
}
}
}