Skip to content

Instantly share code, notes, and snippets.

class MyClass @Inject() (actor: ActorInstance[MyActor])
def updateValue(value: MyValue) = actor.ref ! Update(value)
}
class MyActor @Inject() (db: Database) extends Actor {
def receive() = {
case Update(value) => sender ! db.update(value)
...
}
}
@Singleton
class ActorInstance[T <: Actor] @Inject() (
systemProvider: Provider[ActorSystem], builder: ActorBuilder, provider: Provider[T]) {
lazy val ref: ActorRef = builder(systemProvider.get, provider)
}
@ImplementedBy(classOf[ActorBuilderImpl])
trait ActorBuilder {
def apply(system: ActorSystem, provider: Provider[_ <: Actor]): ActorRef
}
db.readOnly { implicit session =>
val conn = session.conn
val st = conn.createStatement()
...
val sql =
s"""
select CONCAT(something, "-", other_thing, "-", YEAR(created_at))
from some_table
where created_at >= ${db.dialect.day(startDate)} and
created_at < ${db.dialect.day(endDate)};
trait DatabaseDialect[T <: DataBaseComponent] {
def day(date: DateTime): String
}
object MySqlDatabaseDialect extends DatabaseDialect[MySQL] {
def day(date: DateTime): String =
s"""STR_TO_DATE('${date.toStandardDateString}', '%Y-%m-%d')"""
}
object H2DatabaseDialect extends DatabaseDialect[H2] {
db.readOnly { implicit s =>
// only reading from db - not in a transaction
}
db.readWrite { implicit s =>
// reading and writing to db in a transaction
}
db.readWrite(3) { implicit s =>
// reading and writing to db in a transaction with retries if a database
// exception is thrown (up to 3 attempts total) by rolling back the
// transaction, starting a new one, and re-executing the block.
abstract class SessionWrapper(_session: => Session) extends Session {
lazy val session = _session
def conn: Connection = session.conn
def metaData = session.metaData
def capabilities = session.capabilities
override def resultSetType = session.resultSetType
override def resultSetConcurrency = session.resultSetConcurrency
override def resultSetHoldability = session.resultSetHoldability
def close() { throw new UnsupportedOperationException }
// this allows us to replace the database session implementation in tests
// and check when sessions are being obtained
@ImplementedBy(classOf[SlickSessionProviderImpl])
trait SlickSessionProvider {
def createReadOnlySession(handle: SlickDatabase): Session
def createReadWriteSession(handle: SlickDatabase): Session
}
@Singleton
class SlickSessionProviderImpl extends SlickSessionProvider {
case class MyDbInfo() extends DbInfo {
def database = SlickDatabase.forDataSource(DB.getDataSource("shoebox")(Play.current))
def driverName = Play.current.configuration.getString("db.shoebox.driver").get
}
...
install(new SlickModule(new MyDbInfo()))
...
trait DbInfo {
def database: SlickDatabase
def driverName: String
}
class SlickModule(dbInfo: DbInfo) extends ScalaModule {
def configure(): Unit = {
//see http://stackoverflow.com/questions/6271435/guice-and-scala-injection-on-generics-dependencies
lazy val db = dbInfo.driverName match {
case MySQL.driverName => new MySQL(dbInfo.database)