Wrapper catching exceptions accured on db.run call - scala

In our project we always injecting dbConfigProvider: DatabaseConfigProvider in our bean objects and then doing database operations with db.run(some query), it returns Future. How can I write a logging wrapper for db.run which will print all sql exceptions.
Example:
class SomeBeanImpl #Inject()(dbConfigProvider: DatabaseConfigProvider) {
private val logger = Logger(getClass)
def someDBQuery() = {
db.run(some wrong sql query) // exception raised in future, I need to print it with logger
}
}
Note:
If I add .onFailure on each db.run call it will mess up my code very badly. That's why I need write this wrapper for all of db.run calls.
If I wrap db.run in some function with different signature, I must change it in many places, which is not the best option. How can I do it implicitly?

You don't need to explicitly create a new wrapper class, you can use the Pimp My Library pattern to create an implicit method which wraps the invocation of db.run and attaches a onFailure to the Future:
object MyExtensions {
class DbExtensions(db: Db) {
def runAndLog(query: String): Future[String] = {
val result = db.run(query)
result.onFailure {
case e => Logger.getLogger("x").error(s"Exception: $e")
}
result
}
}
implicit def dbExtention(db: Db): DbExtensions = new DbExtensions(db)
}
class Db {
def run(query: String): Future[String] = Future.successful("Hello")
}
object App extends Application {
import MyExtensions._
val db = new Db
db.runAndLog("hello")
}
For Scala 2.10 and above, this can be shortened significantly using Implicit Classes:
implicit class DbExtensions(val db: Db) {
def runAndLog(query: String): Future[String] = {
val result = db.run(query)
result.onFailure {
case e => Logger.getLogger("x").error(s"Exception: $e")
}
result
}
}
class Db {
def run(query: String): Future[String] = Future.successful("Hello")
}
object App extends Application {
val db = new Db
db.runAndLog("hello")
}
You can further make DbExtensions extend AnyVal for a performance optimization:
implicit class DbExtensions(val db: Db) extends AnyVal

Make a new class:
case class DBWrapper(db: DatabaseComponent) {
def run(query: String) = db.run(query).onFailure { case e => logger.error(e) }
}
And replace your db wherever you initialize it with DBWrapper(db).
You can make the conversions back and forth implicit too, although I would not recommend it in this case.

Related

Assign dynamically injected database name in Play Slick

I have the following Play Slick DAO class. Note that the database configuration is a constant control0001. The DAO has a function readUser that reads a user based on its user id:
class UsersDAO #Inject()(#NamedDatabase("control0001")
protected val dbConfigProvider: DatabaseConfigProvider)
extends HasDatabaseConfigProvider[JdbcProfile] {
import driver.api._
def readUser (userid: String) = {
val users = TableQuery[UserDB]
val action = users.filter(_.userid === userid).result
val future = db.run(action.asTry)
future.map{
case Success(s) =>
if (s.length>0)
Some(s(0))
else
None
case Failure(e) => throw new Exception ("Failure in readUser: " + e.getMessage)
}
}
}
Instead of having a constant in #NamedDatabase("control0001"), I need the database to be variable. In the application, I have multiple databases (control0001, control002 and so on) configured in application.conf. Depending on a variable value, I need to determine the database to be used in the DAO. All the databases are similar and have the same tables (the data in each database differs).
The following Play class calls the DAO function, but first it needs to determine the database name to be injected:
class TestSlick #Inject()(dao: UsersDAO) extends Controller {
def test(someCode: Int, userId: String) = Action { request =>
val databaseName = if (someCode == 1) "control0001" else "control0002"
// Run the method in UsersDAO accessing the database set by databaseName
val future = dao.readUser(userId)
future.map { result =>
result match {
case Some(user) => Ok(user.firstName)
case _ => Ok("user not found")
}
}
}
}
How can this be achieved in Play Slick?
You can try to initialize slick db object overriding default config:
val db = Database.forURL("jdbc:mysql://localhost/" + databaseName, driver="org.h2.Driver")
more information in slick docs http://slick.lightbend.com/doc/3.0.0/database.html
Instead of trying to use Play's runtime dependency injection utilities in this case, use the SlickApi directly in your DAO and pass the datasource name to the dbConfig(DbName(name)) method. To obtain the SlickApi, mix in the SlickComponents trait:
class UsersDAO extends SlickComponents {
def readUser(userid: String, dbName: String) = {
val users = TableQuery[UserDB]
val action = users.filter(_.userid === userid).result
val dbConfig = slickApi.dbConfig(DbName(dbName))
val future = dbConfig.db.run(action.asTry)
...
}
}
Then in your controller:
def test(someCode: Int, userId: String) = Action { request =>
val databaseName = if (someCode == 1) "control0001" else "control0002"
val future = dao.readUser(userId, databaseName)
...
}

Scala What is this "_1" in type?

I would like to understand this error:
found : row.type (with underlying type _#TableElementType)
required: _1#TableElementType
Looks like I was very close, but what is this "1" in _1#TableElementType? Can I convert one in the other?
Edit: useful bits of codes for context (Play + Slick):
abstract class GenericDAO[T <: AbstractTable[_]](...) {
def table: TableQuery[T]
def insert(model: T#TableElementType) = db run (table += model)
}
trait TableObject[T <: AbstractTable[_]] {
def rowFromJson(jsObject: JsObject): T#TableElementType
def dao(driver: JdbcProfile, db: Database): GenericDAO[T]
}
// Controller Action with an instance implementing `tableObject` above:
val tableObject = tableObjectFactory("test")
val row = tableObject.rowFromJson(request.body.asJson.get)
val dao = tableObject.dao(driver, db) // tableObject has a DOA extending GenericDAO
dao.insert(row)
Example of tableObject:
object TestTable extends TableObject[Test] {
def dao(driver: JdbcProfile, db: Database) = new TestDAO(driver, db)
def rowFromJson(j: JsObject): TestRow = { TestRow(...) }
class TestDAO(...) extends GenericDAO[Test](driver, db) { ... }
}
I use a factory to get the right one from the url:
object TableObjectFactory {
def tableObjectFactory(name: String) = {
name match {
case "test" => TestTable
case "projects" => ProjectsTable
case "people" => PeopleTable
...
}
}
}
Although it doesn't explain much, it works if I make the DAO parse the request body and insert, instead of producing the row object separately and applying one of the DAO's methods on it.
I got all kinds of similar errors with names such as _$1#TableElementType, _1$u#TableElementType etc., but I think they are compiler aliases for different instances of the same class.
So the solution was to do
val j: JsValue = request.body.asJson.get
val tableObject: TableObject[_] = tableObjectFactory(table)
val dao = tableObject.dao(driver, db)
val res: Future[Int] = dao.insert(j)
where this new insert method now is abstract in GenericDAO, and in the concrete implementations takes a JsValue and parses it, then inserts:
class TestDAO(override val driver: JdbcProfile, override val db: Database) extends GenericDAO[Test](driver, db) {
import this.driver.api._
val table = TableQuery[Test]
//def insert(model: TestRow) = db run (table += model) // NO!
def insert(j: JsValue): Future[Int] = {
val row = TestRow(
(j \ "id").as[Int],
(j \ "name").as[String],
(j \ "value").as[Float],
(j \ "other").as[String]
)
db run (table += row)
}
}
At the same time, it makes Play forms completely useless, which is a good thing anyway.

Async before and after for creating and dropping scala slick tables in scalatest

I'm trying to figure out a way to have async before and after statements where the next test cases aren't run until the completion of the action inside of the test case. In my case, it is the creating and dropping a table inside of a database
val table = TableQuery[BlockHeaderTable]
val dbConfig: DatabaseConfig[PostgresDriver] = DatabaseConfig.forConfig("databaseUrl")
val database: Database = dbConfig.db
before {
//Awaits need to be used to make sure this is fully executed before the next test case starts
//TODO: Figure out a way to make this asynchronous
Await.result(database.run(table.schema.create), 10.seconds)
}
"BlockHeaderDAO" must "store a blockheader in the database, then read it from the database" in {
//...
}
it must "delete a block header in the database" in {
//...
}
after {
//Awaits need to be used to make sure this is fully executed before the next test case starts
//TODO: Figure out a way to make this asynchronous
Await.result(database.run(table.schema.drop),10.seconds)
}
Is there a simple way I can remove these Await calls inside of my before and after functions?
Unfortunately, #Jeffrey Chung's solution hanged for me (since futureValue actually awaits internally). This is what I ended up doing:
import org.scalatest.{AsyncFreeSpec, FutureOutcome}
import scala.concurrent.Future
class TestTest extends AsyncFreeSpec /* Could be any AsyncSpec. */ {
// Do whatever setup you need here.
def setup(): Future[_] = ???
// Cleanup whatever you need here.
def tearDown(): Future[_] = ???
override def withFixture(test: NoArgAsyncTest) = new FutureOutcome(for {
_ <- setup()
result <- super.withFixture(test).toFuture
_ <- tearDown()
} yield result)
}
The following is the testing approach that Dennis Vriend takes in his slick-3.2.0-test project.
First, define a dropCreateSchema method. This method attempts to create a table; if that attempt fails (because, for example, the table already exists), it drops, then creates, the table:
def dropCreateSchema: Future[Unit] = {
val schema = BlockHeaderTable.schema
db.run(schema.create)
.recoverWith {
case t: Throwable =>
db.run(DBIO.seq(schema.drop, schema.create))
}
}
Second, define a createEntries method that populates the table with some sample data for use in each test case:
def createEntries: Future[Unit] = {
val setup = DBIO.seq(
// insert some rows
BlockHeaderTable ++= Seq(
BlockHeaderTableRow(/* ... */),
// ...
)
).transactionally
db.run(setup)
}
Third, define an initialize method that calls the above two methods sequentially:
def initialize: Future[Unit] = for {
_ <- dropCreateSchema
_ <- createEntries
} yield ()
In the test class, mix in the ScalaFutures trait. For example:
class TestSpec extends FlatSpec
with Matchers
with ScalaFutures
with BeforeAndAfterAll
with BeforeAndAfterEach {
// ...
}
Also in the test class, define an implicit conversion from a Future to a Try, and override the beforeEach method to call initialize:
implicit val timeout: Timeout = 10.seconds
implicit class PimpedFuture[T](self: Future[T]) {
def toTry: Try[T] = Try(self.futureValue)
}
override protected def beforeEach(): Unit = {
blockHeaderRepo.initialize // in this example, initialize is defined in a repo class
.toTry recover {
case t: Throwable =>
log.error("Could not initialize the database", t)
} should be a 'success
}
override protected def afterAll(): Unit = {
db.close()
}
With the above pieces in place, there is no need for Await.
You can simplify #Jeffrey Chung
A simplified dropCreateSchema method:
def dropCreateSchema: Future[Unit] = {
val schema = users.schema
db.run(DBIO.seq(schema.dropIfExists, schema.create))
}
Also in the test class, I simplified beforeEach method that calls initialize. I removed an implicit conversion from a Future to a Try, and use onComplete callback:
override protected def beforeEach(): Unit = {
initialize.onComplete(f =>
f recover {
case t: Throwable =>
log.error("Could not initialize the database", t)
} should be a 'success)
}
override protected def afterAll(): Unit = {
db.close()
}

Is it possible to implement (without macros) an implicit zip/unzip in Scala to achieve a sneaky fluent or lazy pattern?

Edit2
Okay, so maybe I should parse out two desires here.
I had in mind that when it came time to get to the setSendTimeout(0) part, I would be using something like implicitly[Socket].
new ZContext(1) {
createSocket(ZMQ.PUB).setSendTimeout(0).//RATS!
}
I also had in mind a more generic approach to it, that would be (in pseudo code terms):
This is how you wrap a reference of T at a point in time without copying it, so that moving forward, you can tease out state of the reference after potential state changes from the value of whatever expression used it.
If it could be thought of as a chain of map map map s from T to where ever it ended up, then it is easy to append / apply a value onto it - just map again...
This is the motivating example.
override def createLogic(inheritedAttributes: Attributes): GraphStageLogic = new GraphStageLogic(shape) {
logger.info("Initializing ZMQ context.")
val context = new ZContext(1)
logger.info(s"Binding PUB socket to ${endpoint}")
val socket = {
val s = context.createSocket(ZMQ.PUB)
s.setSendTimeOut(0)
s.bind(endpoint)
s
}
Look at socket down there. For some reason that feels uglier than it needs to be to me, but is a consequence of the fact that setters don't return stuff like setSendTimeOut.
I would normally try to improve it as follows:
new ZContext(1) {
createSocket(ZMQ.PUB).setSendTimeout(0).//RATS!
}
Here a version of #Dima's answer. Again the setup:
trait Instance {
def createPort(): Port
}
trait Port {
def makeSpecial(): Unit
def bindTo(address: Any): Unit
}
trait Provider {
def getTheInstance(i: Int): Instance
}
Now the trick:
implicit class InstanceOps(i: Instance) {
def withCreatePort(fun: (Unit => Port) => Any): Port = {
val res = i.createPort()
fun(_ => res)
res
}
}
And if you add an implicit modifier to the argument of the function passed into withCreatePort, you "import" the implicit conversion:
trait ConnectTest extends Provider {
getTheInstance(2).withCreatePort { implicit p =>
().makeSpecial().bindTo("foo")
}
}
This is potentially more dangerous, because you have an implicit conversion from Unit to Port, although it is locally encapsulated. This is generic because Connect is generic.
This trick is perhaps too clever and difficult to understand by some outside standing person reading your code.
Yes, you can create two wrappers, one giving you withCreatePort, the other giving you variants of the port method that return this:
trait Instance {
def createPort(): Port
}
trait Port {
def makeSpecial(): Unit
def bindTo(address: Any): Unit
}
class PortOps(p: Port) {
def makeSpecial() : this.type = { p.makeSpecial() ; this }
def bindTo(address: Any): this.type = { p.bindTo(address); this }
}
implicit class InstanceOps(i: Instance) {
def withCreatePort[A](fun: PortOps => A): A = fun(new PortOps(i.createPort()))
}
Example:
trait Provider {
def getTheInstance(i: Int): Instance
}
trait Plain extends Provider {
val instance = getTheInstance(2)
val port = instance.createPort()
port.makeSpecial()
port.bindTo("foo")
}
trait Rich extends Provider {
getTheInstance(2).withCreatePort { p =>
p.makeSpecial().bindTo("foo")
}
}
The question is if the effort is worth it. You can also experiment with import:
trait Import extends Provider {
val instance = getTheInstance(2)
val port = instance.createPort()
locally {
import port._
makeSpecial(); bindTo("foo")
}
}
I am not sure where you are going with this Zipped thingy ... But what you described in the beginning of your question (assuming that port in the end of that snippet is a typo, and you really meant to return instance) can be done with something like this:
object Taps {
implicit class Tap[T](t: T) extends Anyval {
def tap(f: T => Unit) = { f(t); t }
}
}
Then you can write:
import Taps._
val instance = getTheInstance(2).tap {
_.createPort
.makeSpecial
.bindTo(...)
}
Is this what you are looking for?

making an implicit available within a play action

My app hits many different dbs, which db depends on a query string parameter. I have a DatabaseConfigLocator that takes the string and returns the config and it works great. My problem is I want to make the config for each request available implicitly in my controller. I have tried two approaches.
class MyController extends Controller{
implicit def dbConfig(implicit request: RequestHeader): DatabaseConfig[JdbcProfile] = DatabaseConfigLocator.get[JdbcProfile](request.getQueryString("dbName")
}
This dosn't compile unless I change it to an implicit val with the same type but I need to recheck the query string every request not just once so I don't think an implicit val will work
The other approach was to create an action
object IODBAction extends ActionBuilder[Request]{
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
implicit def dbConfig(implicit request: RequestHeader): DatabaseConfig[JdbcProfile] = DatabaseConfigLocator.get[JdbcProfile]("blah")
block(request)
}
}
but that implicit is not available in the scope of the block and I cant find any way to pass it in as an implicit.
My goal is to be able to do something like this
class MyController extends Controller {
def create = {
Action.async {
request =>
ApiResponse {
for {
id <- aProvider.save(validRegistrationRequest.toVisitor)
} yield id
}
}
}
}
class aProvider {
def save(v: Visitor)(implicit dbConfig: DatabaseConfig[JdbcProfile]): ApiResponse[VisitorId]
}
or if the provider can get the implicit at instantiation time all the better
class aProvider(implicit dbConfig: DatabaseConfig[JdbcPRofile]) {
def save(v: Visitor): ApiResponse[VisitorId]
}
Any advice on how to approach this or if its possible with play framework?
Unfortunately, I fear you're stuck with an action receiving a single parameter, so you need to stick to the standard play "Action Composition" pattern. This is documented pretty extensively in the play docs.
I'd define yourself a a "Context" like this:
case class Context(dbConfig: DatabaseConfig[JDBCProfile], request: Request[A])
extends WrappedRequest(request)
Then create a custom action builder like this:
object DBIOAction extends ActionBuilder[Context]{
def invokeBlock[A](request: Request[A], block: (Context[A]) => Future[Result]) = {
val dbConfig = DatabaseConfigLocator.get[JdbcProfile]("blah")
val context = Context(dbConfig, request)
block(context)
}
}
You then should be able to use it like this:
def index = DBIOAction { implicit context =>
// do some stuff. return a result
}
In order to make things simple, I'd pass the implicit context into your service methods, perhaps extracting the dbConfig from the context and passing it the rest of the way down to your DAO's.
class FunService {
def getSomeData(param1: String)(implicit context: Context) = {
// do some work, perhaps using context.dbConfig
}