Play 2.x+ Liquibase Migration Module
Runs Liquibase migrations on Play application startup.
Table Of Contents
- Play 2.x Liquibase Migration Module
- Table Of Contents
- Adding Liquibase Module to your Play Scala project
- Dependency Matrix
- Configuration
- Using Liquibase
- Publishing Jars to Maven Central
- Copyright and License
Adding Liquibase Module to your Play Scala project
Add dependency to your build.sbt
:
libraryDependencies += "com.ticketfly" %% "play-liquibase" % "<version>"
Current version is built against Scala 2.10, 2.11 and 2.12 and works with Play 2.4 and higher.
No additional code changes are necessary. It uses Play Dependency Injection to eagerly run migrations on startup.
Dependency Matrix
Play | Scala | play-liquibase |
---|---|---|
2.4 - 2.5 | 2.10 - 2.11 | 1.6 |
2.6 | 2.11 - 2.12 | 2.2 |
Configuration
If only one jdbc connection is defined, that is used by default, no additional configuration needed. E.g.
db.default {
url = "jdbc:mysql://localhost/myschema"
driver = "com.mysql.jdbc.Driver"
}
Otherwise add to application.conf
:
liquibase {
url = "jdbc:mysql://localhost/myschema?logger=com.mysql.jdbc.log.Slf4JLogger"
driver = "com.mysql.jdbc.Driver"
user = "ticketfly"
password = "bar123"
}
If you are using Slick with Play, you can reference Slick config:
liquibase = ${slick.dbs.default.db}
Supported optional liquibase configuration parameters:
changelog, contexts, defaultCatalogName, defaultSchemaName, databaseClass, driverPropertiesFile, propertyProviderClass, liquibaseCatalogName, liquibaseSchemaName, databaseChangeLogTableName, databaseChangeLogLockTableName
To disable liquibase execution set liquibase.enable=false
Note: Required parameters are: url, driver
Using Liquibase
Liquibase Module works with Liquibase 3.6+
Example changelog.xml:
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">
<changeSet id="1" author="dragisak">
<comment>Create a table</comment>
<createTable tableName="my_table">
<column name="id" type="bigint" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="event_id" type="bigint">
<constraints nullable="false"/>
</column>
<column name="ticket_type" type="varchar(30)">
<constraints nullable="false"/>
</column>
<column name="onsale_date" type="datetime">
<constraints nullable="false"/>
</column>
<column name="offsale_date" type="datetime">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
</databaseChangeLog>
Place your changelog.xml
file in the conf/liquibase
directory. That will make it a part of Play distribution.
You can override name and path to changelog file by setting liquibase.changelog
configuration parameter. Default is conf/liquibase/changelog.xml
For details on using Liquibase, go to: www.liquibase.org
Using include
and includeAll
tags
Example changelog.xml (if you place your schema changelogs in conf/liquibase/schema
directory and trigger in conf/liquibase/triggers
directory):
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<includeAll path="./schema" relativeToChangelogFile="true"/>
<include path="./triggers/trigger-1.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
Using contexts
Liquibase contexts can be used to maintain a different set of change sets for different environments or uses. For example, you may have one set to maintain the production schema and one set to maintain the test schema, along with a small set of test data
Context is an attribute of the change set
<changeSet id="2" author="bob" context="test">
...
</changeSet>
To run the "test" context only, add to your liquibase configuration in application.conf
liquibase.contexts = ["test"]
Loading changes from the classpath
If your database access code is in a sub-module or library, you may want to keep your change files in, for example, src/main/resources/liquibase of that library. In this case you can choose to load your files from the classpath by specifying the changelog attribute and prepending 'classpath:' to the path. In the scenario where your master.xml file is located in src/main/resources/liquibase, add to your liquibase configuration
liquibase.changelog = "classpath:liquibase/master.xml"
Disabling Liquibase migrations
To disable running Liquibase on startup, you can set
liquibase.enable = false
You can disable Liquibase from command line with -Dliquibase.enable=false
.
For details on configuring Play app, see Play Production Configuration
Testing With In-memory Database
There is a special options in H2 url to tell H2 to keep schema after Liquibase has finished: DB_CLOSE_DELAY=-1
Also, you have to make sure that it does not force table name to uppercase with DATABASE_TO_UPPER=false
Example:
val appWithMemoryDatabase = FakeApplication(
additionalConfiguration = {
val driver = "org.h2.Driver"
val url = s"jdbc:h2:mem:test${Random.nextInt()}:test;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1"
Map(
"slick.dbs.default.driver" -> "slick.driver.H2Driver$",
"slick.dbs.default.db.driver" -> driver,
"slick.dbs.default.db.url" -> url,
"slick.dbs.default.db.user" -> "sa",
"slick.dbs.default.db.password" -> "",
"liquibase.driver" -> driver,
"liquibase.url" -> url,
"liquibase.user" -> "sa",
"liquibase.password" -> ""
)
}
)
"save and query" in new WithApplication(appWithMemoryDatabase) {
...
val postRequest = FakeRequest(POST, "/test").withJsonBody(Json.toJson(payload))
val Some(saveResult) = route(postRequest)
status(saveResult) must equalTo(OK)
...
}
Logging
To show logs generated by Liquibase, add this to your app's logback.xml
:
<logger name="liquibase" level="INFO" />
Publishing Jars to Maven Central
Project uses sbt-sonatype plugin.
After setting your credentials, you can do:
sbt +publishSigned
sbt sonatypeReleaseAll
Copyright and License
All code is available to you under the MIT license, available at http://opensource.org/licenses/MIT and also in the LICENSE file.
Copyright Ticketfly, Inc., 2016.