5

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?

Max Plevako
  • 1,832
  • 11
  • 11
binford
  • 1,655
  • 1
  • 18
  • 36

2 Answers2

2

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)))

Community
  • 1
  • 1
Max Plevako
  • 1,832
  • 11
  • 11
  • 1
    Does not work for me: `[error] Slick does not know how to map the given types. [error] Possible causes: T in Table[T] does not match your * projection. Or you use an unsupported type in a Query (e.g. scala List). [error] Required level: slick.lifted.FlatShapeLevel [error] Source type: (slick.lifted.Rep[Int], slick.lifted.Rep[java.time.LocalDateTime], slick.lifted.Rep[Int], slick.lifted.Rep[String]) [error] Unpacked type: T [error] Packed type: G [error] TableQuery[Journal].map(je => (je.id, je.valueDate, je.amount, je.note)) ++=` – binford Jul 08 '16 at 09:01
1

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.

user2829759
  • 3,372
  • 2
  • 29
  • 53