5
votes

I have a JOURNAL table where the INSERT_DATE column should be filled by the DB with the current date and time when the record is inserted. I did not use the TIMESTAMP type on purpose, because of its limited range.

class Journal(tag: Tag) extends Table[JournalEntry](tag, "JOURNAL") { 
   def id = column[Int]("ID", O.PrimaryKey, O.AutoInc)
   def insertDate = column[OffsetDateTime]("INSERT_DATE", SqlType("DateTime default CURRENT_TIMESTAMP"))(localDateTimeColumnType)
   def valueDate = column[OffsetDateTime]("VALUE_DATE", SqlType("DateTime"))(localDateTimeColumnType)
   def amount = column[Int]("AMOUNT")
   def note = column[String]("NOTE", O.Length(100))

   def * : ProvenShape[JournalEntry] = (id.?, insertDate.?, valueDate, amount, note) 
     <> ((JournalEntry.apply _).tupled, JournalEntry.unapply)
}

I also implement a case class:

case class JournalEntry(id: Option[Int], insertDate: Option[LocalDateTime], 
  valueDate: LocalDateTime, amount: Int, note: String)

When my app starts up, I populate the DB with random test data:

TableQuery[Journal] ++= Seq.fill(1000)(JournalEntry(None, Some(LocalDateTime.now()), 
   LocalDateTime.of(2006 + Random.nextInt(10), 1 + Random.nextInt(11), 
   1 + Random.nextInt(27),Random.nextInt(24), Random.nextInt(60)), Random.nextInt(),
   TestDatabase.randomString(100)))

This works, but the INSERT_DATE ist set by the JVM not by the Database. The Slick docs say that columns should be omitted, if one wants the default value to get inserted. But I just dont get how I omit columns if I have a case class.

I also found this SO post but could not figure out how to use it in my context.

Any ideas?

2

2 Answers

2
votes

The Slick docs give an example of such omission right in the first code snippet here. Follow the steps or the cvogt's answer and you will arrive at the solution:

TableQuery[Journal].map(je => (je.id, je.valueDate, je.amount, je.note)) ++= Seq.fill(1000)((None, LocalDateTime.of(2006 + Random.nextInt(10), 1 + Random.nextInt(11), 1 + Random.nextInt(27),Random.nextInt(24), Random.nextInt(60)), Random.nextInt(), TestDatabase.randomString(100)))

1
votes

I work in the following way:

import java.time.{ ZonedDateTime, ZoneOffset}
import slick.profile.SqlProfile.ColumnOption.SqlType
import scala.concurrent.duration.Duration
import scala.concurrent.Await

implicit val zonedDateTimeType = MappedColumnType.base[ZonedDateTime, Timestamp](
    {dt =>Timestamp.from(dt.toInstant)},
    {ts =>ZonedDateTime.ofInstant(ts.toInstant, ZoneOffset.UTC)}
)

class Users(tag: Tag) extends Table[(String, ZonedDateTime)](tag, "users") {
    def name = column[String]("name")
    def createAt = column[ZonedDateTime]("create_at", SqlType("timestamp not null default CURRENT_TIMESTAMP"))
    def * = (name, createAt)
}

val users = TableQuery[Users]
val setup = DBIO.seq(
    users.schema.create,
    users.map(u => (u.name)) ++= Seq(("Amy"), ("Bob"), ("Chris"), ("Dave"))
Await.result(db.run(setup), Duration.Inf)

I am not using case class here, just a tuple.