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

io.kaizensolutions.virgil.codecs.CqlUdtValueEncoder.scala Maven / Gradle / Ivy

There is a newer version: 1.2.1
Show newest version
package io.kaizensolutions.virgil.codecs

import com.datastax.oss.driver.api.core.`type`.UserDefinedType
import com.datastax.oss.driver.api.core.data.UdtValue

/**
 * A [[CqlUdtValueEncoder]] encodes a Scala type `A` as a component of a
 * `UdtValue`
 *
 * @tparam A
 */
trait CqlUdtValueEncoder[-A] {
  def encodeByFieldName(structure: UdtValue, fieldName: String, value: A): UdtValue
  def encodeByIndex(structure: UdtValue, index: Int, value: A): UdtValue
}
object CqlUdtValueEncoder extends UdtValueEncoderMagnoliaDerivation {

  /**
   * A [[CqlUdtValueEncoder.Object]] that encodes a Scala type `A` as an entire
   * `UdtValue`. This is really contravariant in A but Magnolia's automatic
   * derivation process is disrupted
   *
   * @tparam A
   */
  trait Object[A] extends CqlUdtValueEncoder[A] { self =>
    def encode(structure: UdtValue, value: A): UdtValue

    override def encodeByFieldName(structure: UdtValue, fieldName: String, value: A): UdtValue = {
      val emptySubStructure  = structure.getType(fieldName).asInstanceOf[UserDefinedType].newValue()
      val filledSubStructure = encode(emptySubStructure, value)
      structure.setUdtValue(fieldName, filledSubStructure)
    }

    override def encodeByIndex(structure: UdtValue, index: Int, value: A): UdtValue = {
      val emptySubStructure  = structure.getType(index).asInstanceOf[UserDefinedType].newValue()
      val filledSubStructure = encode(emptySubStructure, value)
      structure.setUdtValue(index, filledSubStructure)
    }

    def contramap[B](f: B => A): CqlUdtValueEncoder.Object[B] = new CqlUdtValueEncoder.Object[B] {
      override def encode(structure: UdtValue, value: B): UdtValue = self.encode(structure, f(value))
    }

    // Safe to use a subtype because a subtype contains more information, therefore we can discard the extra information
    // prior to writing the data
    def narrow[B <: A]: CqlUdtValueEncoder.Object[B] = contramap(identity)

    def zip[B](that: CqlUdtValueEncoder.Object[B]): CqlUdtValueEncoder.Object[(A, B)] =
      new CqlUdtValueEncoder.Object[(A, B)] {
        def encode(structure: UdtValue, value: (A, B)): UdtValue = {
          val (a, b)   = value
          val resultA  = self.encode(structure, a)
          val resultAB = that.encode(resultA, b)
          resultAB
        }
      }
  }

  def apply[A](implicit encoder: CqlUdtValueEncoder.Object[A]): CqlUdtValueEncoder.Object[A] = encoder

  def custom[A](f: (UdtValue, A) => UdtValue): CqlUdtValueEncoder.Object[A] = new CqlUdtValueEncoder.Object[A] {
    override def encode(structure: UdtValue, value: A): UdtValue = f(structure, value)
  }

  implicit def fromCqlPrimitive[A](implicit prim: CqlPrimitiveEncoder[A]): CqlUdtValueEncoder[A] =
    new CqlUdtValueEncoder[A] {
      override def encodeByFieldName(structure: UdtValue, fieldName: String, value: A): UdtValue =
        CqlPrimitiveEncoder.encodePrimitiveByFieldName(structure, fieldName, value)(prim)

      override def encodeByIndex(structure: UdtValue, index: Int, value: A): UdtValue =
        CqlPrimitiveEncoder.encodePrimitiveByIndex(structure, index, value)(prim)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy