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

anorm.SimpleSql.scala Maven / Gradle / Ivy

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

package anorm

import java.sql.{ Connection, PreparedStatement }

/** Simple/plain SQL. */
case class SimpleSql[T](
    sql: SqlQuery,
    params: Map[String, ParameterValue],
    defaultParser: RowParser[T],
    resultSetOnFirstRow: Boolean = false
) extends Sql {

  /**
   * Returns the query prepared with named parameters.
   *
   * {{{
   * import anorm._
   *
   * val baseSql = SQL("SELECT * FROM table WHERE id = {id}") // one named param
   * val preparedSql = baseSql.on("id" -> "value")
   * }}}
   */
  def on(args: NamedParameter*): SimpleSql[T] =
    copy(params = this.params ++ args.map(_.tupled))

  /**
   * Returns the query prepared with parameters using initial order
   * of placeholder in statement.
   *
   * {{{
   * import anorm._
   *
   * val baseSql =
   *   SQL("SELECT * FROM table WHERE name = {name} AND lang = {lang}")
   *
   * val preparedSql = baseSql.onParams("1st", "2nd")
   * // 1st param = name, 2nd param = lang
   * }}}
   */
  def onParams(args: ParameterValue*): SimpleSql[T] =
    copy(params = this.params ++ Sql.zipParams(sql.paramsInitialOrder, args, Map.empty))

  /**
   * Returns the query prepared with the named parameters,
   * provided by the appropriate `converter`.
   *
   * @param value the value to be converted as list of [[NamedParameter]]
   * @param converter the function used to convert the `value`
   * @tparam U the type of the value
   */
  def bind[U](value: U)(implicit converter: ToParameterList[U]): SimpleSql[T] =
    on(converter(value): _*)

  private val prepareNoGeneratedKeys = { (con: Connection, sql: String) =>
    con.prepareStatement(sql)
  }

  private val prepareGeneratedKeys = { (con: Connection, sql: String) =>
    con.prepareStatement(sql, java.sql.Statement.RETURN_GENERATED_KEYS)
  }

  private def prepareGeneratedCols(columns: Array[String]) = { (con: Connection, sql: String) =>
    con.prepareStatement(sql, columns)
  }

  def unsafeStatement(connection: Connection, getGeneratedKeys: Boolean = false) = {
    if (getGeneratedKeys) unsafeStatement(connection, prepareGeneratedKeys)
    else unsafeStatement(connection, prepareNoGeneratedKeys)
  }

  def unsafeStatement(connection: Connection, generatedColumn: String, generatedColumns: Seq[String]) =
    unsafeStatement(connection, prepareGeneratedCols((generatedColumn +: generatedColumns).toArray))

  private def unsafeStatement(
      connection: Connection,
      prep: (Connection, String) => PreparedStatement
  ): PreparedStatement = {
    @SuppressWarnings(Array("TryGet"))
    def unsafe = Sql
      .query(sql.stmt.tokens, sql.paramsInitialOrder, params, 0, new StringBuilder(), List.empty[(Int, ParameterValue)])
      .get

    val (psql, vs): (String, Seq[(Int, ParameterValue)]) = unsafe

    val stmt = prep(connection, psql)

    sql.fetchSize.foreach(stmt.setFetchSize(_))
    sql.timeout.foreach(stmt.setQueryTimeout(_))

    vs.foreach { case (i, v) => v.set(stmt, i + 1) }

    stmt
  }

  /** Prepares query with given row parser. */
  @deprecated(message = "Use [[as]]", since = "2.5.1")
  def using[U](p: RowParser[U]): SimpleSql[U] = copy(sql, params, p)

  def map[A](f: T => A): SimpleSql[A] =
    copy(defaultParser = defaultParser.map(f))

  /** Returns a copy with updated timeout. */
  def withQueryTimeout(seconds: Option[Int]): SimpleSql[T] =
    copy(sql = sql.withQueryTimeout(seconds))

  /** Returns a copy with updated flag. */
  def withResultSetOnFirstRow(onFirst: Boolean): SimpleSql[T] =
    copy(resultSetOnFirstRow = onFirst)

  /** Fetch size */
  def fetchSize: Option[Int] = sql.fetchSize

  /**
   * Returns this query with the fetch suze updated to the row `count`.
   * @see [[SqlQuery.fetchSize]]
   */
  def withFetchSize(count: Option[Int]): SimpleSql[T] =
    copy(sql.withFetchSize(count))

}

object SimpleSql {
  final class SimpleSqlShow[T](sql: SimpleSql[T]) extends Show {

    def show = s"SimpleSql(${Show.mkString(sql.sql)})"
  }

  final class ShowMaker[T] extends Show.Maker[SimpleSql[T]] {
    def apply(subject: SimpleSql[T]): Show = new SimpleSqlShow(subject)
  }

  implicit def showMaker[T]: Show.Maker[SimpleSql[T]] = new ShowMaker[T]
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy