I'm trying to move all of my implicits to a common object so I can use them in all of my DAO classes, but I cannot set it up correctly.
I have this so far:
package com.example.dao
import java.sql.Timestamp
import java.time.Instant
import play.api.db.slick.DatabaseConfigProvider
import play.api.db.slick.HasDatabaseConfigProvider
import slick.driver.JdbcProfile
object DbImplicits {
import driver.api._
implicit val dateColumnType = MappedColumnType.base[Instant, Timestamp](
i => Timestamp.from(i),
ts => {
ts.toInstant
}
)
}
I am getting this error:
not found: object driver
In your DAO it's taken from extended trait HasDatabaseConfigProvider.
Just put your conversation into trait then (trait DbImplicits) that require to be mixed-in together with or extends HasDatabaseConfigProvider.
trait DbImplicits { self: HasDatabaseConfigProvider[JdbcProfile] =>
import self.driver._
implicit val dateColumnType = MappedColumnType.base[Instant, Timestamp](
i => Timestamp.from(i),
ts => {
ts.toInstant
}
)
}
Later use it like this:
class MyClassUsingImplicits #Inject()(
protected val dbConfigProvider: DatabaseConfigProvider
) extends HasDatabaseConfigProvider[JdbcProfile]
with DbImplicits {
import driver._
// your further code comes here
}
All this is kind of specific to play-slick.
I also updated the original answer: https://stackoverflow.com/a/41437295/2239369
Related
I have a wrapper trait that extends BasicFormats from spray json https://github.com/spray/spray-json/blob/release/1.3.x/src/main/scala/spray/json/BasicFormats.scala
but I would like to override the behavior of implicit object BigDecimalJsonFormat extends JsonFormat[BigDecimal] to add rounding logic. Example being
import spray.json._
import scala.math.BigDecimal.RoundingMode
case class Foo(i: BigDecimal)
object Foo extends DefaultJsonProtocol {
implicit val roundedBigDecimalProtocol: JsonFormat[BigDecimal] =
new JsonFormat[BigDecimal] {
def write(f: BigDecimal) = JsNumber(f.setScale(2, RoundingMode.HALF_UP))
def read(json: JsValue): BigDecimal =
DefaultJsonProtocol.BigDecimalJsonFormat.read(json)
}
implicit val fooFormatter = jsonFormat1(this.apply)
}
scastie snippet:
https://scastie.scala-lang.org/9RNhajzGRDGMX5QsuAohVA
Great question, I wasn't even aware this may cause so many problems. The solution I am about to propose is probably not the cleanest, but it does the job... First of all, you don't have to extend DefaultJsonProtocol, you might also import it's members:
object Foo {
import DefaultJsonProtocol._
implicit val roundedBigDecimalProtocol: JsonFormat[BigDecimal] = ...
implicit val fooFormatter = jsonFormat1(this.apply)
}
This doesn't solve the problem but that way you can exclude some of the members so that they are not imported. Here's the syntax for that
import DefaultJsonProtocol.{BigDecimalJsonFormat => _, _}
It basically says: don't import BigDecimalJsonFormat but import the rest.
And the following code sums it up.
import spray.json._
import scala.math.BigDecimal.RoundingMode
case class Foo(i: BigDecimal)
object Foo {
import DefaultJsonProtocol.{BigDecimalJsonFormat => _, _}
implicit val roundedBigDecimalProtocol: JsonFormat[BigDecimal] =
new JsonFormat[BigDecimal] {
def write(f: BigDecimal) = JsNumber(f.setScale(2, RoundingMode.HALF_UP))
def read(json: JsValue): BigDecimal =
DefaultJsonProtocol.BigDecimalJsonFormat.read(json)
}
implicit val fooFormatter = jsonFormat1(this.apply)
}
ive come across this problem :
Caused by: org.postgresql.util.PSQLException: FATAL: sorry, too many clients already
The app works, but i can only make like 3 or 4 requests and then im getting this error, so whats happening (im guessing) is im creating new connections per request and id like to keep one connection per app lifecycle, any idea how to modify the code to do so?
Tried injecting UsersDao to my controller instead of using it as an object but that changes nothing
Im really new to scala so any help is appreciated
Dao
import config.DatabaseConfig
import domain.{User, UsersTable}
import slick.jdbc.PostgresProfile.api._
import slick.sql.SqlAction
import scala.concurrent.Future
trait BaseDao extends DatabaseConfig {
val usersTable = TableQuery[UsersTable]
protected implicit def executeFromDb[A](action: SqlAction[A, NoStream, _ <: slick.dbio.Effect]): Future[A] = {
println(db)
db.run(action)
}
}
object UsersDao extends BaseDao {
def findAll: Future[Seq[User]] = usersTable.result
def create(user: User): Future[Long] = usersTable.returning(usersTable.map(_.id)) += user
def findByFirstName(firstName: String): Future[Seq[User]] = usersTable.filter(_.firstName === firstName).result
def findById(userId: Long): Future[User] = usersTable.filter(_.id === userId).result.head
def delete(userId: Long): Future[Int] = usersTable.filter(_.id === userId).delete
}
DatabaseConfig
trait DatabaseConfig extends Config {
val driver = slick.jdbc.PostgresProfile
import driver.api._
def db = Database.forConfig("dbname")
implicit val session: Session = db.createSession()
}
Controller
import domain.User
import javax.inject.{Inject, Singleton}
import play.api.libs.json.Json
import play.api.mvc._
import repository.UsersDao
import scala.concurrent.{ExecutionContext, Future}
#Singleton
class UserController #Inject() ()(cc: ControllerComponents, parsers: PlayBodyParsers)(implicit exec: ExecutionContext) extends AbstractController(cc) {
def addUser = Action.async(parse.json[User]) { req => {
UsersDao.create(req.body).map({ user =>
Ok(Json.toJson(user))
})
}
}
I'm using Play Scala 2.5, I would like to write functional tests for a controller class.
This is the signature of my controller class with a action I would like to test for example.
class MyController #Inject()(implicit context: ExecutionContext, val messagesApi: MessagesApi, val dao: Dao) extends Controller with I18nSupport {
def getMyData = Action.async { implicit request =>
dao.getMyData map { myData =>
Ok(views.html.render(myData))
}.recover {
// recover.
}
}
}
Here is my Dao class that is used in my controller's action :
import play.api.Configuration
class Dao #Inject()(val ws: WSClient, val configuration: Configuration) {
val myConfigData: List[MyConfigData] = { ... } // Get data from configuration
def getMyData(): Future[List[MyData]] = {
// use myConfigData and call web service (ws) to get some data
}
}
I would like to test my controller's action using different configuration in my Dao class.
I manage to do it and my test class is working but I would like some advices to improve the code.
package controllers
import play.core.server.Server
import org.scalatest._
import Inspectors._
import org.scalatestplus.play._
import play.api.routing.sird._
import play.api.libs.json._
import play.api.mvc._
import play.api.Play
import play.api.test._
import play.api.i18n.MessagesApi
import play.api.Configuration
import play.api.test.Helpers.{ OK, status, contentAsString }
import org.scalatest.concurrent.ScalaFutures
import scala.concurrent.Future
import scala.concurrent.Await
import scala.concurrent.duration._
import play.api.libs.json._
import play.api.mvc._
import scala.concurrent.ExecutionContext
import com.typesafe.config.ConfigFactory
import dao.{ Dao }
import akka.util.Timeout
class MyControllerFunctionalSpec extends PlaySpec with OneAppPerSuite with ScalaFutures {
implicit val messagesApi = app.injector.instanceOf[MessagesApi]
implicit val ec = app.injector.instanceOf[ExecutionContext]
implicit val timeout = Timeout(5 seconds)
trait OneConfig {
val config = ConfigFactory.parseString(""" my config """)
}
trait AnotherConfig {
val config = ConfigFactory.parseString(""" my other config """)
}
"MyController" should {
"get some data" in new OneConfig {
Server.withRouter() {
case GET(p"/url1/some/data") => Action {
Results.Ok(Json.arr(Json.obj("name" -> "data1")))
}
} { implicit port =>
WsTestClient.withClient { client =>
implicit val dao = new Dao(client, Configuration(config))
val myController = new MyController()
val result = myController.getMyData(FakeRequest())
status(result) must equal(OK)
//println(contentAsString(result))
}
}
}
}
}
It is working like this but I was guided by compilation error and by fixing them to get it to work.
I would like help or advices to do it the right way.
Any advice welcome.
Any idea why this code doesn't work? I'm trying to have serialize method to all my exceptions to avoid the need for pattern matching for every exception. With the code below, I just need to case ex:MarshallableException => ex.serialize
The below code can run stand-alone. It will print Start... Serialization Failure shared.utils.InvalidID :(
import scala.util.{Failure, Success}
import akka.http.scaladsl.marshalling.{Marshaller, Marshal}
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.http.scaladsl.model.ResponseEntity
import spray.json.DefaultJsonProtocol
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
trait MarshallableException{
def serialize: Future[ResponseEntity]
}
case class InvalidID(error:String, code: String= "6001") extends Exception with MarshallableException {
import Exceptions._
override def serialize: Future[ResponseEntity] = {
Marshal(this).to[ResponseEntity]
}
}
object Exceptions extends DefaultJsonProtocol{
implicit val invalidIDFormat = jsonFormat2(InvalidID.apply)
}
object Test extends App{
val ex = new InvalidID("Test exception")
println("Start...\n")
ex.serialize.onComplete{
case Success(e) => println(e.toString())
case Failure(f) =>
println("Serialization Failure " + f.toString)
}
}
Registration.scala
package model
import akka.actor.Actor
import spray.json._
import DefaultJsonProtocol._
case class Registration(
system: String,
identity: String)
object RegistrationProtocol extends DefaultJsonProtocol {
implicit val adsRegistrationFormat = jsonFormat2(Registration)
}
RegistrationService.scala
import akka.actor.{Props, ActorLogging, Actor}
import model.Registration
object RegistrationsService {
case class PostRegistrationMessage(registration: Registration)
def props(property: String) = Props(classOf[RegistrationsService], property)
}
class RegistrationsService(property: String) extends Actor with ActorLogging {
import RegistrationsService._
def receive = {
case PostRegistrationMessage(registration) => {
import model.RegistrationProtocol._
val json = registration.toJson
}
}
}
Can anyone help me understand why this is failing with compilation error "value toJson is not a member of model.Registration" and how to fix it. It if failing in the last line of the code above, which is "val json = registration.toJson"
You need to import implicit operations provided by spray in RegistrationService.scala too
import model.RegistrationProtocol._
import spray.json._