/scala-forklift-quill

A demonstration of using Scala-Forklift to support database migrations on Quill.

Primary LanguageScalaCreative Commons Zero v1.0 UniversalCC0-1.0

This is a simple demonstration of using Scala-Forklift to support database migrations on Quill. This demo still contains some hard code and unimplemented features, but it's sufficient to show how it works.

How to Use

Note : Don't directly compile the project in your sbt. If you haven't run any of the commands listed below, it will fail.

Clone this repo. Edit the database configuration in app/src/main/resources/application.conf to your database settings. Once it's done, enter sbt in the project root. Type the following command in your sbt:

> mg init
[info] Running MyMigrations init
[success] Total time: 1 s, completed

Then find the code in migrations/src/main/scala/Migrations.scala, uncomment the following code:

case class Migrations(id: Int)
lazy val lookupMigration = quote {
    query[Migrations].map(_.id)
}
lazy val applyMigration = quote {
    (id: Int) => query[Migrations].insert(_.id -> id)
}

override def alreadyAppliedIds = {
    db.run(lookupMigration)
}

def latest =
    if (alreadyAppliedIds.isEmpty) None
    else Some(alreadyAppliedIds.last)

override protected def up(migrations: Iterator[Migration[Int, Unit]]) {
    for (m <- migrations) {
        m.up
        db.run(applyMigration).using(List(m.id))
    }
}

And comment out the following code:

override def alreadyAppliedIds = List()

Back to your sbt, enter the following command:

> mg update
[info] Running MyMigrations update
create link to ./migrations/src/main/scala/migrations/1.scala for /path-to-quill-example/./migrations/src_migrations/main/scala/1.scala
[success] Total time: 0 s, completed
> mg apply
[info] Compiling 2 Scala sources to /path-to-quill-example/migrations/target/scala-2.11/classes...
[info] Running MyMigrations apply
applying migrations: 1
[success] Total time: 1 s, completed

This will execute the migration defined in migrations/src_migrations/main/scala/1.scala:

db.execute("create table `users` (`id` integer not null primary key, `name` varchar(255) not null)"))

Once the users table is created, you can run the application code:

> app/run
[info] Running Application
List()
[success] Total time: 0 s, completed

To add some data into this list, we need to execute the next migration defined in migrations/src_migrations/main/scala/2.scala:

val insert = quote {
    (id: Int, name: String) => query[Users].insert(_.id -> id, _.name -> name)
}
db.run(insert).using(List((1, "Harry Potter"),
    (2, "Ron Weasley"), (3, "Hermione Granger")))

Apply the migration in your sbt:

> mg update
[info] Running MyMigrations update
create link to ./migrations/src/main/scala/migrations/2.scala for /path-to-quill-example/./migrations/src_migrations/main/scala/2.scala
[success] Total time: 0 s, completed
> mg apply
[info] Compiling 2 Scala sources to /path-to-quill-example/migrations/target/scala-2.11/classes...
[info] /path-to-quill-example/migrations/src/main/scala/migrations/2.scala:12: INSERT INTO users (id,name) VALUES (?, ?)
[info]       db.run(insert).using(List((1, "Harry Potter"),
[info]             ^
[info] Running MyMigrations apply
applying migrations: 2
[success] Total time: 2 s, completed

Then checkout the application:

> app/run
[info] Running Application
List(Harry Potter, Ron Weasley, Hermione Granger)
[success] Total time: 0 s, completde

Challenges

Different with Slick, Quill uses probes to check if a database schema matches the Scala queries at compile time. This is why some code fragments in Migrations.scala has to be commentted out at first: migrations table was not created until mg init was executed.

This may not be a problem if this part of code was in the library, because it has already been compiled. However, this will still cause troubles when users want to extend the library.

Others

For more information on Scala-Forklift, please refer to https://github.com/lastland/scala-forklift. A more detailed example of using Slick can be found here: https://github.com/lastland/scala-forklift/tree/develop/example