Sometimes you need to automate maintenance tasks in your Play application (e.g. import data from CSV file into your app’s database, generate a report…). To do anything useful you need the proper classpath and probably a connection to the database using the same infrastructure normally used by the application. This is very similar to how tests are run. In this post I will show how I created a Scripts object that takes care of the FakeApplication initialization to allow simple script creation and usage from the test:console.

The Scripts object

Place a Scripts.scala file inside the test folder. This is required as the files inside this folder are compiled with a classpath that includes the play.api.test._ symbols.

test/Scripts.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// I'm using Slick and I will need these to pass the Slick sessions to the scripts
import scala.slick.session.Database
import scala.slick.session.Session

// FakeApplication and the running() helper
import play.api.test._
import play.api.test.Helpers._

import play.api.db.DB

// Where I place the actual scripts and utilities (e.g. JogosCSVImporter)
import tools._

object Scripts {
  // Declare this implicit to have it easily passed to DB.getDataSource()
  private implicit lazy val application = FakeApplication()

  // Lazily initialized Slick Database
  private lazy val db = Database.forDataSource(DB.getDataSource())

  /**
   * $ play test:console
   * > Scripts.importJogosFromCSV("path/to/file.csv")
   */
  def importJogosFromCSV(csvFilePath: String) = {
    db withSession { implicit s: Session =>
      JogosCSVImporter.importJogos(csvFilePath)
    }
  }
}

JogosCSVImporter

To minimize the code in the test folder place the JogosCSVImporter object inside the app/tools folder.

Implementation of the JogosCSVImporter Script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package tools

import scala.slick.jdbc.{StaticQuery => Q}
import scala.slick.session.Session
import scala.slick.session.Database

// My Slick Tables
import tables._

import utils.CSV

object JogosCSVImporter {
  ...

  // The implicit Session will be accessible to all the script code and will
  // be passed automatically to functions that require a Slick Session.
  def importJogos(csvFilePath: String)(implicit s: Session): Int = {
    ...
  }
}

Using scripts in the test:console

Implementation of the JogosCSVImporter Script
1
$ play test:console  # start the test console

In the test:console you can call any Scripts.\_ without worring about the classpath or any context initialization.

Running a Script
1
2
3
4
5
6
7
8
9
10
[info] Starting scala interpreter...
[info] Welcome to Scala version 2.10.2 (Java HotSpot(TM) 64-Bit Server VM, Java
1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.

scala> Scripts.importJogosFromCSV("/Users/felipe/a.csv")
Importing jogos...

scala>