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

anorm.ToSql.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) from 2022 The Play Framework Contributors , 2011-2021 Lightbend Inc. 
 */

package anorm

/** Set value as prepared SQL statement fragment. */
@annotation.implicitNotFound("No SQL renderer found for parameter of type ${A}: `anorm.ToSql[${A}]` required")
trait ToSql[A] {

  /**
   * Prepares SQL fragment for value,
   * using `java.sql.PreparedStatement` syntax (with '?').
   *
   * @return SQL fragment and count of "?" placeholders in it
   */
  def fragment(value: A): (String, Int)
}

/** Provided ToSql implementations. */
object ToSql {
  import scala.collection.immutable.SortedSet

  private class FunctionalToSql[A](f: A => (String, Int)) extends ToSql[A] {
    def fragment(value: A): (String, Int) = f(value)
  }

  /** Functional factory */
  def apply[A](f: A => (String, Int)): ToSql[A] = new FunctionalToSql(f)

  /**
   * Returns fragment for each value, separated by ", ".
   *
   * {{{
   * anorm.ToSql.listToSql[Int].fragment(List(1, 3, 5))
   * // "?, ?, ?"
   * }}}
   */
  implicit def listToSql[A](implicit conv: ToSql[A] = ToSql.missing[A]): ToSql[List[A]] = traversableToSql[A, List[A]]

  /**
   * Returns fragment for each value, separated by ", ".
   *
   * {{{
   * anorm.ToSql.seqToSql[String].fragment(Seq("A", "B", "C"))
   * // "?, ?, ?"
   * }}}
   */
  implicit def seqToSql[A](implicit conv: ToSql[A] = ToSql.missing[A]): ToSql[Seq[A]] = traversableToSql[A, Seq[A]]

  /**
   * Returns fragment for each value, separated by ", ".
   *
   * {{{
   * anorm.ToSql.setToSql[Int].fragment(Set(1, 3, 5))
   * // "?, ?, ?"
   * }}}
   */
  implicit def setToSql[A](implicit conv: ToSql[A] = ToSql.missing[A]): ToSql[Set[A]] = traversableToSql[A, Set[A]]

  /**
   * Returns fragment for each value, separated by ", ".
   *
   * {{{
   * import scala.collection.immutable.SortedSet
   *
   * anorm.ToSql.sortedSetToSql[String].fragment(SortedSet("A", "B", "C"))
   * // "?, ?, ?"
   * }}}
   */
  implicit def sortedSetToSql[A](implicit conv: ToSql[A] = ToSql.missing[A]): ToSql[SortedSet[A]] =
    traversableToSql[A, SortedSet[A]]

  /**
   * Returns fragment for each value, separated by ", ".
   */
  implicit def streamToSql[A](implicit conv: ToSql[A] = ToSql.missing[A]): ToSql[Compat.LazyLst[A]] =
    traversableToSql[A, Compat.LazyLst[A]]

  /**
   * Returns fragment for each value, separated by ", ".
   *
   * {{{
   * anorm.ToSql.vectorToSql[String].fragment(Vector("A", "B", "C"))
   * // "?, ?, ?"
   * }}}
   */
  implicit def vectorToSql[A](implicit conv: ToSql[A] = ToSql.missing[A]): ToSql[Vector[A]] =
    traversableToSql[A, Vector[A]]

  /** Returns fragment for each value, with custom formatting. */
  implicit def seqParamToSql[A](implicit conv: ToSql[A] = ToSql.missing[A]): ToSql[SeqParameter[A]] =
    ToSql[SeqParameter[A]] { p =>
      val before = p.before.getOrElse("")
      val after  = p.after.getOrElse("")
      val c: A => (String, Int) =
        if (conv == null) _ => "?" -> 1 else conv.fragment

      val sql = p.values.foldLeft(new StringBuilder() -> 0) {
        case ((sb, i), v) =>
          val frag = c(v)
          val st =
            if (i > 0) sb ++= p.separator ++= before ++= frag._1
            else sb ++= before ++= frag._1

          (st ++= after, i + frag._2)
      }

      sql._1.toString -> sql._2
    }

  @inline private def traversableToSql[A, T <: Compat.Trav[A]](implicit conv: ToSql[A]) = ToSql[T] { values =>
    val c: A => (String, Int) =
      if (conv == null) _ => "?" -> 1 else conv.fragment

    val sql = values.foldLeft(new StringBuilder() -> 0) {
      case ((sb, i), v) =>
        val frag = c(v)
        val st   = if (i > 0) sb ++= ", " ++= frag._1 else sb ++= frag._1

        (st, i + frag._2)
    }

    sql._1.toString -> sql._2
  }

  /** Fallback when no instance is available. */
  @deprecated("Do not use", "2.5.4")
  def missing[A] = null
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy