Coder Social home page Coder Social logo

play-liquibase's Introduction

Build Status Codacy Badge Codacy Badge Maven Central Dependencies

Play 2.x+ Liquibase Migration Module

Runs Liquibase migrations on Play application startup.

Table Of Contents

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.

play-liquibase's People

Contributors

b-gyula avatar dragisak avatar feoktant avatar jtescher avatar noambarkai avatar vadim-shb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

play-liquibase's Issues

Support Play 2.6.x for Scala 2.11 as well

Currently Play 2.6.x supports both Scala 2.11 and Scala 2.12
However, play-liquibase assumes Play 2.4.x when Scala version is 2.11 (see https://github.com/Ticketfly/play-liquibase/blob/master/play-liquibase/build.sbt#L19)
Thus, when trying to run with Play 2.6.x + Scala 2.11 we encounter a runtime exception:

Caused by: java.lang.NoSuchMethodError: play.api.Logger.info(Lscala/Function0;)V
	at com.ticketfly.play.liquibase.PlayLiquibase.upgradeSchema(PlayLiquibaseModule.scala:53)

play-liquibase doesn't start if user/pass aren't specified

Hi there,

This is a great plugin and I find it enormously useful - thanks!

However, I've found one small quirk that stumped me for a while: if I'm running play locally, I use H2 in-memory as my database and I configure this without a username and password for simplicity. When play-liquibase is starting up, however, it expects there to be values:

val usernameOpt = liquibaseConfOpt.flatMap(_.getString("user"))

If user or password are blank, then the for/yield below returns None which results in the (slightly misleading) error "Liquibase is not configured". Can be reproduced with the following in application.conf:

slick.dbs.default.driver="slick.driver.H2Driver$"
slick.dbs.default.db.driver="org.h2.Driver"
slick.dbs.default.db.url="jdbc:h2:mem:default;DB_CLOSE_DELAY=-1"

liquibase=${slick.dbs.default.db}

Make PlayLiquibase extendable

As a developer, I need to extend standard upgradeSchema process. To do this, I need to have instance of Liquibase class. I cannot do this, because of method private def liquibase(), which is private.

My propose is to make it protected

Give me back commit privileges

I don't know who owns this project now. Please add me back to project admins so I can continue maintaining this project.

play-liquibase needs a new home

I am no longer an owner of this repo and can't merge pull requests. Also, I haven't been working with Play or Liquibase in years and can't maintain this project anymore.

We need someone to fork play-liquibase project.

Feature request: method of manually running migrations

Sometimes it is important to run database migrations before launching an application. It should be possible to do the following:

  1. Set liquibase.enable = false.
  2. Run a script, bin/apply_migrations for example.
  3. Start the application.

This would be similar to the grails dbm-update command.

2.2 fails with a NullPointerException if more than one database is configured

I am not up on scala, but from what I can see including stepping through the debugger, PlayLiquibase.liquibase() throws an NPE if more than one db is configured, because in that case dbCfg is null via singleJdbcDatabaseConfig and dbCfg.flatMap() is subsequently unconditionally invoked. See the two 'NPE' comments below:

protected def liquibase(): Option[Liquibase] = {
var missingRequiredParam = false

/** get p parameter from cfg.
 * If not found use defValue
 *
 * @param p         parameter get value for
 * @param defValue  default value
 * @param cfg       configuration the value shall be taken from
 * @return null if not set or trimmed to an empty string
 */
def getRequiredParam(p: Param, defValue: Option[String] = None)
                    (implicit cfg: Option[Configuration]): String = {
  val ret = getParam(p, defValue)(cfg)
  if (null == ret) {
    missingRequiredParam = true
    log.warn(s"Missing required configuration parameter: $p")
  }
  ret
}

implicit val liquibaseConfOpt: Option[Configuration] = config.getOptional[Configuration]("liquibase")

// NPE:  if more than one db is configured, singleJdbcDatabaseConfig returns null:
val dbCfg = singleJdbcDatabaseConfig

// NPE:  if more than one db is configured, dbCfg is null and .flatMap() results an NPE:
val url = getRequiredParam(Param.url, dbCfg.flatMap(_.url))
val driver = getRequiredParam(Param.driver, dbCfg.flatMap(_.driver))

...

}

liquibase resolve wrong file lication for releative rescource

conf
    liquibase
        changelog.xml
        dicts
            dict.xml
            dict.csv

changelog.xml is:

<includeAll path="./dicts" relativeToChangelogFile="true" />

When I trying to run applcation I have an exception:

liquibase.exception.ChangeLogParseException: file:/conf/liquibase/dicts/dict.xml does not exist

In FileSystemResourceAccessor chengelog.xml opened from path:

/home/myuser/git/myapp/conf/liquibase/changelog.xml

but relative resource path resolve as

/home/myuser/git/myapp/file:/conf/liquibase/dicts/dict.xml

file: in the middle of the path broke the correct path

load files from classpath

hi

i saw the comment in PlayLiquibaseModule about the classpath loader not working. however, i think my use case is a little different

i have a sub module with my data access code. i also have unit tests here which need to run liquibase changes before running the tests. if i put my liquibase files in my sub module i can use them for my tests and also with the classpath loader from the plugin without errors (they would ultimately be in a jar)

anyhoo, i've already made the basic changes on my fork, but i want to make sure, given the comments, that a pull request would be accept before i finish it up

let me know and i can finish it up real quick

README.md liquibase version

To use liquibase 3.6 the xml namesace shallla be http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">

Play-slick - how add two database and changelog?

Hello. I use play-slick 3.0.1 and play-liquibase 1.4.

Now I have one database with changelog. My application.conf:

slick.dbs.default.profile = "models.database.CustomPostgresProfile$"
slick.dbs.default.db.driver = "org.postgresql.Driver"
slick.dbs.default.db.url = "jdbc:postgresql://127.0.0.1:5432/mydb"
slick.dbs.default.db.user = "postgres"
slick.dbs.default.db.password = "postgres"

liquibase = ${slick.dbs.default.db}
liquibase.changelog = "classpath:liquibase/changelog-master.xml"

I add two database:

slick.dbs.db2.profile = "models.database.CustomPostgresProfile$"
slick.dbs.db2.db.driver = "org.postgresql.Driver"
slick.dbs.db2.db.url = "jdbc:postgresql://127.0.0.1:5432/mydb2"
slick.dbs.db2.db.user = "postgres"
slick.dbs.db2.db.password = "postgres"

How i can add changelog-master-db2.xml to added database?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.