Skip to content

Commit

Permalink
Add deployer generic abstraction that captures sharded repository ope…
Browse files Browse the repository at this point in the history
…ration
  • Loading branch information
Jonas Chapuis committed Sep 13, 2023
1 parent 7727601 commit f004fb4
Showing 1 changed file with 86 additions and 0 deletions.
86 changes: 86 additions & 0 deletions core/src/main/scala/endless/core/entity/Deployer.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package endless.core.entity

import cats.effect.kernel.Resource
import endless.core.entity.Deployer.{InterpretedEffector, InterpretedEntity, InterpretedRepository}
import endless.core.event.EventApplier
import endless.core.interpret.EffectorT.EffectorT
import endless.core.interpret.EntityT
import endless.core.protocol.CommandProtocol

/** `Deployer` deploys entity repositories by assembling the required interpreters and components.
*/
trait Deployer {

/** Deploys an entity repository in context `F`, returning an instance of its algebra wrapped in a
* resource (since deployments typically require finalization).
*
* Repository operation uses the three provided interpreters in combination, following a strictly
* defined sequence:
* - the interpreted repository is used to create a handle on the entity with the specified ID,
* which implements the entity algebra. This allows further interaction with the entity by
* the caller of the repository algebra.
* - the interpreted entity runs invoked function on the entity algebra: this possibly involves
* reading the entity state (e.g. for validation), and writing events (which affect the
* state)
* - after events were written, a possible side-effect is triggered: this can be asynchronous
* (i.e. the function doesn't wait for completion)
* - the function finally returns to the caller of entity algebra
*
* This interaction pattern occurs with "actor-like" semantics: all calls on the entity are
* processed in sequence.
*
* @param repository
* provides access to to an entity with a specific ID via its algebra
* @param entity
* runs calls on entity algebra
* @param effector
* handles side-effects after entity interaction
* @param nameProvider
* provides a name for the entity (in other words, the "type of entity", e.g. "booking")
* @param commandProtocol
* protocol-centric definition of entity algebra: defines a wire encoding for interactions with
* remote entities
* @param eventApplier
* defines how events are applied to the entity state
* @tparam ID
* entity ID
* @tparam S
* entity state
* @tparam Alg
* entity algebra
* @tparam RepositoryAlg
* repository algebra
* @tparam EffectorAlg
* effector algebra
* @return
* a resource encapsulating access to the repository algebra
*/
def deployRepository[F[_], ID, S, E, Alg[_[_]], RepositoryAlg[_], EffectorAlg[_]](
repository: InterpretedRepository[F, ID, Alg, RepositoryAlg],
entity: InterpretedEntity[F, S, E, Alg],
effector: InterpretedEffector[F, S, Alg, RepositoryAlg, EffectorAlg]
)(implicit
nameProvider: EntityNameProvider[ID],
commandProtocol: CommandProtocol[Alg],
eventApplier: EventApplier[S, E]
): Resource[F, RepositoryAlg[F]]

}

object Deployer {
trait InterpretedEntity[F[_], S, E, Alg[_[_]]] {
def apply(entity: Entity[EntityT[F, S, E, *], S, E]): F[Alg[EntityT[F, S, E, *]]]
}

trait InterpretedRepository[F[_], ID, Alg[_[_]], RepositoryAlg[_]] {
def apply(repository: Repository[F, ID, Alg]): F[RepositoryAlg[F]]
}

trait InterpretedEffector[F[_], S, Alg[_[_]], RepositoryAlg[_], EffectorAlg[_]] {
def apply(
effector: Effector[EffectorT[F, S, Alg, *], S, Alg],
repositoryAlg: RepositoryAlg[F],
entityAlg: Alg[F]
): F[EffectorAlg[F]]
}
}

0 comments on commit f004fb4

Please sign in to comment.