Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 38 additions & 4 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -201,12 +201,30 @@ lazy val `anorm-core` = project
coreMimaFilter,
// was deprecated
ProblemFilters.exclude[IncompatibleMethTypeProblem]("anorm.ColumnNotFound.copy"),
ProblemFilters.exclude[IncompatibleResultTypeProblem]("anorm.ColumnNotFound.copy$default$2")
ProblemFilters.exclude[IncompatibleResultTypeProblem]("anorm.ColumnNotFound.copy$default$2"),
// Joda-Time support moved to anorm-joda module
ProblemFilters.exclude[MissingClassProblem]("anorm.JodaColumn"),
ProblemFilters.exclude[MissingClassProblem]("anorm.JodaToStatement"),
ProblemFilters.exclude[MissingClassProblem]("anorm.JodaParameterMetaData"),
ProblemFilters.exclude[MissingClassProblem]("anorm.JodaParameterMetaData$"),
ProblemFilters.exclude[MissingClassProblem]("anorm.JodaParameterMetaData$JodaTimeMetaData"),
ProblemFilters.exclude[MissingClassProblem]("anorm.JodaParameterMetaData$JodaDateTimeMetaData$"),
ProblemFilters.exclude[MissingClassProblem]("anorm.JodaParameterMetaData$JodaLocalDateTimeMetaData$"),
ProblemFilters.exclude[MissingClassProblem]("anorm.JodaParameterMetaData$JodaInstantMetaData$"),
ProblemFilters.exclude[MissingClassProblem]("anorm.JodaParameterMetaData$JodaLocalDateMetaData$"),
ProblemFilters.exclude[MissingTypesProblem]("anorm.Column$"),
ProblemFilters.exclude[MissingTypesProblem]("anorm.ToStatement$"),
ProblemFilters.exclude[DirectMissingMethodProblem]("anorm.Column.columnToJodaLocalDate"),
ProblemFilters.exclude[DirectMissingMethodProblem]("anorm.Column.columnToJodaLocalDateTime"),
ProblemFilters.exclude[DirectMissingMethodProblem]("anorm.Column.columnToJodaDateTime"),
ProblemFilters.exclude[DirectMissingMethodProblem]("anorm.Column.columnToJodaInstant"),
ProblemFilters.exclude[DirectMissingMethodProblem]("anorm.ToStatement.jodaDateTimeToStatement"),
ProblemFilters.exclude[DirectMissingMethodProblem]("anorm.ToStatement.jodaLocalDateTimeToStatement"),
ProblemFilters.exclude[DirectMissingMethodProblem]("anorm.ToStatement.jodaLocalDateToStatement"),
ProblemFilters.exclude[DirectMissingMethodProblem]("anorm.ToStatement.jodaInstantToStatement")
),
libraryDependencies ++= {
Seq(
"joda-time" % "joda-time" % "2.14.2",
"org.joda" % "joda-convert" % "3.0.1",
"org.scala-lang.modules" %% "scala-parser-combinators" % parserCombinatorsVer.value,
"org.scala-lang.modules" %% "scala-xml" % xmlVer % Test,
"com.h2database" % "h2" % "2.3.230" % Test,
Expand Down Expand Up @@ -317,6 +335,21 @@ lazy val `anorm-enumeratum` = project
)
.dependsOn(`anorm-core`)

lazy val `anorm-joda` = project
.in(file("joda"))
.settings(
Seq(
mimaPreviousArtifacts := Set.empty,
libraryDependencies ++= Seq(
"joda-time" % "joda-time" % "2.14.2",
"org.joda" % "joda-convert" % "3.0.1",
"com.h2database" % "h2" % "2.3.230" % Test,
acolyte
) ++ specs2Test
) ++ licensing
)
.dependsOn(`anorm-core`)

// ---

lazy val `anorm-parent` = project
Expand All @@ -328,7 +361,8 @@ lazy val `anorm-parent` = project
`anorm-akka`,
`anorm-pekko`,
`anorm-postgres`,
`anorm-enumeratum`
`anorm-enumeratum`,
`anorm-joda`
)
.settings(
Seq(
Expand Down
118 changes: 1 addition & 117 deletions core/src/main/scala/anorm/Column.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ trait Column[A] extends ((Any, MetaDataItem) => Either[SqlRequestError, A]) { pa
}

/** Column companion, providing default conversions. */
object Column extends JodaColumn with JavaTimeColumn {
object Column extends JavaTimeColumn {

/**
* Resolves the `Column` instance for the given type.
Expand Down Expand Up @@ -643,122 +643,6 @@ object Column extends JodaColumn with JavaTimeColumn {
implicitly[ClassTag[InputStream]]
}

sealed trait JodaColumn {
import org.joda.time.{ DateTime, LocalDate, LocalDateTime, Instant }
import Column.{ nonNull, className, timestamp => Ts }

/**
* Parses column as Joda local date.
* Time zone is the one of default JVM time zone
* (see `org.joda.time.DateTimeZone.getDefault`).
*
* {{{
* import org.joda.time.LocalDate
* import anorm._, SqlParser.scalar
*
* def ld(implicit con: java.sql.Connection): LocalDate =
* SQL("SELECT last_mod FROM tbl").as(scalar[LocalDate].single)
* }}}
*/
implicit val columnToJodaLocalDate: Column[LocalDate] =
nonNull { (value, meta) =>
val MetaDataItem(qualified, _, _) = meta

value match {
case date: java.util.Date => Right(new LocalDate(date.getTime))
case time: Long => Right(new LocalDate(time))
case TimestampWrapper1(ts) => Ts(ts)(t => new LocalDate(t.getTime))
case TimestampWrapper2(ts) => Ts(ts)(t => new LocalDate(t.getTime))
case _ =>
Left(TypeDoesNotMatch(s"Cannot convert $value: ${className(value)} to Joda LocalDate for column $qualified"))
}
}

/**
* Parses column as Joda local date/time.
* Time zone is the one of default JVM time zone
* (see `org.joda.time.DateTimeZone.getDefault`).
*
* {{{
* import org.joda.time.LocalDateTime
* import anorm._, SqlParser._
*
* def ldt(implicit con: java.sql.Connection): LocalDateTime =
* SQL("SELECT last_mod FROM tbl").as(scalar[LocalDateTime].single)
* }}}
*/
implicit val columnToJodaLocalDateTime: Column[LocalDateTime] =
nonNull { (value, meta) =>
val MetaDataItem(qualified, _, _) = meta

value match {
case date: java.util.Date => Right(new LocalDateTime(date.getTime))
case time: Long => Right(new LocalDateTime(time))
case TimestampWrapper1(ts) => Ts(ts)(t => new LocalDateTime(t.getTime))
case TimestampWrapper2(ts) => Ts(ts)(t => new LocalDateTime(t.getTime))
case _ =>
Left(
TypeDoesNotMatch(s"Cannot convert $value: ${className(value)} to Joda LocalDateTime for column $qualified")
)
}
}

/**
* Parses column as joda DateTime
*
* {{{
* import org.joda.time.DateTime
* import anorm._, SqlParser._
*
* def dt(implicit con: java.sql.Connection): DateTime =
* SQL("SELECT last_mod FROM tbl").as(scalar[DateTime].single)
* }}}
*/
implicit val columnToJodaDateTime: Column[DateTime] =
nonNull { (value, meta) =>
val MetaDataItem(qualified, _, _) = meta

@SuppressWarnings(Array("AsInstanceOf"))
def unsafe = value match {
case date: Date => Right(new DateTime(date.getTime))
case time: Long => Right(new DateTime(time))
case TimestampWrapper1(ts) =>
Option(ts).fold(Right(null.asInstanceOf[DateTime]))(t => Right(new DateTime(t.getTime)))

case TimestampWrapper2(ts) =>
Option(ts).fold(Right(null.asInstanceOf[DateTime]))(t => Right(new DateTime(t.getTime)))

case _ =>
Left(TypeDoesNotMatch(s"Cannot convert $value: ${className(value)} to DateTime for column $qualified"))
}

unsafe
}

/**
* Parses column as joda Instant
*
* {{{
* import anorm._, SqlParser.scalar
* import org.joda.time.Instant
*
* def d(implicit con: java.sql.Connection): Instant =
* SQL("SELECT last_mod FROM tbl").as(scalar[Instant].single)
* }}}
*/
implicit val columnToJodaInstant: Column[Instant] =
nonNull { (value, meta) =>
val MetaDataItem(qualified, _, _) = meta
value match {
case date: Date => Right(new Instant(date.getTime))
case time: Long => Right(new Instant(time))
case TimestampWrapper1(ts) => Ts(ts)(t => new Instant(t.getTime))
case TimestampWrapper2(ts) => Ts(ts)(t => new Instant(t.getTime))
case _ => Left(TypeDoesNotMatch(s"Cannot convert $value: ${className(value)} to Instant for column $qualified"))
}
}
}

sealed trait JavaTimeColumn {
import java.time.{ ZonedDateTime, ZoneOffset, ZoneId, LocalDate, LocalDateTime, Instant }
import Column.{ nonNull, className, timestamp => Ts }
Expand Down
75 changes: 1 addition & 74 deletions core/src/main/scala/anorm/ToStatementMisc.scala
Original file line number Diff line number Diff line change
Expand Up @@ -723,79 +723,6 @@ sealed trait ToStatementPriority0 {
}
}

/** Meta data for Joda parameters */
object JodaParameterMetaData {
import org.joda.time.{ DateTime, LocalDate, LocalDateTime, Instant }

import java.sql.Types

sealed trait JodaTimeMetaData {
val sqlType = "TIMESTAMP"
val jdbcType = Types.TIMESTAMP
}

/** Date/time parameter meta data */
implicit object JodaDateTimeMetaData extends ParameterMetaData[DateTime] with JodaTimeMetaData

/** Local date/time parameter meta data */
implicit object JodaLocalDateTimeMetaData extends ParameterMetaData[LocalDateTime] with JodaTimeMetaData

/** Instant parameter meta data */
implicit object JodaInstantMetaData extends ParameterMetaData[Instant] with JodaTimeMetaData

/** Local date parameter meta data */
implicit object JodaLocalDateMetaData extends ParameterMetaData[LocalDate] with JodaTimeMetaData
}

sealed trait JodaToStatement {
import org.joda.time.{ DateTime, LocalDate, LocalDateTime, Instant }

/**
* Sets joda-time DateTime as statement parameter.
* For `null` value, `setNull` with `TIMESTAMP` is called on statement.
*/
implicit def jodaDateTimeToStatement(implicit meta: ParameterMetaData[DateTime]): ToStatement[DateTime] =
new ToStatement[DateTime] {
def set(s: PreparedStatement, index: Int, date: DateTime): Unit =
if (date != (null: DateTime)) {
s.setTimestamp(index, new Timestamp(date.getMillis()))
} else s.setNull(index, meta.jdbcType)
}

/**
* Sets a local date/time on statement.
*/
implicit def jodaLocalDateTimeToStatement(implicit
meta: ParameterMetaData[LocalDateTime]
): ToStatement[LocalDateTime] = new ToStatement[LocalDateTime] {
def set(s: PreparedStatement, i: Int, t: LocalDateTime): Unit =
if (t == (null: LocalDateTime)) s.setNull(i, meta.jdbcType)
else s.setTimestamp(i, new Timestamp(t.toDateTime.getMillis))
}

/**
* Sets a local date on statement.
*/
implicit def jodaLocalDateToStatement(implicit meta: ParameterMetaData[LocalDate]): ToStatement[LocalDate] =
new ToStatement[LocalDate] {
def set(s: PreparedStatement, i: Int, t: LocalDate): Unit =
if (t == (null: LocalDate)) s.setNull(i, meta.jdbcType)
else s.setTimestamp(i, new Timestamp(t.toDate.getTime))
}

/**
* Sets joda-time Instant as statement parameter.
* For `null` value, `setNull` with `TIMESTAMP` is called on statement.
*/
implicit def jodaInstantToStatement(implicit meta: ParameterMetaData[Instant]): ToStatement[Instant] =
new ToStatement[Instant] {
def set(s: PreparedStatement, index: Int, instant: Instant): Unit =
if (instant != (null: Instant)) {
s.setTimestamp(index, new Timestamp(instant.getMillis))
} else s.setNull(index, meta.jdbcType)
}
}

sealed trait JavaTimeToStatement {
import java.time.{ Instant, LocalDate, LocalDateTime, ZonedDateTime }

Expand Down Expand Up @@ -894,7 +821,7 @@ sealed trait ToStatementPriority1 extends ToStatementPriority0 {
/**
* Provided conversions to set statement parameter.
*/
private[anorm] class ToStatementConversions extends ToStatementPriority1 with JodaToStatement with JavaTimeToStatement {
private[anorm] class ToStatementConversions extends ToStatementPriority1 with JavaTimeToStatement {

/**
* Resolves `ToStatement` instance for the given type.
Expand Down
Loading
Loading