Skip to content

Commit

Permalink
Add Encoders/Decoders for java.time._
Browse files Browse the repository at this point in the history
  • Loading branch information
mdedetrich committed Sep 29, 2019
1 parent 1eb40fa commit e4dabad
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ trait Decoders {

case class AsyncDecoder[T](sqlType: DecoderSqlType)(implicit decoder: BaseDecoder[T])
extends BaseDecoder[T] {
override def apply(index: Index, row: ResultRow) =
override def apply(index: Index, row: ResultRow): T =
decoder(index, row)
}

Expand All @@ -26,7 +26,7 @@ trait Decoders {
sqlType: DecoderSqlType
): Decoder[T] =
AsyncDecoder[T](sqlType)(new BaseDecoder[T] {
def apply(index: Index, row: ResultRow) = {
def apply(index: Index, row: ResultRow): T = {
row(index) match {
case value: T => value
case value if f.isDefinedAt(value) => f(value)
Expand All @@ -45,7 +45,7 @@ trait Decoders {
})

trait NumericDecoder[T] extends BaseDecoder[T] {
def apply(index: Index, row: ResultRow) =
def apply(index: Index, row: ResultRow): T =
row(index) match {
case v: Byte => decode(v)
case v: Short => decode(v)
Expand All @@ -63,7 +63,7 @@ trait Decoders {

implicit def optionDecoder[T](implicit d: Decoder[T]): Decoder[Option[T]] =
AsyncDecoder(d.sqlType)(new BaseDecoder[Option[T]] {
def apply(index: Index, row: ResultRow) = {
def apply(index: Index, row: ResultRow): Option[T] = {
row(index) match {
case null => None
case value => Some(d(index, row))
Expand Down Expand Up @@ -99,25 +99,25 @@ trait Decoders {

implicit val intDecoder: Decoder[Int] =
AsyncDecoder(SqlTypes.INTEGER)(new NumericDecoder[Int] {
def decode[U](v: U)(implicit n: Numeric[U]) =
def decode[U](v: U)(implicit n: Numeric[U]): Int =
n.toInt(v)
})

implicit val longDecoder: Decoder[Long] =
AsyncDecoder(SqlTypes.BIGINT)(new NumericDecoder[Long] {
def decode[U](v: U)(implicit n: Numeric[U]) =
def decode[U](v: U)(implicit n: Numeric[U]): Long =
n.toLong(v)
})

implicit val floatDecoder: Decoder[Float] =
AsyncDecoder(SqlTypes.FLOAT)(new NumericDecoder[Float] {
def decode[U](v: U)(implicit n: Numeric[U]) =
def decode[U](v: U)(implicit n: Numeric[U]): Float =
n.toFloat(v)
})

implicit val doubleDecoder: Decoder[Double] =
AsyncDecoder(SqlTypes.DOUBLE)(new NumericDecoder[Double] {
def decode[U](v: U)(implicit n: Numeric[U]) =
def decode[U](v: U)(implicit n: Numeric[U]): Double =
n.toDouble(v)
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ trait Encoders {

case class AsyncEncoder[T](sqlType: DecoderSqlType)(implicit encoder: BaseEncoder[T])
extends BaseEncoder[T] {
override def apply(index: Index, value: T, row: PrepareRow) =
override def apply(index: Index, value: T, row: PrepareRow): PrepareRow =
encoder.apply(index, value, row)
}

Expand All @@ -23,19 +23,19 @@ trait Encoders {

def encoder[T](f: T => Any, sqlType: DecoderSqlType): Encoder[T] =
AsyncEncoder[T](sqlType)(new BaseEncoder[T] {
def apply(index: Index, value: T, row: PrepareRow) =
def apply(index: Index, value: T, row: PrepareRow): PrepareRow =
row :+ f(value)
})

implicit def mappedEncoder[I, O](implicit mapped: MappedEncoding[I, O], e: Encoder[O]): Encoder[I] =
AsyncEncoder(e.sqlType)(new BaseEncoder[I] {
def apply(index: Index, value: I, row: PrepareRow) =
def apply(index: Index, value: I, row: PrepareRow): PrepareRow =
e(index, mapped.f(value), row)
})

implicit def optionEncoder[T](implicit d: Encoder[T]): Encoder[Option[T]] =
AsyncEncoder(d.sqlType)(new BaseEncoder[Option[T]] {
def apply(index: Index, value: Option[T], row: PrepareRow) = {
def apply(index: Index, value: Option[T], row: PrepareRow): PrepareRow = {
value match {
case None => nullEncoder(index, null, row)
case Some(v) => d(index, v, row)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package io.getquill.context.jdbc

import java.sql.Timestamp
import java.time.LocalDate
import java.time.{LocalDate, LocalDateTime, LocalTime, OffsetDateTime}
import java.util.Date
import java.sql.{ Date => SqlDate }
import java.math.{ BigDecimal => JBigDecimal }
import java.math.{BigDecimal => JBigDecimal}

import io.getquill.context.sql.encoding.ArrayEncoding
import io.getquill.util.Messages.fail
Expand All @@ -13,7 +12,7 @@ import scala.collection.generic.CanBuildFrom
import scala.reflect.ClassTag

trait ArrayDecoders extends ArrayEncoding {
self: JdbcContextBase[_, _] =>
self: JdbcContextBase[_, _] with PostgresDateTimeDecoders =>

implicit def arrayStringDecoder[Col <: Seq[String]](implicit bf: CanBuildFrom[Nothing, String, Col]): Decoder[Col] = arrayRawDecoder[String, Col]
implicit def arrayBigDecimalDecoder[Col <: Seq[BigDecimal]](implicit bf: CBF[BigDecimal, Col]): Decoder[Col] = arrayDecoder[JBigDecimal, BigDecimal, Col](BigDecimal.apply)
Expand All @@ -26,7 +25,10 @@ trait ArrayDecoders extends ArrayEncoding {
implicit def arrayDoubleDecoder[Col <: Seq[Double]](implicit bf: CBF[Double, Col]): Decoder[Col] = arrayRawDecoder[Double, Col]
implicit def arrayDateDecoder[Col <: Seq[Date]](implicit bf: CBF[Date, Col]): Decoder[Col] = arrayRawDecoder[Date, Col]
implicit def arrayTimestampDecoder[Col <: Seq[Timestamp]](implicit bf: CBF[Timestamp, Col]): Decoder[Col] = arrayRawDecoder[Timestamp, Col]
implicit def arrayLocalDateDecoder[Col <: Seq[LocalDate]](implicit bf: CBF[LocalDate, Col]): Decoder[Col] = arrayDecoder[SqlDate, LocalDate, Col](_.toLocalDate)
implicit def arrayLocalDateDecoder[Col <: Seq[LocalDate]](implicit bf: CBF[LocalDate, Col]): Decoder[Col] = arrayRawDecoder[LocalDate, Col]
implicit def arrayLocalTimeDecoder[Col <: Seq[LocalTime]](implicit bf: CBF[LocalTime, Col]): Decoder[Col] = arrayRawDecoder[LocalTime, Col]
implicit def arrayLocalDateTimeDecoder[Col <: Seq[LocalDateTime]](implicit bf: CBF[LocalDateTime, Col]): Decoder[Col] = arrayRawDecoder[LocalDateTime, Col]
implicit def arrayOffsetDateTimeDecoder[Col <: Seq[LocalDateTime]](implicit bf: CBF[OffsetDateTime, Col]): Decoder[Col] = arrayRawDecoder[OffsetDateTime, Col]

/**
* Generic encoder for JDBC arrays.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package io.getquill.context.jdbc

import java.sql.{ Timestamp, Date => SqlDate }
import java.sql.Types._
import java.time.LocalDate
import java.time.{ LocalDate, LocalDateTime, LocalTime, OffsetDateTime }
import java.util.Date

import io.getquill.context.sql.encoding.ArrayEncoding
Expand All @@ -23,7 +23,10 @@ trait ArrayEncoders extends ArrayEncoding {
implicit def arrayDoubleEncoder[Col <: Seq[Double]]: Encoder[Col] = arrayRawEncoder[Double, Col](DOUBLE)
implicit def arrayDateEncoder[Col <: Seq[Date]]: Encoder[Col] = arrayRawEncoder[Date, Col](TIMESTAMP)
implicit def arrayTimestampEncoder[Col <: Seq[Timestamp]]: Encoder[Col] = arrayRawEncoder[Timestamp, Col](TIMESTAMP)
implicit def arrayLocalDateEncoder[Col <: Seq[LocalDate]]: Encoder[Col] = arrayEncoder[LocalDate, Col](parseJdbcType(DATE), SqlDate.valueOf)
implicit def arrayLocalDateEncoder[Col <: Seq[LocalDate]]: Encoder[Col] = arrayRawEncoder[LocalDate, Col](parseJdbcType(OTHER))
implicit def arrayLocalTimeEncoder[Col <: Seq[LocalTime]]: Encoder[Col] = arrayRawEncoder[LocalTime, Col](parseJdbcType(OTHER))
implicit def arrayLocalDateTimeEncoder[Col <: Seq[LocalDateTime]]: Encoder[Col] = arrayRawEncoder[LocalDateTime, Col](parseJdbcType(OTHER))
implicit def arrayOffsetDateTimeEncoder[Col <: Seq[OffsetDateTime]]: Encoder[Col] = arrayRawEncoder[OffsetDateTime, Col](parseJdbcType(OTHER))

/**
* Generic encoder for JDBC arrays.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ trait PostgresJdbcContextBase[N <: NamingStrategy] extends JdbcContextBase[Postg
with BooleanObjectEncoding
with UUIDObjectEncoding
with ArrayDecoders
with ArrayEncoders {
with ArrayEncoders
with PostgresDateTimeDecoders
with PostgresDateTimeEncoders {

val idiom = PostgresDialect

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ trait Decoders {
type Decoder[T] = JdbcDecoder[T]

case class JdbcDecoder[T](decoder: BaseDecoder[T]) extends BaseDecoder[T] {
def apply(index: Index, row: ResultRow) =
def apply(index: Index, row: ResultRow): T =
decoder(index + 1, row)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ trait Encoders {

type Encoder[T] = JdbcEncoder[T]

protected val dateTimeZone = TimeZone.getDefault
protected val dateTimeZone: TimeZone = TimeZone.getDefault

case class JdbcEncoder[T](sqlType: Int, encoder: BaseEncoder[T]) extends BaseEncoder[T] {
override def apply(index: Index, value: T, row: PrepareRow) =
override def apply(index: Index, value: T, row: PrepareRow): PrepareRow =
encoder(index + 1, value, row)
}

Expand Down Expand Up @@ -60,4 +60,4 @@ trait Encoders {
implicit val localDateTimeEncoder: Encoder[LocalDateTime] =
encoder(Types.TIMESTAMP, (index, value, row) =>
row.setTimestamp(index, Timestamp.valueOf(value), Calendar.getInstance(dateTimeZone)))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.getquill.context.jdbc

import java.time.{ LocalDate, LocalDateTime, LocalTime, OffsetDateTime }

trait PostgresDateTimeDecoders {
self: JdbcContextBase[_, _] with Decoders =>
// Taken from https://jdbc.postgresql.org/documentation/head/8-date-time.html

override implicit val localDateDecoder: Decoder[LocalDate] =
decoder(
(index, row) =>
row.getObject(index, classOf[LocalDate])
)

implicit val localTimeDecoder: Decoder[LocalTime] =
decoder(
(index, row) =>
row.getObject(index, classOf[LocalTime])
)

override implicit val localDateTimeDecoder: Decoder[LocalDateTime] =
decoder(
(index, row) =>
row.getObject(index, classOf[LocalDateTime])
)

implicit val offsetDateTimeDecoder: Decoder[OffsetDateTime] =
decoder(
(index, row) =>
row.getObject(index, classOf[OffsetDateTime])
)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.getquill.context.jdbc

import java.time.{ LocalDate, LocalDateTime, LocalTime, OffsetDateTime }

trait PostgresDateTimeEncoders {
self: JdbcContextBase[_, _] with Encoders =>
// Taken from https://jdbc.postgresql.org/documentation/head/8-date-time.html

private[this] def objectEncoder[T]: Encoder[T] = encoder(
java.sql.Types.OTHER,
(index, value, row) => row.setObject(index, value)
)

override implicit val localDateEncoder: Encoder[LocalDate] = objectEncoder[LocalDate]
implicit val localTimeEncoder: Encoder[LocalTime] = objectEncoder[LocalTime]
override implicit val localDateTimeEncoder: Encoder[LocalDateTime] = objectEncoder[LocalDateTime]
implicit val offsetDateTimeEncoder: Encoder[OffsetDateTime] = objectEncoder[OffsetDateTime]
}

0 comments on commit e4dabad

Please sign in to comment.