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

com.twitter.finagle.mysql.Parameter.scala Maven / Gradle / Ivy

There is a newer version: 24.2.0
Show newest version
package com.twitter.finagle.mysql

import com.twitter.finagle.mysql.transport.MysqlBufWriter
import java.util.logging.Logger
import scala.language.implicitConversions

/**
 * A value of type `A` can implicitly convert to a `Parameter` if an evidence
 * `CanBeParameter[A]` is available in scope via the [[Parameter.wrap]] or
 * [[Parameter.wrapOption]] implicits. Explicit conversions are available
 * via [[Parameter.of]] and [[Parameters.of]].
 *
 * A Scala example with implicits:
 * {{{
 * import com.twitter.finagle.mysql.Parameter
 * import com.twitter.finagle.mysql.Parameter._
 *
 * val p: Parameter = "this will get implicitly converted to a Parameter"
 * }}}
 *
 * A Scala example without implicits:
 * {{{
 * import com.twitter.finagle.mysql.Parameter
 *
 * val p: Parameter = Parameter.of("explicitly converted to a Parameter")
 * }}}
 *
 * A Java example:
 * {{{
 * import com.twitter.finagle.mysql.Parameter;
 * import com.twitter.finagle.mysql.Parameters;
 *
 * Parameter p = Parameters.of("explicitly converted to a Parameter");
 * }}}
 */
sealed trait Parameter {
  type A
  def value: A
  def evidence: CanBeParameter[A]

  final def writeTo(writer: MysqlBufWriter): Unit = {
    evidence.write(writer, value)
  }

  final def size: Int = evidence.sizeOf(value)
  final def typeCode: Short = evidence.typeCode(value)
}

/**
 * For Scala users, the typical usage is by importing the implicit conversions
 * and then letting the compiler do the conversions for you. Explicit
 * runtime conversions are also available via [[Parameter.of]].
 *
 * Java users should generally be using [[Parameters.of]] to do explicit
 * conversions.
 *
 * A Scala example with implicits:
 * {{{
 * import com.twitter.finagle.mysql.Parameter
 * import com.twitter.finagle.mysql.Parameter._
 *
 * val p: Parameter = "this will get implicitly converted to a Parameter"
 * }}}
 *
 * A Scala example without implicits:
 * {{{
 * import com.twitter.finagle.mysql.Parameter
 *
 * val p: Parameter = Parameter.of("explicitly converted to a Parameter")
 * }}}
 *
 * A Java example:
 * {{{
 * import com.twitter.finagle.mysql.Parameter;
 * import com.twitter.finagle.mysql.Parameters;
 *
 * Parameter p = Parameters.of("explicitly converted to a Parameter");
 * }}}
 *
 * @see [[Parameters]] for a Java-friendly API.
 */
object Parameter {

  /**
   * Generally used via implicits.
   * Input of `None` is treated as a `NULL`.
   *
   * {{{
   * import com.twitter.finagle.mysql.Parameter
   * import com.twitter.finagle.mysql.Parameter._
   *
   * val p: Parameter = Some("this will get implicitly converted to a Parameter")
   * }}}
   *
   * Java users can use [[Parameters.of]].
   */
  implicit def wrapOption[_A](option: Option[_A])(implicit ev: CanBeParameter[_A]): Parameter =
    option match {
      case None => NullParameter
      case Some(value) => wrap(value)
    }

  /**
   * Generally used via implicits.
   *
   * {{{
   * import com.twitter.finagle.mysql.Parameter
   * import com.twitter.finagle.mysql.Parameter._
   *
   * val p: Parameter = "this will get implicitly converted to a Parameter"
   * }}}
   *
   * Java users can use [[Parameters.of]].
   */
  implicit def wrap[_A](_value: _A)(implicit _evidence: CanBeParameter[_A]): Parameter = {
    if (_value == null) {
      NullParameter
    } else {
      new Parameter {
        type A = _A
        def value: A = _value
        def evidence: CanBeParameter[A] = _evidence
        override def toString = s"Parameter($value)"
      }
    }
  }

  private val log = Logger.getLogger("finagle-mysql")

  /**
   * Converts the given `value` into a [[Parameter]] at runtime.
   *
   * Scala users may use the implicit conversions if they prefer.
   *
   * {{{
   * import com.twitter.finagle.mysql.Parameter
   *
   * val p: Parameter = Parameter.of("a string")
   * }}}
   *
   * @note Any unknown types are treated as a SQL NULL.
   * @see [[Parameters.of]] for Java users.
   */
  def of(value: Any): Parameter = value match {
    case null => NullParameter
    case Some(v) => of(v)
    case None => NullParameter
    case v: String => wrap(v)
    case v: Boolean => wrap(v)
    case v: Byte => wrap(v)
    case v: Short => wrap(v)
    case v: Int => wrap(v)
    case v: Long => wrap(v)
    case v: Float => wrap(v)
    case v: Double => wrap(v)
    case v: Array[Byte] => wrap(v)
    case v: Value => wrap(v)
    case v: java.sql.Timestamp => wrap(v)
    case v: java.sql.Date => wrap(v)
    case v: java.util.Date => wrap(v)
    case o: java.util.Optional[_] if o.isPresent => of(o.get())
    case o: java.util.Optional[_] => NullParameter
    case v =>
      // Unsupported type. Write the error to log, and write the type as null.
      // This allows us to safely skip writing the parameter without corrupting the buffer.
      log.warning(s"Unknown parameter ${v.getClass.getName} will be treated as SQL NULL.")
      NullParameter
  }

  /**
   * Synonym for [[of]].
   */
  def unsafeWrap(value: Any): Parameter = of(value)

  /**
   * Java users can use [[Parameters.nullParameter]].
   */
  object NullParameter extends Parameter {
    type A = Null
    def value: Null = null
    def evidence: CanBeParameter[Null] = CanBeParameter.nullCanBeParameter
  }
}

/**
 * A Java adaptation of the [[com.twitter.finagle.mysql.Parameter]] companion object.
 */
object Parameters {

  /**
   * See [[Parameter.NullParameter]].
   */
  def nullParameter: Parameter = Parameter.NullParameter

  /**
   * Java friendly factory method for a [[Parameter]].
   *
   * Synonym for [[of]].
   */
  def unsafeWrap(value: Any): Parameter = of(value)

  /**
   * Java friendly factory method for a [[Parameter]].
   */
  def of(value: Any): Parameter = Parameter.unsafeWrap(value)

  //TODO: create an accessor to Parameter.wrap, so type errors are caught at compile time.
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy