Skip to content

Instantly share code, notes, and snippets.

@notxcain
Created October 16, 2017 14:22
Show Gist options
  • Select an option

  • Save notxcain/6a9fd101832a3e095ceadd4f0bd41728 to your computer and use it in GitHub Desktop.

Select an option

Save notxcain/6a9fd101832a3e095ceadd4f0bd41728 to your computer and use it in GitHub Desktop.
Projection
package com.evotor.payments.common
import aecor.data.Folded
import cats.MonadError
import cats.implicits._
object Projection {
def apply[F[_], I, E, S](
store: Store[F, I, Versioned[S]]
)(implicit F: MonadError[F, Throwable], SE: Eventsourced[S, E]): (I, Long, E) => F[Unit] = {
(id, seqNr, e) =>
def error[A](message: String): F[A] =
F.raiseError[A](new RuntimeException(message))
for {
oldStateOpt <- store.readState(id)
v = oldStateOpt.fold(0L)(_.version)
_ <- if (seqNr <= v) {
().pure[F]
} else if (seqNr == v + 1) {
oldStateOpt
.map(_.a)
.fold(SE.init(e))(SE.update(e, _))
.fold(error[Unit]("Illegal fold"), a => store.saveState(id, Versioned(v + 1, a)))
} else {
error[Unit]("Missing event")
}
} yield ()
}
}
trait Store[F[_], I, S] {
def readState(i: I): F[Option[S]]
def saveState(i: I, s: S): F[Unit]
}
trait Eventsourced[S, E] {
def init(e: E): Folded[S]
def update(e: E, s: S): Folded[S]
}
case class Versioned[A](version: Long, a: A)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment