Skip to content

Commit

Permalink
SDK and Flowz updates (#83)
Browse files Browse the repository at this point in the history
* Work on the Activity type and improve sharing of Step constructors

* Fix unsound operations and allow specifying a reporting phase

* Change name of the output phase to be report

* Improve numeric support in the SDK

* Refine flowz

* Try and fix issues

* Fix warnings

* Fix issues caused by moving the location of the unit val

* #65 Add the Set module to the SDK

* #65 Fix Set::size issue and add missing functions from morphir.sdk.Int

* Remove zio-prelude from being a dependency for morphir-sdk-core

* Number type support and inclusion
  • Loading branch information
DamianReeves authored Jan 28, 2021
1 parent be58079 commit b009404
Show file tree
Hide file tree
Showing 25 changed files with 920 additions and 147 deletions.
6 changes: 3 additions & 3 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ object Deps {

val silencer = "1.7.1"
val scalaCollectionsCompat = "2.3.1"
val zio = "1.0.3"
val zioConfig = "1.0.0-RC30-1"
val zioLogging = "0.5.4"
val zio = "1.0.4"
val zioConfig = "1.0.0-RC32"
val zioLogging = "0.5.5"
val zioNio = "1.0.0-RC10"
val zioPrelude = "1.0.0-RC1"
val zioProcess = "0.2.0"
Expand Down
13 changes: 13 additions & 0 deletions morphir/flowz/src/morphir/flowz/Context.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package morphir.flowz

sealed trait Context {
def eventBus: EventBus
}

object Context {
final case class FlowStartupContext(eventBus: EventBus) extends Context
final case class StepInputContext[+Params](parameters: Params, eventBus: EventBus) extends Context
final case class StepOutputContext(eventBus: EventBus) extends Context
}

sealed trait EventBus
199 changes: 199 additions & 0 deletions morphir/flowz/src/morphir/flowz/ContextSetup.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
package morphir.flowz

import com.github.ghik.silencer.silent
import zio._

/**
* ContextSetup provides a recipe for building the context which a flow needs to execute.
*/
trait ContextSetup[-StartupEnv, -Input, +Env, +State, +Params] { self =>

def &&[StartupEnv1 <: StartupEnv, Input1 <: Input, Env0 >: Env, Env1, State1, Params1](
other: ContextSetup[StartupEnv1, Input1, Env1, State1, Params1]
)(implicit
ev: Has.Union[Env0, Env1]
): ContextSetup[StartupEnv1, Input1, Env0 with Env1, (State, State1), (Params, Params1)] =
ContextSetup[StartupEnv1, Input1, Env0 with Env1, (State, State1), (Params, Params1)] { input: Input1 =>
self.recipe.provideSome[StartupEnv1]((_, input)).zipWith(other.recipe.provideSome[StartupEnv1]((_, input))) {
case (
StepContext(leftEnv, StepInputs(leftState, leftParams)),
StepContext(rightEnv, StepInputs(rightState, rightParams))
) =>
StepContext(
environment = ev.union(leftEnv, rightEnv),
state = (leftState, rightState),
params = (leftParams, rightParams)
)
}
}

def andUses[StartupEnv1]: ContextSetup[StartupEnv with StartupEnv1, Input, Env, State, Params] = ContextSetup {
input =>
ZIO.accessM[StartupEnv with StartupEnv1](env => self.recipe.provide((env, input)))
}

def extractParamsWith[StartupEnv1 <: StartupEnv, Input1 <: Input, Params1](
func: Input1 => RIO[StartupEnv1, Params1]
): ContextSetup[StartupEnv1, Input1, Env, State, Params1] = ContextSetup[StartupEnv1, Input1, Env, State, Params1] {
input =>
ZIO.accessM[StartupEnv1](env =>
self.recipe.flatMap(ctx => func(input).map(ctx.updateParams).provide(env)).provide((env, input))
)
}

def provideSomeInput[In](adapter: In => Input): ContextSetup[StartupEnv, In, Env, State, Params] =
ContextSetup[StartupEnv, In, Env, State, Params](input =>
self.recipe.provideSome[StartupEnv](env => (env, adapter(input)))
)

def makeContext(input: Input): RIO[StartupEnv, StepContext[Env, State, Params]] =
recipe.provideSome[StartupEnv](env => (env, input))

def derivesParamsWith[Input1 <: Input, Params1](
func: Input1 => Params1
): ContextSetup[StartupEnv, Input1, Env, State, Params1] =
ContextSetup.CreateFromRecipe[StartupEnv, Input1, Env, State, Params1](
ZIO.accessM[(StartupEnv, Input1)] { case (_, input) =>
self.recipe.flatMap(ctx => ZIO.effect(ctx.updateParams(func(input))))
}
)

/**
* The effect that can be used to build the `StepContext`
*/
def recipe: ZIO[(StartupEnv, Input), Throwable, StepContext[Env, State, Params]]

/**
* Apply further configuration.
*/
def configure[StartupEnv1, Input1, Env1, State1, Params1](
func: ContextSetup[StartupEnv, Input, Env, State, Params] => ContextSetup[
StartupEnv1,
Input1,
Env1,
State1,
Params1
]
): ContextSetup[StartupEnv1, Input1, Env1, State1, Params1] = func(self)

/**
* Parse the parameters of the input to this flow from a command line
*/
def parseCommandLineWith[CmdLine <: Input, Params1](parse: CmdLine => Params1)(implicit
@silent ev: CmdLine <:< List[String]
): ContextSetup[StartupEnv, CmdLine, Env, State, Params1] =
ContextSetup[StartupEnv, CmdLine, Env, State, Params1](cmdLine =>
self.recipe
.flatMap(context => ZIO.effect(context.updateParams(parse(cmdLine))))
.provideSome[StartupEnv](env => (env, cmdLine))
)
}

object ContextSetup {

def apply[StartupEnv, Input, Env, State, Params](
f: Input => RIO[StartupEnv, StepContext[Env, State, Params]]
): ContextSetup[StartupEnv, Input, Env, State, Params] = Create[StartupEnv, Input, Env, State, Params](f)

/**
* Create a `ContextSetup` from a setup function (which is potentially side-effecting).
*/
def create[Input, Env, State, Params](
setupFunc: Input => StepContext[Env, State, Params]
): ContextSetup[Any, Input, Env, State, Params] =
ContextSetup { input: Input => ZIO.effect(setupFunc(input)) }

/**
* Create an instance of the default StepContextConfig.
* This configuration only requires ZIO's ZEnv, and accepts command line args (as a list of strings).
*/
val default: ContextSetup[ZEnv, List[String], ZEnv, Any, Any] = ContextSetup { _: List[String] =>
ZIO.access[ZEnv](StepContext.fromEnvironment)
}

def deriveParams[Input, Params](
f: Input => Params
): ContextSetup[Any, Input, Any, Any, Params] =
ContextSetup { input =>
ZIO
.accessM[(Any, Input)] { case (env, input) =>
ZIO.effect(StepContext(environment = env, state = (), params = f(input)))
}
.provide(((), input))
}

val empty: ContextSetup[Any, Any, Any, Any, Any] = ContextSetup { _: Any =>
ZIO.succeed(StepContext.any)
}

/**
* Create a context setup from an effectual function that parses a command line.
*/
def forCommandLineApp[StartupEnv <: Has[_], Params](
func: List[String] => RIO[StartupEnv, Params]
): ContextSetup[StartupEnv, List[String], StartupEnv, Any, Params] =
ContextSetup[StartupEnv, List[String], StartupEnv, Any, Params]((cmdLineArgs: List[String]) =>
ZIO.accessM[StartupEnv] { env =>
func(cmdLineArgs).map(params => StepContext(environment = env, state = (), params = params))
}
)

/**
* Creates a context setup that uses its initial startup requirements as the environment of the created context.
*/
def givenEnvironmentAtStartup[R]: ContextSetup[R, Any, R, Any, Any] = ContextSetup { _: Any =>
ZIO.access[R](env => StepContext(environment = env, state = (), params = ()))
}

def requiresEnvironmentOfType[R]: ContextSetup[R, Any, R, Any, Any] =
new ContextSetup[R, Any, R, Any, Any] {

/**
* The effect that can be used to build the `StepContext`
*/
def recipe: ZIO[(R, Any), Throwable, StepContext[R, Any, Any]] = ZIO.access[(R, Any)] { case (env, _) =>
StepContext.fromEnvironment(env)
}
}

/**
* Creates a new context setup that requires input of the provided type
*/
def requiresInputOfType[Input]: ContextSetup[Any, Input, Any, Any, Any] = ContextSetup { _: Input =>
ZIO.succeed(StepContext(environment = (), state = (), params = ()))
}

def uses[StartupEnv]: ContextSetup[StartupEnv, Any, StartupEnv, Any, Any] = ContextSetup { _: Any =>
ZIO.access[StartupEnv](StepContext.fromEnvironment)
}

//def make[StartupEnv, Input, Env, State, Params](effect:ZIO[Input, Throwable, StepContext[Env, State, Params]])
//def make[R, StartupEnv, Input, Env, State, Params](effect:ZIO[R, Throwable, StepContext[Env, State, Params]]) = ???

val withNoRequirements: ContextSetup[Any, Any, Any, Any, Any] = ContextSetup { _: Any =>
ZIO.succeed(StepContext(environment = (), state = (), params = ()))
}

final case class CreateFromRecipe[StartupEnv, Input, Env, State, Params](
recipe0: RIO[(StartupEnv, Input), StepContext[Env, State, Params]]
) extends ContextSetup[StartupEnv, Input, Env, State, Params] {

/**
* The effect that can be used to build the `StepContext`
*/
def recipe: ZIO[(StartupEnv, Input), Throwable, StepContext[Env, State, Params]] = recipe0
}

final case class Create[StartupEnv, Input, Env, State, Params](
f: Input => RIO[StartupEnv, StepContext[Env, State, Params]]
) extends ContextSetup[StartupEnv, Input, Env, State, Params] {

/**
* The effect that can be used to build the `StepContext`
*/
def recipe: ZIO[(StartupEnv, Input), Throwable, StepContext[Env, State, Params]] =
ZIO.accessM[(StartupEnv, Input)] { case (env, input) =>
f(input).provide(env)
}
}
}
Loading

0 comments on commit b009404

Please sign in to comment.