tminglei / slick-pg

Slick extensions for PostgreSQL
BSD 2-Clause "Simplified" License
838 stars 180 forks source link

DateTimeParseException for Instant #731

Open mwisnicki opened 1 month ago

mwisnicki commented 1 month ago

Add this test case:

        {
          val now = Instant.now()
          sql"""SELECT ${now}""".as[Instant].head.map {
            r =>
              r === now
          }
        },

to https://github.com/tminglei/slick-pg/blob/master/src/test/scala/com/github/tminglei/slickpg/PgDate2SupportSuite.scala#L434

And it will fail:

[info] - Java8 date Plain SQL support *** FAILED ***
[info]   java.time.format.DateTimeParseException: Text '2024-08-13T20:58:07.433589Z' could not be parsed at index 10
[info]   at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
[info]   at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
[info]   at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:492)
[info]   at com.github.tminglei.slickpg.PgDate2Support$Date2DateTimeFormatters.$anonfun$fromDateTimeOrInfinity$1(PgDate2Support.scala:72)
[info]   at com.github.tminglei.slickpg.PgDate2Support$Date2DateTimeFormatters.$anonfun$fromInfinitable$1(PgDate2Support.scala:67)
[info]   at scala.Function1.$anonfun$andThen$1(Function1.scala:87)
[info]   at com.github.tminglei.slickpg.PgDate2Support$Date2DateTimeFormatters.$anonfun$fromInfinitable$1(PgDate2Support.scala:67)
[info]   at scala.Option.map(Option.scala:242)
[info]   at com.github.tminglei.slickpg.PgDate2Support$Date2DateTimePlainImplicits$PgDate2TimePositionedResult.nextInstantOption(PgDate2Support.scala:205)
[info]   at com.github.tminglei.slickpg.PgDate2Support$Date2DateTimePlainImplicits$PgDate2TimePositionedResult.nextInstant(PgDate2Support.scala:204)
[info]   ...
export SLICK_PG_TEST_POSTGRES_IMAGE_TAG=14
sbt test
mwisnicki commented 1 month ago

BTW using instantType works pretty well:

import slick.jdbc.{GetResult, PositionedResult, PostgresProfile, SetParameter}

import java.time.Instant

trait PlainMappers {

  import PostgresProfile.columnTypes.instantType

  private def toInstant(unused: String, pr: PositionedResult) = instantType.getValue(pr.rs, pr.currentPos)

  implicit val getResultInstant: GetResult[Instant] = pr => toInstant(pr.nextString(), pr)
  implicit val getResultInstantOpt: GetResult[Option[Instant]] = pr => pr.nextStringOption().map(toInstant(_, pr))

  implicit val setParameterInstant: SetParameter[Instant] = (v, pp) => {
    val npos = pp.pos + 1
    instantType.setValue(v, pp.ps, npos)
    pp.pos = npos
  }
  implicit val setParameterInstantOption: SetParameter[Option[Instant]] = (v, pp) => {
    val npos = pp.pos + 1
    v match {
      case None => pp.ps.setNull(npos, java.sql.Types.TIMESTAMP)
      case Some(value) => instantType.setValue(value, pp.ps, npos)
    }
    pp.pos = npos
  }
}