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

4u.meteor-awssdk_3.2.0.11.source-code.syntax.scala Maven / Gradle / Ivy

package meteor

import cats.implicits._
import software.amazon.awssdk.services.dynamodb.model.AttributeValue
import meteor.codec._
import meteor.errors.DecoderError

/** Utility to help writing [[meteor.codec.Codec]], [[meteor.codec.Encoder]] and [[meteor.codec.Decoder]].
  *
  * Examples:
  * {{{
  * import meteor.syntax._
  * import meteor.codec._
  *
  * case class Author(
  *   names: String,
  *   age: Int
  * )
  *
  * case class Book(
  *   name: String,
  *   author: Author,
  *   coAuthor: Option[Author]
  * )
  *
  * implicit val encoderForAuthor: Encoder[Author] = Encoder.instance { obj =>
  *   Map(
  *     "names" -> obj.names.asAttributeValue,
  *     "age" -> obj.age.asAttributeValue
  *   ).asAttributeValue
  * }
  *
  * implicit val encoderForBook: Encoder[Book] = Encoder.instance { obj =>
  *   Map(
  *     "name" -> obj.names.asAttributeValue,
  *     "author" -> obj.age.asAttributeValue,
  *     "coAuthor" -> obj.age.asAttributeValue,
  *   ).asAttributeValue
  * }
  *
  * implicit val decoderForAuthor: Decoder[Author] = Decoder.instance { av =>
  *   for {
  *     names <- av.getAs[String]("names")
  *     age <- av.getAs[Int]("age")
  *   } yield Author(names, age)
  * }
  *
  * implicit val decoderForBook: Decoder[Book] = Decoder.instance { av =>
  *   for {
  *     name <- av.getAs[String]("name")
  *     author <- av.getAs[Author]("author")
  *     coAuthor <- av.getOpt[Author]("coAuthor")
  *   } yield Book(name, author, coAuthor)
  * }
  * }}}
  */
trait syntax {

  /** Provide extension method(s) to write to a Java AttributeValue
    */
  implicit class RichWriteAttributeValue[A: Encoder](a: A) {

    /** Write value of type A to an AttributeValue given an `meteor.codec.Encoder` of A in scope.
      */
    def asAttributeValue: AttributeValue = Encoder[A].write(a)
  }

  /** Provide extension method(s) to read from a Java AttributeValue
    */
  implicit class RichReadAttributeValue(av: AttributeValue) {

    /** Attempt to read the AttributeValue as a value of type A or DecoderError
      *
      * Note: if the value of the AttributeValue is nullable, use `asOpt` instead.
      *
      * @return either a value of type A or DecoderError
      */
    def as[A: Decoder]: Either[DecoderError, A] = Decoder[A].read(av)

    /** Attempt to read the AttributeValue as an optional value of type A or DecoderError.
      * This should be used when AttributeValue can be NULL.
      *
      * @return either an optional value of type A or DecoderError
      */
    def asOpt[A: Decoder]: Either[DecoderError, Option[A]] =
      if (Option(av.nul()).exists(_.booleanValue())) None.asRight
      else av.as[A].map(_.some)

    /** Attempt to treat the AttributeValue as of type M, retrieve value by a given key as an
      * AttributeValue.
      *
      * @param key the key whose associated value is to be returned
      * @return either a value as AttributeValue type or DecoderError
      */
    def get(key: String): Either[DecoderError, AttributeValue] =
      if (av.hasM) {
        Option(av.m().get(key)).fold(
          DecoderError.missingKeyFailure(key).asLeft[AttributeValue]
        )(_.asRight[DecoderError])
      } else {
        DecoderError.invalidTypeFailure(DynamoDbType.M).asLeft[AttributeValue]
      }

    /** Attempt to treat the AttributeValue as of type M, retrieve AttributeValue that associated to
      * a given key and attempt reading it to a value of type A.
      *
      * Note: if the returning AttributeValue is nullable, use `getOpt` instead.
      *
      * @param key the key whose associated value is to be returned
      * @return either a value of type A type or DecoderError
      */
    def getAs[A: Decoder](key: String): Either[DecoderError, A] =
      get(key).flatMap(_.as[A])

    /** Attempt to treat the AttributeValue as of type M, retrieve AttributeValue that associated to
      * a given key and attempt reading it to an optional value of type A.
      * This should be used when the returning AttributeValue can be NULL.
      *
      * @param key the key whose associated value is to be returned
      * @return either a value of type A type or DecoderError
      */
    def getOpt[A: Decoder](key: String): Either[DecoderError, Option[A]] =
      if (av.hasM) {
        Option(av.m().get(key)).fold(none[A].asRight[DecoderError])(_.asOpt[A])
      } else {
        DecoderError.invalidTypeFailure(DynamoDbType.M).asLeft[Option[A]]
      }
  }
}

object syntax extends syntax




© 2015 - 2024 Weber Informatics LLC | Privacy Policy