Most examples are using await and that is blocking. Why use Slick if you are going to block? Look at onComplete, onSuccess, onFailure, and promise.
** Chaining transactions looks like this in one case
** Chaining transactions looks like this in one case
db.run{ (for {
customer <- customerTable.save();
address <- a
ddressTable
.save()
} yield ()).transactionally
}
** Returning a list of ids from a select looks like this
(but you can also use returning keyword)
db = Database.forConfig("myactors.database") session = db createSession;session.conn.setCatalog("mydb") session.conn.setSchema("myschema") val query = Tables.rawStringTest.to[List].map(_.id) val resultSet = db.run(query.result)
**this prints the list
resultSet.onComplete(res => println(s"string returns $res") )
**this waits for the future to return and uses the success/failure traits
resultSet.onComplete{ case Success(res) => res.foreach(x => db.run(Tables.rawStringTest.filter(_.id === x).delete)) case Failure(ex) => println(s"error $ex") }
**Testing is a challenge for aysync operations. Using an eventually retry block or a continuation both work. This is with eventually.
it("ids are generated when None is passed in table calls"){ val pk = None val validation = Tables.rawStringMessages.map(_.message_data) sut.insertStringMsg(None, "this is a fancy message", mockSuccessFunction(waiter), mockFailureFunction(waiter)) sut.insertStringMsg(None, "this is another fancy message", mockSuccessFunction(waiter), mockFailureFunction(waiter)) eventually(timeout(duration)) { val resultSet = Await.result(db.run(validation.result), duration)resultSet.onComplete{case Success(res) => resultSet.head.equals(99) shouldBe truecase Failure(ex) => fail(s"this failed $ex)
}
**Some ways to insert
table returning table forceInsert JsonMessage(receiptId, messageData, None)table returning table insertOrUpdate JsonMessage(receiptId, messageData, None) table returning table += JsonMessageInsert(receiptId, messageData)
**And any of these can return nothing
table += JsonMessageInsert(receiptId, messageData)table insertOrUpdate JsonMessage(receiptId, messageData, None)
/** * `Await` is what is used to ensure proper handling of blocking for `Awaitable` instances. * * While occasionally useful, e.g. for testing, it is recommended that you avoid Await * when possible in favor of callbacks and combinators like onComplete and use in * for comprehensions. Await will block the thread on which it runs, and could cause * performance and deadlock issues. */
Clean up is a chore as well for integration tests. In this case I did clean up in the AfterAll block to avoid cleaning data during concurrent test runs.
override def afterAll() { db = Database.forConfig("rtisystem.database") session = db createSession; session.conn.setCatalog("rti") session.conn.setSchema("rti") val query = Tables.rawStringMessages.to[List].map(_.id) val resultSet = db.run(query.result) resultSet.onComplete{ case Success(res) => res.foreach(x => db.run(Tables.rawStringMessages.filter(_.id === x).delete)) case Failure(ex) => println(s"error $ex") } val jquery = Tables.jsonMessages.to[List].map(_.id) val jresultSet = db.run(jquery.result) jresultSet.onComplete{ case Success(res) => res.foreach(x => db.run(Tables.jsonMessages.filter(_.id === x).delete)) case Failure(ex) => println(s"error $ex") }
This is an test example where I insert two records through a DAO extension method and compare them in a select query. it("generates ids when None is passed instead of a long in the table call"){ val pk = None val msgList: List[String] = List("this is a fancy message", "this is a fancy message also") val read = Tables.rawStringMessages.filter(row => row.message_data inSet msgList).map(_.id) sut.insertStringMsg(None, msgList.head, mockSuccessFunction(waiter), mockFailureFunction(waiter)) sut.insertStringMsg(None, msgList.tail.head, mockSuccessFunction(waiter), mockFailureFunction(waiter)) eventually(timeout(duration)) { val resultSet = db.run(read.result) resultSet.onComplete { case Success(res) => assert(res.head != res.tail.head && res.head > 100000 && res.tail.head > 100000) case Failure(ex) => println(s"error $ex") } } }
val visitorId: Int = // whatever val locationCodes = List("loc1","loc2","loc3"...) // your query, with bind params. val q = for { v <- Visits if v.visitor is visitorId.bind if v.location_code inSetBind locationCodes } yield v // have a look at the generated query. println(q.selectStatement) // run the query q.list
*** To use a db default ***
O.AutoInc column_name.?
Column Option[Timestamp]
table += Class(id, data, Some(timestamp))
Or a detailed version
import slick.driver.PostgresDriver.api._ import slick.lifted._ import java.sql.{Date, Timestamp} /** A representation of the message decorated for Slick persistence * created_date should always be null on insert operations. * It is set at the database level to ensure time syncronicity * Id is the Twitter snowflake id. All columns NotNull unless declared as Option * */ class RawMessages(tag: Tag) extends Table[(String, Option[String], Timestamp)](tag, Some("rti"), "RawMessages") { def id = column[String]("id", O.PrimaryKey) def MessageString = column[Option[String]]("MessageString") def CreatedDate = column[Timestamp]("CreatedDate", O.SqlType("timestamp default now()")) def * = (id, MessageString, CreatedDate) }