All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.evolutiongaming.kafka.journal.eventual.EventualRead.scala Maven / Gradle / Ivy

The newest version!
package com.evolutiongaming.kafka.journal.eventual

import cats.syntax.all._
import cats.~>
import com.evolutiongaming.catshelper.MonadThrowable
import com.evolutiongaming.kafka.journal.util.Fail
import com.evolutiongaming.kafka.journal.util.Fail.implicits._
import com.evolutiongaming.kafka.journal.{JournalError, JsonCodec, Payload, PayloadType}


trait EventualRead[F[_], A] {

  def apply(payloadAndType: EventualPayloadAndType): F[A]

}

object EventualRead {

  def summon[F[_], A](implicit eventualRead: EventualRead[F, A]): EventualRead[F, A] = eventualRead

  implicit def payloadEventualRead[F[_]: MonadThrowable](implicit decode: JsonCodec.Decode[F]): EventualRead[F, Payload] = {
    implicit val fail: Fail[F] = Fail.lift[F]

    payloadAndType => {
      payloadAndType.payloadType match {
        case PayloadType.Binary => liftError(payloadAndType) {
          payloadAndType.payloadBytes[F].map(Payload.binary)
        }

        case PayloadType.Text => liftError(payloadAndType) {
          payloadAndType.payloadStr[F].map(Payload.text)
        }

        case PayloadType.Json =>
          val jsonEventualRead = EventualRead.readJson(decode.fromStr(_).map(Payload(_)))
          jsonEventualRead(payloadAndType)
      }
    }
  }

  def readJson[F[_]: MonadThrowable, A](parsePayload: String => F[A]): EventualRead[F, A] = {
    implicit val fail: Fail[F] = Fail.lift[F]

    payloadAndType => {
      payloadAndType.payloadType match {
        case PayloadType.Json =>
          liftError(payloadAndType) {
            payloadAndType.payloadStr[F].flatMap(parsePayload)
          }

        case other => s"Json payload type expected, got: $other".fail
      }
    }
  }

  private def liftError[F[_]: MonadThrowable, A](payloadAndType: EventualPayloadAndType)(fa: F[A]): F[A] =
    fa.adaptError { case e =>
      JournalError(s"EventualRead failed for $payloadAndType: $e", e)
    }

  implicit class EventualReadOps[F[_], A](val self: EventualRead[F, A]) extends AnyVal {

    def mapK[G[_]](fg: F ~> G): EventualRead[G, A] =
      payloadAndType => fg(self(payloadAndType))
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy