scalikejdbc.Binders.scala Maven / Gradle / Ivy
package scalikejdbc
import java.io.InputStream
import java.sql.{ PreparedStatement, ResultSet }
import java.time.ZoneId
import JavaUtilDateConverterImplicits._
/**
* Provides both of TypeBinder and ParameterBinderFactory for the specified type A.
*/
trait Binders[A] extends TypeBinder[A] with ParameterBinderFactory[A] { self =>
def xmap[B](f: A => B, g: B => A): Binders[B] = new Binders[B] {
def apply(rs: ResultSet, columnIndex: Int): B = f(self(rs, columnIndex))
def apply(rs: ResultSet, columnLabel: String): B = f(self(rs, columnLabel))
def apply(value: B): ParameterBinderWithValue = self.contramap(g)(value)
}
}
/**
* Provides factories of Binders and built-in Binders.
*/
object Binders {
// --------------------------------------------------------------------------------------------
// Factory methods
// --------------------------------------------------------------------------------------------
def apply[A](index: (ResultSet, Int) => A)(label: (ResultSet, String) => A)(f: A => (PreparedStatement, Int) => Unit): Binders[A] = new Binders[A] {
def apply(rs: ResultSet, columnIndex: Int): A = index(rs, columnIndex)
def apply(rs: ResultSet, columnLabel: String): A = label(rs, columnLabel)
def apply(value: A): ParameterBinderWithValue = {
if (value == null) ParameterBinder.NullParameterBinder
else ParameterBinder(value, f(value))
}
}
def of[A](f: Any => A)(g: A => (PreparedStatement, Int) => Unit): Binders[A] = new Binders[A] {
def apply(rs: ResultSet, columnIndex: Int): A = f(rs.getObject(columnIndex))
def apply(rs: ResultSet, columnLabel: String): A = f(rs.getObject(columnLabel))
def apply(value: A): ParameterBinderWithValue = {
if (value == null) ParameterBinder.NullParameterBinder
else ParameterBinder(value, g(value))
}
}
private[scalikejdbc] def option[A](t: Binders[A]): Binders[Option[A]] = option(t, t)
def option[A](implicit b: TypeBinder[A], p: ParameterBinderFactory[A]): Binders[Option[A]] = new Binders[Option[A]] {
def apply(rs: ResultSet, columnIndex: Int): Option[A] = TypeBinder.option(b).apply(rs, columnIndex)
def apply(rs: ResultSet, columnLabel: String): Option[A] = TypeBinder.option(b).apply(rs, columnLabel)
def apply(value: Option[A]): ParameterBinderWithValue = ParameterBinderFactory.optionalParameterBinderFactory(p).apply(value)
}
// ----------------------------------------------------
// private
private[this] def throwExceptionIfNull[A <: AnyVal, B](f: B => A)(a: B): A = {
if (a == null) throw new UnexpectedNullValueException else f(a)
}
private[this] def wrapCastOption[A <: AnyVal, B](o: B): Option[A] = Option(o).asInstanceOf[Option[A]]
private[this] def unwrapCastOption[A <: AnyVal, B](o: Option[A]): B = o match {
case Some(v) => v.asInstanceOf[B]
case None => null.asInstanceOf[B]
}
private[scalikejdbc] def nullThrough[A, B](f: A => B)(a: A): B = if (a == null) null.asInstanceOf[B] else f(a)
private[scalikejdbc] def convertJavaTimeZonedDateTime(z: ZoneId): java.sql.Timestamp => java.time.ZonedDateTime =
nullThrough(x => java.time.ZonedDateTime.ofInstant(x.toInstant, z))
private[scalikejdbc] def convertJavaTimeOffsetDateTime(z: ZoneId): java.sql.Timestamp => java.time.OffsetDateTime =
nullThrough(x => java.time.OffsetDateTime.ofInstant(x.toInstant, z))
private[scalikejdbc] def convertJavaTimeLocalDateTime(z: ZoneId): java.sql.Timestamp => java.time.LocalDateTime =
nullThrough(x => java.time.LocalDateTime.ofInstant(x.toInstant, z))
// --------------------------------------------------------------------------------------------
// Built-in Binders
// --------------------------------------------------------------------------------------------
val javaInteger: Binders[java.lang.Integer] = Binders.of[java.lang.Integer] {
case null => null
case v: Float => v.toInt.asInstanceOf[java.lang.Integer]
case v: Double => v.toInt.asInstanceOf[java.lang.Integer]
case n: Number => n.intValue
case v => java.lang.Integer.valueOf(v.toString)
}(v => (ps, idx) => ps.setInt(idx, v.intValue))
val int: Binders[Int] = javaInteger.xmap(throwExceptionIfNull(_.intValue), Integer.valueOf)
val optionInt: Binders[Option[Int]] = javaInteger.xmap(wrapCastOption[Int, Integer], unwrapCastOption[Int, Integer])
val javaBoolean: Binders[java.lang.Boolean] = Binders.of[java.lang.Boolean] {
case null => null
case b: java.lang.Boolean => b
case b: Boolean => b.asInstanceOf[java.lang.Boolean]
case s: String if s == "false" || s == "true" => s.toBoolean
case s: String => {
try s.toInt != 0
catch { case e: NumberFormatException => s.nonEmpty }
}.asInstanceOf[java.lang.Boolean]
case n: Number => (n.intValue() != 0).asInstanceOf[java.lang.Boolean]
case v => (v != 0).asInstanceOf[java.lang.Boolean]
}(v => (ps, idx) => ps.setBoolean(idx, v))
val boolean: Binders[Boolean] = javaBoolean.xmap(throwExceptionIfNull(_.booleanValue), java.lang.Boolean.valueOf)
val optionBoolean: Binders[Option[Boolean]] = javaBoolean.xmap(wrapCastOption[Boolean, java.lang.Boolean], unwrapCastOption[Boolean, java.lang.Boolean])
val javaShort: Binders[java.lang.Short] = Binders.of[java.lang.Short] {
case null => null
case v: Float => v.toShort.asInstanceOf[java.lang.Short]
case v: Double => v.toShort.asInstanceOf[java.lang.Short]
case n: Number => n.shortValue
case v => java.lang.Short.valueOf(v.toString)
}(v => (ps, idx) => ps.setShort(idx, v))
val short: Binders[Short] = javaShort.xmap(throwExceptionIfNull(_.shortValue), java.lang.Short.valueOf)
val optionShort: Binders[Option[Short]] = javaShort.xmap(wrapCastOption[Short, java.lang.Short], unwrapCastOption[Short, java.lang.Short])
val javaLong: Binders[java.lang.Long] = Binders.of[java.lang.Long] {
case null => null
case v: Float => v.toLong.asInstanceOf[java.lang.Long]
case v: Double => v.toLong.asInstanceOf[java.lang.Long]
case n: Number => n.longValue
case v => java.lang.Long.valueOf(v.toString)
}(v => (ps, idx) => ps.setLong(idx, v))
val long: Binders[Long] = javaLong.xmap(throwExceptionIfNull(_.longValue), java.lang.Long.valueOf)
val optionLong: Binders[Option[Long]] = javaLong.xmap(wrapCastOption[Long, java.lang.Long], unwrapCastOption[Long, java.lang.Long])
val javaFloat: Binders[java.lang.Float] = Binders.of[java.lang.Float] {
case null => null
case v => java.lang.Float.valueOf(v.toString)
}(v => (ps, idx) => ps.setFloat(idx, v))
val float: Binders[Float] = javaFloat.xmap(throwExceptionIfNull(_.floatValue), java.lang.Float.valueOf)
val optionFloat: Binders[Option[Float]] = javaFloat.xmap(wrapCastOption[Float, java.lang.Float], unwrapCastOption[Float, java.lang.Float])
val javaDouble: Binders[java.lang.Double] = Binders.of[java.lang.Double] {
case null => null
case v => java.lang.Double.valueOf(v.toString)
}(v => (ps, idx) => ps.setDouble(idx, v))
val double: Binders[Double] = javaDouble.xmap(throwExceptionIfNull(_.doubleValue), java.lang.Double.valueOf)
val optionDouble: Binders[Option[Double]] = javaDouble.xmap(wrapCastOption[Double, java.lang.Double], unwrapCastOption[Double, java.lang.Double])
val javaByte: Binders[java.lang.Byte] = Binders.of[java.lang.Byte] {
case null => null
case v => java.lang.Byte.valueOf(v.toString)
}(v => (ps, idx) => ps.setByte(idx, v))
val byte: Binders[Byte] = javaByte.xmap(throwExceptionIfNull(_.byteValue), java.lang.Byte.valueOf)
val optionByte: Binders[Option[Byte]] = javaByte.xmap(wrapCastOption[Byte, java.lang.Byte], unwrapCastOption[Byte, java.lang.Byte])
val string: Binders[String] = Binders(_ getString _)(_ getString _)(v => (ps, idx) => ps.setString(idx, v))
val sqlArray: Binders[java.sql.Array] = Binders(_ getArray _)(_ getArray _)(v => (ps, idx) => ps.setArray(idx, v))
val javaBigDecimal: Binders[java.math.BigDecimal] = Binders(_ getBigDecimal _)(_ getBigDecimal _)(v => (ps, idx) => ps.setBigDecimal(idx, v))
val bigDecimal: Binders[BigDecimal] = javaBigDecimal.xmap(nullThrough(BigDecimal.apply), _.bigDecimal)
val javaBigInteger: Binders[java.math.BigInteger] = javaBigDecimal.xmap(nullThrough(_.toBigInteger), new java.math.BigDecimal(_))
val bigInt: Binders[BigInt] = javaBigInteger.xmap(nullThrough(BigInt.apply), _.bigInteger)
val sqlDate: Binders[java.sql.Date] = Binders(_ getDate _)(_ getDate _)(v => (ps, idx) => ps.setDate(idx, v))
val sqlXml: Binders[java.sql.SQLXML] = Binders(_ getSQLXML _)(_ getSQLXML _)(v => (ps, idx) => ps.setSQLXML(idx, v))
val sqlTime: Binders[java.sql.Time] = Binders(_ getTime _)(_ getTime _)(v => (ps, idx) => ps.setTime(idx, v))
val sqlTimestamp: Binders[java.sql.Timestamp] = Binders(_ getTimestamp _)(_ getTimestamp _)(v => (ps, idx) => ps.setTimestamp(idx, v))
val url: Binders[java.net.URL] = Binders(_ getURL _)(_ getURL _)(v => (ps, idx) => ps.setURL(idx, v))
val utilDate: Binders[java.util.Date] = sqlTimestamp.xmap(identity, _.toSqlTimestamp)
val javaTimeInstant: Binders[java.time.Instant] = sqlTimestamp.xmap(nullThrough(_.toInstant), java.sql.Timestamp.from)
val javaTimeZonedDateTime: Binders[java.time.ZonedDateTime] =
sqlTimestamp.xmap(convertJavaTimeZonedDateTime(java.time.ZoneId.systemDefault()), v => java.sql.Timestamp.from(v.toInstant))
val javaTimeOffsetDateTime: Binders[java.time.OffsetDateTime] =
sqlTimestamp.xmap(convertJavaTimeOffsetDateTime(java.time.ZoneId.systemDefault()), v => java.sql.Timestamp.from(v.toInstant))
val javaTimeLocalDateTime: Binders[java.time.LocalDateTime] =
sqlTimestamp.xmap(convertJavaTimeLocalDateTime(java.time.ZoneId.systemDefault()), v => java.sql.Timestamp.from(v.atZone(java.time.ZoneId.systemDefault()).toInstant))
val javaTimeLocalDate: Binders[java.time.LocalDate] = sqlDate.xmap(nullThrough(_.toLocalDate), java.sql.Date.valueOf)
val javaTimeLocalTime: Binders[java.time.LocalTime] = sqlTime.xmap(nullThrough(v => {
// java.sql.Time#toLocalTime drops its millisecond value
val millis: Long = v.getTime
new java.util.Date(millis).toLocalTime
}), java.sql.Time.valueOf)
val binaryStream: Binders[InputStream] = Binders(_ getBinaryStream _)(_ getBinaryStream _)(v => (ps, idx) => ps.setBinaryStream(idx, v))
val blob: Binders[java.sql.Blob] = Binders(_ getBlob _)(_ getBlob _)(v => (ps, idx) => ps.setBlob(idx, v))
val clob: Binders[java.sql.Clob] = Binders(_ getClob _)(_ getClob _)(v => (ps, idx) => ps.setClob(idx, v))
val nClob: Binders[java.sql.NClob] = Binders(_ getNClob _)(_ getNClob _)(v => (ps, idx) => ps.setNClob(idx, v))
val ref: Binders[java.sql.Ref] = Binders(_ getRef _)(_ getRef _)(v => (ps, idx) => ps.setRef(idx, v))
val rowId: Binders[java.sql.RowId] = Binders(_ getRowId _)(_ getRowId _)(v => (ps, idx) => ps.setRowId(idx, v))
val bytes: Binders[Array[Byte]] = Binders(_ getBytes _)(_ getBytes _)(v => (ps, idx) => ps.setBytes(idx, v))
val characterStream: Binders[java.io.Reader] = Binders(_ getCharacterStream _)(_ getCharacterStream _)(v => (ps, idx) => ps.setCharacterStream(idx, v))
val javaUtilCalendar: Binders[java.util.Calendar] = utilDate.xmap(nullThrough { v =>
val c = java.util.Calendar.getInstance
c.setTime(v)
c
}, _.getTime)
val asciiStream: Binders[java.io.InputStream] = Binders(_ getAsciiStream _)(_ getAsciiStream _)(v => (ps, idx) => ps.setAsciiStream(idx, v))
val nCharacterStream: Binders[java.io.Reader] = Binders(_ getNCharacterStream _)(_ getNCharacterStream _)(v => (ps, idx) => ps.setNCharacterStream(idx, v))
val nString: Binders[String] = Binders(_ getNString _)(_ getNString _)(v => (ps, idx) => ps.setNString(idx, v))
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy