From 8b3748e2faabc80294d9ff2bfdad229b93d2f6c9 Mon Sep 17 00:00:00 2001 From: geirolz Date: Thu, 2 May 2024 17:00:46 +0200 Subject: [PATCH 1/3] Add decoder attempt instance --- .../fs2rabbit/effects/EnvelopeDecoder.scala | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/dev/profunktor/fs2rabbit/effects/EnvelopeDecoder.scala b/core/src/main/scala/dev/profunktor/fs2rabbit/effects/EnvelopeDecoder.scala index 97b13197..5777b706 100644 --- a/core/src/main/scala/dev/profunktor/fs2rabbit/effects/EnvelopeDecoder.scala +++ b/core/src/main/scala/dev/profunktor/fs2rabbit/effects/EnvelopeDecoder.scala @@ -15,13 +15,14 @@ */ package dev.profunktor.fs2rabbit.effects -import cats.{Applicative, ApplicativeThrow} +import cats.{Applicative, ApplicativeThrow, MonadError} import cats.data.Kleisli import dev.profunktor.fs2rabbit.model.{AmqpFieldValue, AmqpProperties, ExchangeName, RoutingKey} import dev.profunktor.fs2rabbit.model.AmqpFieldValue._ import cats.implicits._ -object EnvelopeDecoder { +object EnvelopeDecoder extends EnvelopeDecoderInstances { + def apply[F[_], A](implicit e: EnvelopeDecoder[F, A]): EnvelopeDecoder[F, A] = e def properties[F[_]: Applicative]: EnvelopeDecoder[F, AmqpProperties] = @@ -81,3 +82,11 @@ object EnvelopeDecoder { ): EnvelopeDecoder[F, Option[A]] = Kleisli(_.properties.headers.get(name).traverse(h => F.catchNonFatal(pf(h)))) } + +sealed trait EnvelopeDecoderInstances { + + implicit def decoderAttempt[F[_], E: MonadError[F, *], A](implicit + decoder: EnvelopeDecoder[F, A] + ): EnvelopeDecoder[F, Either[E, A]] = + decoder.attempt +} From 80a16fbc0031051474d5fce8c27d7442f65ea129 Mon Sep 17 00:00:00 2001 From: geirolz Date: Tue, 28 May 2024 09:22:14 +0200 Subject: [PATCH 2/3] Add Option decoder --- .../profunktor/fs2rabbit/effects/EnvelopeDecoder.scala | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/dev/profunktor/fs2rabbit/effects/EnvelopeDecoder.scala b/core/src/main/scala/dev/profunktor/fs2rabbit/effects/EnvelopeDecoder.scala index 5777b706..debd4f97 100644 --- a/core/src/main/scala/dev/profunktor/fs2rabbit/effects/EnvelopeDecoder.scala +++ b/core/src/main/scala/dev/profunktor/fs2rabbit/effects/EnvelopeDecoder.scala @@ -15,7 +15,7 @@ */ package dev.profunktor.fs2rabbit.effects -import cats.{Applicative, ApplicativeThrow, MonadError} +import cats.{Applicative, ApplicativeError, ApplicativeThrow, MonadError} import cats.data.Kleisli import dev.profunktor.fs2rabbit.model.{AmqpFieldValue, AmqpProperties, ExchangeName, RoutingKey} import dev.profunktor.fs2rabbit.model.AmqpFieldValue._ @@ -85,8 +85,13 @@ object EnvelopeDecoder extends EnvelopeDecoderInstances { sealed trait EnvelopeDecoderInstances { - implicit def decoderAttempt[F[_], E: MonadError[F, *], A](implicit + implicit def decoderAttempt[F[_], E: ApplicativeError[F, *], A](implicit decoder: EnvelopeDecoder[F, A] ): EnvelopeDecoder[F, Either[E, A]] = decoder.attempt + + implicit def decoderOption[F[_], E: ApplicativeError[F, *], A](implicit + decoder: EnvelopeDecoder[F, A] + ): EnvelopeDecoder[F, Option[A]] = + decoder.attempt.map(_.toOption) } From 920b3cbb92c4615be20cebcd7cacb63744b3b845 Mon Sep 17 00:00:00 2001 From: geirolz Date: Thu, 30 May 2024 13:13:54 +0200 Subject: [PATCH 3/3] Add tests --- .../effects/EnvelopeDecoderSpec.scala | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/core/src/test/scala/dev/profunktor/fs2rabbit/effects/EnvelopeDecoderSpec.scala b/core/src/test/scala/dev/profunktor/fs2rabbit/effects/EnvelopeDecoderSpec.scala index 8d5e8ee5..341b1ef8 100644 --- a/core/src/test/scala/dev/profunktor/fs2rabbit/effects/EnvelopeDecoderSpec.scala +++ b/core/src/test/scala/dev/profunktor/fs2rabbit/effects/EnvelopeDecoderSpec.scala @@ -31,11 +31,14 @@ import cats.effect.unsafe.implicits.global class EnvelopeDecoderSpec extends AsyncFunSuite { + import EnvelopeDecoder._ // Available instances of EnvelopeDecoder for any ApplicativeError[F, Throwable] EnvelopeDecoder[Either[Throwable, *], String] EnvelopeDecoder[SyncIO, String] EnvelopeDecoder[EitherT[IO, String, *], String] EnvelopeDecoder[Try, String] + EnvelopeDecoder[Try, Option[String]] + EnvelopeDecoder[Try, Either[Throwable, String]] test("should decode a UTF-8 string") { val msg = "hello world!" @@ -86,4 +89,32 @@ class EnvelopeDecoderSpec extends AsyncFunSuite { .unsafeToFuture() } + test("should decode a UTF-8 string - Attempt") { + val msg = "hello world!" + val raw = msg.getBytes(StandardCharsets.UTF_8) + + EnvelopeDecoder[IO, Either[Throwable, String]] + .run( + AmqpEnvelope(DeliveryTag(0L), raw, AmqpProperties.empty, ExchangeName("test"), RoutingKey("test.route"), false) + ) + .flatMap { result => + IO(assert(result == Right(msg))) + } + .unsafeToFuture() + } + + test("should decode a UTF-8 string - Attempt option") { + val msg = "hello world!" + val raw = msg.getBytes(StandardCharsets.UTF_8) + + EnvelopeDecoder[IO, Option[String]] + .run( + AmqpEnvelope(DeliveryTag(0L), raw, AmqpProperties.empty, ExchangeName("test"), RoutingKey("test.route"), false) + ) + .flatMap { result => + IO(assert(result == Option(msg))) + } + .unsafeToFuture() + } + }