Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>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.</p> <p>A simple way to do it would be to change the configuration file for testing. Play lets you <a href="http://www.playframework.com/documentation/2.0/ProductionConfiguration" rel="nofollow">specify which config file is used on the command line</a>. This is not the most practical though.</p> <p>Another solution is to use implicits, define your database connection as an implicit parameter of your function:</p> <pre><code>def createUser(user: User)(implicit dbName: String): Option[User]= DB.withConnection(dbName) { ... } </code></pre> <p>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) ... }</p> <p>and when you call it from the top:</p> <pre><code>implicit dbName = "test" importUsers(...) </code></pre> <p>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 <a href="http://lanyrd.com/2012/nescala/sqygc/" rel="nofollow">Dead-Simple Dependency Injection</a>.</p> <p>The gist of it is that you make your <code>createUser</code> 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.</p> <p>1- you create a Connection trait that configures a connection. A simple form would be:</p> <pre><code>trait ConnectionConfig { def dbName: String } </code></pre> <p>2- your method depending on that config returns a function:</p> <pre><code>def createUser(user: User): ConnectionConfig =&gt; Option[User] = { conn =&gt; DB.withConnection(conn.dbName) { ... } } </code></pre> <p>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:</p> <pre><code>def importUsers(csvFile: File): ConnectionConfig =&gt; Seq[User] = { conn =&gt; ... User.createUser(u)(conn) ... } </code></pre> <p>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:</p> <pre><code>class RealConncetionConfig extends ConnectionConfig { val dbName = "xxx_test" } </code></pre> <p>but in your test file, you create a test DB config:</p> <pre><code>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") } } } } </code></pre> <p>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 <code>(conn)</code> argument that is making this code ugly.</p> <p>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:</p> <pre><code>trait ConnectionConfig { def createUser(user: User): Option[User] } </code></pre> <p>and in the User model object:</p> <pre><code>def createUser(user: User): ConnectionConfig =&gt; Option[User] = { conn =&gt; conn.createUser(user) } </code></pre> <p>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):</p> <pre><code>trait ConnectionConfig { def createUser(user: User): Option[User] = Some(user) } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload