Can a scala self-type be satisfied via delegation? - scala

Suppose I have (and this is rather contrived)
trait DbConnection {
val dbName: String
val dbHost: String
}
class Query {
self: DbConnection =>
def doQuery(sql: String) {
// connect using dbName, dbHost
// perform query
}
}
class HasADbConnection(override val dbName: String,
override val dbHost: String) extends DbConnection {
self =>
def doSomething() {
doSomethingElseFirst()
}
def doSomethingElseFirst() = {
val query = new Query() with DbConnection {
override val dbName = self.dbName
override val dbHost = self.dbHost
}
query.doQuery("")
}
}
Is there a way to avoid the redundant "override val dbName = self.dbName, override val dbHost = self.dbHost" in the new Query() creation, and instead indicate that the new Query object should inherit from / delegate to the HasADbConnection instance for these fields?
I realize it may be more appropriate for Query to take a DbConnection as a constructor argument. I'm interested though in other ways of satisfying the Query self-type. Perhaps there is no way of propagating the HasADbconnection fields onto the new Query instance, which is a completely valid answer.

Not sure exactly what you are trying to do, but this seems like a possible match to your intent:
trait C extends B {
def myA = new A() with C { // Note that this could be "with B" rather than "with C" and it would still work.
val name: String = C.this.name // explicit type not actually required - String type can be inferred.
}
}
then, for example:
scala> val myC = new C() { val name = "myC-name" }
myC: C = $anon$1#7f830771
scala> val anA = myC.myA
anA: A with C = C$$anon$1#249c38d5
scala> val aName = anA.name
aName: String = myC-name
Hopefully that can at least help guide your eventual solution. Might be able to give further help if you clarify what you want to do (or why you want to do it) further.
EDIT - after update to question:
I suggest you may be thinking about this the wrong way. I would not like tying the Query class down to knowing how to forge a connection. Rather, either pass a ready-made connection as a parameter to your call that uses the connection, or (as shown below) set up the Query class to supply a function from a connection to a result, then call that function using a connection established elsewhere.
Here is a how I would think about solving this (note that this example doesn't create an actual DB connection per se, I just take your DbConnection type at face value - really you have actually defined a 'DbConnConfig' type):
trait DbConnection {
val dbName: String
val dbHost: String
}
class Query(sql: String) {
def doQuery: DbConnection => String = { conn: DbConnection =>
// No need here to know how to: connect using dbName, dbHost
// perform query, using provided connection:
s"${conn.dbName}-${sql}-${conn.dbHost}" // <- Dummy implementation only here, so you can, for example, try it out in the REPL.
}
}
class HasADbConnection(override val dbName: String,
override val dbHost: String) extends DbConnection {
// You can create your actual connection here...
val conn = makeConnection
def doSomething(query: Query) = {
// ... or here, according to your program's needs.
val conn = makeConnection
query.doQuery(conn)
}
def makeConnection = this // Not a real implementation, just a quick cheat for this example.
}
In reality, doQuery (which could be named better) should have a type of DbConnection => ResultSet or similar. Example usage:
scala> val hasConn = new HasADbConnection("myDb", "myHost")
hasConn: HasADbConnection = HasADbConnection#6c1e5d2f
scala> hasConn.doSomething(new Query("#"))
res2: String = myDb-#-myHost

Related

Implicits over function closures in Scala

I've been trying to understand implicits for Scala and trying to use them at work - one particular place im stuck at is trying to pass implicits in the following manner
object DBUtils {
case class DB(val jdbcConnection: Connection) {
def execute[A](op: =>Unit): Any = {
implicit val con = jdbcConnection
op
}
}
object DB {
def SQL(query: String)(implicit jdbcConnection: Connection): PreparedStatement = {
jdbcConnection.prepareStatement(query)
}
}
val someDB1 = DB(jdbcConnection)
val someDB2 = DB(jdbcConnection2)
val someSQL = SQL("SOME SQL HERE")
someDB1.execute{someSQL}
someDB2.execute{someSQL}
Currently i get an execption saying that the SQL() function cannot find the implicit jdbcConnection.What gives and what do i do to make it work in the format i need?
Ps-:Im on a slightly older version of Scala(2.10.4) and cannot upgrade
Edit: Changed the problem statement to be more clear - I cannot use a single implicit connection in scope since i can have multiple DBs with different Connections
At the point where SQL is invoked there is no implicit value of type Connection in scope.
In your code snippet the declaration of jdbcConnection is missing, but if you change it from
val jdbcConnection = //...
to
implicit val jdbcConnection = // ...
then you will have an implicit instance of Connection in scope and the compiler should be happy.
Try this:
implicit val con = jdbcConnection // define implicit here
val someDB = DB(jdbcConnection)
val someSQL = SQL("SOME SQL HERE") // need implicit here
someDB.execute{someSQL}
The implicit must be defined in the scope where you need it. (In reality, it's more complicated, because there are rules for looking elsewhere, as you can find in the documentation. But the simplest thing is to make sure the implicit is available in the scope where you need it.)
Make the following changes
1) execute method take a function from Connection to Unit
2) Instead of this val someDB1 = DB(jdbcConnection) use this someDB1.execute{implicit con => someSQL}
object DBUtils {
case class DB(val jdbcConnection: Connection) {
def execute[A](op: Connection =>Unit): Any = {
val con = jdbcConnection
op(con)
}
}
Here is the complete code.
object DB {
def SQL(query: String)(implicit jdbcConnection: Connection): PreparedStatement = {
jdbcConnection.prepareStatement(query)
}
}
val someDB1 = DB(jdbcConnection)
val someDB2 = DB(jdbcConnection2)
val someSQL = SQL("SOME SQL HERE")
someDB1.execute{implicit con => someSQL}
someDB2.execute{implicit con => someSQL}

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.

Always execute code at beginning and end of method

I'm connecting to MongoDb using following code :
def insert() = {
val mc = new com.mongodb.MongoClient("localhost", 27017);
val db = mc.getDatabase("MyDb");
//My insert code
mc.close();
} //> insert: ()Unit
I have various methods which open and close the connection.
Can the lines :
val mc = new com.mongodb.MongoClient("localhost", 27017);
val db = mc.getDatabase("MyDb");
mc.close();
be extracted so that they are implicitly called at beginning and end of method.
Does Scala implicits cater for this scenario or is reflection required ?
A common pattern would be to use a call-by-name method where you can pass a function that accepts a DB and does something with it. The call-by-name method can facilitate the creation of the client, etc, and execute the code within.
def withDB[A](block: DB => A): A = {
val mc = new com.mongodb.MongoClient("localhost", 27017);
val db = mc.getDatabase("MyDb");
try block(db) finally mc.close()
}
And use it:
def insert() = withDB { db =>
// do something with `db`
}
However, a look at the documentation says:
A MongoDB client with internal connection pooling. For most applications, you should have one MongoClient instance for the entire JVM.
Which makes the above approach look like a bad idea, assuming that is the version you are using. I can definitely see some concurrency issues trying to do this and having too many connections open.
But, you can follow the same pattern, stuffing the connection creating into a singleton object. You would need to manage the closing of the client when your application is shutdown, however.
object Mongo {
lazy val mc = new com.mongodb.MongoClient("localhost", 27017);
lazy val db = mc.getDatabase("MyDb");
def withDB[A](block: DB => A): A = block(db)
def close(): Unit = mc.close()
}
You can define a method that executes some 'work' function e.g.
def withMongoDb[T](work: DB => T): T = {
val mc = new com.mongodb.MongoClient("localhost", 27017)
// I don't actually know what type `db` is so I'm calling it `DB`
val db: DB = mc.getDatabase("MyDb")
try { work(db) }
finally { mc.close() }
}
Then you can use it like:
withMongoDb { db =>
db.insert(...)
db.query(...)
}
This is a similar approach to the one used in Slick, pre-3.0, i.e. withSession and withTransaction.
Now, if you implemented some convenience methods e.g.
def insertStuff(values: Seq[Int])(implicit db: DB) = {
db.insert(values)
}
Then you could call mark the db as implicit in your withMongoDb call, effectively making sure you never accidentally call insertStuff outside of that block.
withMongoDb { implicit db =>
insertStuff(Seq(1,2,3,4))
}
insertStuff(Seq(1,2,3,4)) // compile error
Instead of implicits you could do something like this:
def mongoConn(ip:String, port:Int, dbName:String):(Database => Unit) => Unit = {
f => {
val mc = new com.mongodb.MongoClient(ip, port)
val db = mc.getDatabase(dbName)
f(db)
mc.close()
}
}
val conn = mongoConn("localhost", 27017, "MyDb")
conn(db => {
//insert code
})

Scala Reflection to update a case class val

I'm using scala and slick here, and I have a baserepository which is responsible for doing the basic crud of my classes.
For a design decision, we do have updatedTime and createdTime columns all handled by the application, and not by triggers in database. Both of this fields are joda DataTime instances.
Those fields are defined in two traits called HasUpdatedAt, and HasCreatedAt, for the tables
trait HasCreatedAt {
val createdAt: Option[DateTime]
}
case class User(name:String,createdAt:Option[DateTime] = None) extends HasCreatedAt
I would like to know how can I use reflection to call the user copy method, to update the createdAt value during the database insertion method.
Edit after #vptron and #kevin-wright comments
I have a repo like this
trait BaseRepo[ID, R] {
def insert(r: R)(implicit session: Session): ID
}
I want to implement the insert just once, and there I want to createdAt to be updated, that's why I'm not using the copy method, otherwise I need to implement it everywhere I use the createdAt column.
This question was answered here to help other with this kind of problem.
I end up using this code to execute the copy method of my case classes using scala reflection.
import reflect._
import scala.reflect.runtime.universe._
import scala.reflect.runtime._
class Empty
val mirror = universe.runtimeMirror(getClass.getClassLoader)
// paramName is the parameter that I want to replacte the value
// paramValue is the new parameter value
def updateParam[R : ClassTag](r: R, paramName: String, paramValue: Any): R = {
val instanceMirror = mirror.reflect(r)
val decl = instanceMirror.symbol.asType.toType
val members = decl.members.map(method => transformMethod(method, paramName, paramValue, instanceMirror)).filter {
case _: Empty => false
case _ => true
}.toArray.reverse
val copyMethod = decl.declaration(newTermName("copy")).asMethod
val copyMethodInstance = instanceMirror.reflectMethod(copyMethod)
copyMethodInstance(members: _*).asInstanceOf[R]
}
def transformMethod(method: Symbol, paramName: String, paramValue: Any, instanceMirror: InstanceMirror) = {
val term = method.asTerm
if (term.isAccessor) {
if (term.name.toString == paramName) {
paramValue
} else instanceMirror.reflectField(term).get
} else new Empty
}
With this I can execute the copy method of my case classes, replacing a determined field value.
As comments have said, don't change a val using reflection. Would you that with a java final variable? It makes your code do really unexpected things. If you need to change the value of a val, don't use a val, use a var.
trait HasCreatedAt {
var createdAt: Option[DateTime] = None
}
case class User(name:String) extends HasCreatedAt
Although having a var in a case class may bring some unexpected behavior e.g. copy would not work as expected. This may lead to preferring not using a case class for this.
Another approach would be to make the insert method return an updated copy of the case class, e.g.:
trait HasCreatedAt {
val createdAt: Option[DateTime]
def withCreatedAt(dt:DateTime):this.type
}
case class User(name:String,createdAt:Option[DateTime] = None) extends HasCreatedAt {
def withCreatedAt(dt:DateTime) = this.copy(createdAt = Some(dt))
}
trait BaseRepo[ID, R <: HasCreatedAt] {
def insert(r: R)(implicit session: Session): (ID, R) = {
val id = ???//insert into db
(id, r.withCreatedAt(??? /*now*/))
}
}
EDIT:
Since I didn't answer your original question and you may know what you are doing I am adding a way to do this.
import scala.reflect.runtime.universe._
val user = User("aaa", None)
val m = runtimeMirror(getClass.getClassLoader)
val im = m.reflect(user)
val decl = im.symbol.asType.toType.declaration("createdAt":TermName).asTerm
val fm = im.reflectField(decl)
fm.set(??? /*now*/)
But again, please don't do this. Read this stackoveflow answer to get some insight into what it can cause (vals map to final fields).

Play2 and Scala, How should I configure my integration tests to run with proper DB

I'm trying to figure out how to write my db integration tests in my Play2 app.
In my conf file I have specified two databases, xxx_test for regular use and h2 db for testing:
db.xxx_test.driver=com.mysql.jdbc.Driver
db.xxx_test.url="jdbc:mysql://localhost/xxx_test?characterEncoding=UTF-8"
db.xxx_test.user="root"
db.xxx_test.password=""
db.h2.driver=org.h2.Driver
db.h2.url="jdbc:h2:mem:play"
db.h2.user=sa
db.h2.password=""
In my User object I have specified xxx_test to be used when I run the application.
def createUser(user: User): Option[User] = {
DB.withConnection("xxx_test") {
implicit connection =>
SQL("insert into users(first_name, last_name, email, email_validated, last_login, created, modified, active) values({first_name},{last_name},{email},{email_validated},{last_login}, {created}, {modified}, {active})").on(
'first_name -> user.firstName,
'last_name -> user.lastName,
'email -> user.email,
'email_validated -> user.emailValidated,
'last_login -> user.lastLogin,
'created -> user.created,
'modified -> user.modified,
'active -> true
).executeInsert().map(id => {
return Some(User(new Id[Long](id), user.firstName, user.lastName, user.email, user.emailValidated, user.lastLogin, user.created, user.modified, true))
}
)
}
None
}
In my test I create a new inMemoryDatabase and then use the User to create and get my object
for testing.
class DBEvolutionsTest extends Specification {
"The Database" should {
"persist data properly" in {
running(FakeApplication(additionalConfiguration = inMemoryDatabase())) {
User.create(User(Id[Long](1L), "jakob",
"aa",
"aaa",
true,
DateTime.now(),
DateTime.now(),
DateTime.now(),
true))
val newUser = User.findBy(Id[Long](1L))
newUser.get.firstName must beEqualTo("jakob")
}
}
}
}
This of course is not the correct way since the User object uses the xxx_test and not the
h2 db. The test will create a User in the real db and not the one in memory since I have specified the db in the User(DB.withConnection("xxx_test")) object.
I guess there is some smart way of doing this, I do not want to pass the db name around
inte the application like User.create(User(...), "xxx_test")
How have you solved this problem?
You might want to checkout how to do dependency injection in scala. A good solution is to abstract your database out of your User model and then pass it as a dependency.
A simple way to do it would be to change the configuration file for testing. Play lets you specify which config file is used on the command line.
This is not the most practical though.
Another solution is to use implicits, define your database connection as an implicit parameter of your function:
def createUser(user: User)(implicit dbName: String): Option[User]=
DB.withConnection(dbName) { ... }
You will still have to propagate the parameter upwards in all your calls, but you can hide it:
def importUsers(csvFile: File)(implicit dbName: String): Seq[User] = { conn =>
...
User.createUser(u)
...
}
and when you call it from the top:
implicit dbName = "test"
importUsers(...)
This is build in in scala, so it's pretty easy to setup and doesn't need a lot of boilerplate supporting it. Personally, I think that implicits make the code unclear and I prefer the solution presented in this presentation Dead-Simple Dependency Injection.
The gist of it is that you make your createUser and all other methods that depend on a database connection to return a function depending on the connection, and not just the result. Here is how it would work with your example.
1- you create a Connection trait that configures a connection. A simple form would be:
trait ConnectionConfig {
def dbName: String
}
2- your method depending on that config returns a function:
def createUser(user: User): ConnectionConfig => Option[User] = { conn =>
DB.withConnection(conn.dbName) { ... }
}
3- when you use createUser in another method, that method becomes dependent on the connection too, so you mark it as such by returning the dependency on ConnectionConfig with a function return type, for example:
def importUsers(csvFile: File): ConnectionConfig => Seq[User] = { conn =>
...
User.createUser(u)(conn)
...
}
This is a good habit to have, as it will be clear in your code which methods depends on a connection to the database, and you can easily swap connections. So, in your main app, you would create the real connection:
class RealConncetionConfig extends ConnectionConfig {
val dbName = "xxx_test"
}
but in your test file, you create a test DB config:
class DBEvolutionsTest extends Specification {
class TestDBConfig extends ConnectionConfig {
val dbName = "h2"
}
val testDB = new TestDBConfig()
"The Database" should {
"persist data properly" in {
running(FakeApplication(additionalConfiguration = inMemoryDatabase())) {
User.create(User(Id[Long](1L), "jakob",
"aa",
"aaa",
true,
DateTime.now(),
DateTime.now(),
DateTime.now(),
true))(testDB)
val newUser = User.findBy(Id[Long](1L))
newUser.get.firstName must beEqualTo("jakob")
}
}
}
}
This is the gist of it. Check out the presentation and slides I mentioned, there is a nice way to abstract all of that so that you can loose the (conn) argument that is making this code ugly.
As a side comment, if I were you, I would even abstract the type of DB. So, instead of having the SQL in the User model object, have it in a separate implementation, this way you can easily switch the type of database (use mongodb, dynamo...).
It would just be something like this, extending from the previous code:
trait ConnectionConfig {
def createUser(user: User): Option[User]
}
and in the User model object:
def createUser(user: User): ConnectionConfig => Option[User] = { conn =>
conn.createUser(user)
}
this way, when testing parts of your code depending on the User model, you can make a mock DB where createUser always works and returns the expected result (or always fails...), without even using the in memory database (you would still need tests for the real SQL connection, but you could test other parts of your app):
trait ConnectionConfig {
def createUser(user: User): Option[User] = Some(user)
}
The inMemoryDatabase method is defined like this:
def inMemoryDatabase(
name: String = "default",
options: Map[String, String] = Map.empty[String, String]): Map[String, String]
My guess is that you should pass the xxx_test as the name parameter.
You must define a name other than your default(xxx_test) name for the in memory database. I think the following snippet should work.
FakeApplication(additionalConfiguration = inMemoryDatabase("h2"))
Please see also: https://stackoverflow.com/a/11029324/2153190