2

I'm using anorm for play framework and I have the following service class:

@javax.inject.Singleton
class ProductService @Inject() (dbApi: DBApi) {

  private val DB = dbApi.database("default")

  def save(product: Product) = {
    DB.withConnection { implicit connection =>
      ....
    }
  }
}

Two issues here:

1) I do not wish to add the line private val DB = dbApi.database("default") in each Service class. What is the best way to abstract this?

2) I would also like to have the datasource configurable so that I can pass test datasource when writing Integration tests

Test class:

import models.ProductService
import org.scalatestplus.play.{OneAppPerSuite, PlaySpec}
import play.api.db.Databases

class ProductSpec extends PlaySpec with OneAppPerSuite {

  var productService: ProductService = app.injector.instanceOf(classOf[ProductService])

  Databases.withDatabase(
    driver = "com.mysql.jdbc.Driver",
    url = "jdbc:mysql://localhost/playtest",
    config = Map(
      "user" -> "test",
      "password" -> "demo"
    )
  ) { database =>
    import play.api.db.evolutions._
    Evolutions.applyEvolutions(database)

    "Product" should {
      "be retrieved by Id" in {
        val product = productService.get(23)
        product.get.name must equal("mobile")
      }
    }
  }

}

Any suggestions?

saravana_pc
  • 2,607
  • 11
  • 42
  • 66

1 Answers1

4

You can inject the database object itself instead of a DBApi. By the way, one of Guice's best practices is to inject only direct dependencies. So, your example could be something like:

import play.api.db.Database

@Singleton
class ProductService @Inject() (database: Database) {

  def save(product: Product) = {
    database.withConnection { implicit connection =>
      ....
    }
  }
}

Of course, if you want to inject a specific database (instead of the "default" one), you can annotate the property like this:

import play.api.db.Database
import play.db.NamedDatabase

@Singleton
class ProductService @Inject() (@NamedDatabase("customers") database: Database) {

  def save(product: Product) = {
    database.withConnection { implicit connection =>
      ....
    }
  }
}

And, at your tests, you can create the Database as you want and manually inject it into your service. See more details about how to do it at the docs.

marcospereira
  • 12,045
  • 3
  • 46
  • 52
  • Thanks, this works great for the service class. However, I'm not able to use a test database in Integration test. I've added my test class to the question. While applying evolutions, it tries to apply to the "default" database (configured in application.conf) instead of the test database defined in the test suite. Any help is much appreciated. – saravana_pc Jan 03 '17 at 16:43
  • @marcospereira when I do this I get a ```Play error on startup: No implementation for play.api.db.Database was bound``` exception. When I manualy add the name default to the database I get the ```No implementation for play.api.db.Database annotated with @play.db.NamedDatabase(value=default) was bound.``` – decapo Jun 30 '19 at 18:59
  • @decapo did you added the `jdbc` dependency as explained here? https://www.playframework.com/documentation/2.7.x/ScalaDatabase#Configuring-JDBC-connection-pools – marcospereira Jul 03 '19 at 15:19
  • @marcospereira I did and that interferes with the slick plugin so I removed it. I forget the exact error. I may need to ask in a separate question but is it possible to use Slick and jdbc in the same project? – decapo Jul 04 '19 at 03:31
  • I cannot see why not. Maybe you have a conflict error? Better to ask a new question and share the error message. – marcospereira Jul 04 '19 at 22:18
  • @marcospereira The error I get when I mix jdbc and slick is the same as this https://stackoverflow.com/questions/33004303/a-binding-to-play-api-db-dbapi-was-already-configured-evolutions-and-injector-e , the solution there was to remove the jdbc dependency however I would like to use it. So I'll ask another question on SO about mixing the 2 together. – decapo Jul 05 '19 at 17:20
  • @marcospereira I've asked the question here https://stackoverflow.com/questions/56907379/how-to-mix-slick-and-jdbc-in-the-same-play-framework-project – decapo Jul 05 '19 at 17:47