Skip to content

Latest commit

 

History

History
 
 

example

Project Structure

A typical Scala-Forklift project is consist of several sub-projects, as shown in this tutorial. They are:

  • app is where your application code resides.
  • migrations stores all the migration scripts, and the tools to preview and apply migrations.
  • migration_manager is where customized migration manager is defined. There is also a tool to run some rescue commands, in case your code in migrations cannot be run or compiled.
  • generated_code is where the code generated by Slick Code Generator is stored. You should NOT modify or edit code in this sub-project.
  • tools is to provide other convenient tools. For now, there's only a tool to help users work with git.

A Quick Walkthrough

Project migrations contains the migration scripts and tools to apply these scripts. Simply launch sbt shell and enter:

migrations/run

This will gives you a list of available commands. Since this command could be used a lot during development, we have defined a shortcut in build.sbt:

addCommandAlias("mg", "migrations/run")

So you can enter the following command in your sbt shell:

mg init

This is equivalent to migrations/run init. This will make your database ready for migrations.

Your migration scripts are stored in directory migrations/src_migrations/main/scala, with the file named by numbers. For example, 1.scala creates the table users:

object M1 {
  MyMigrations.migrations = MyMigrations.migrations :+ SqlMigration(1)(List(
    sqlu"""create table "users" ("id" INTEGER NOT NULL PRIMARY KEY,"first" VARCHAR NOT NULL,"last" VARCHAR NOT NULL)"""
  ))
}

Both SQL queries and Slick statements can be used in a migration. Details will be discussed in the next section. For now, let's just apply these migrations by entering the following command in your sbt shell:

~mg migrate

This command will find all the not yet applied migrations, and try to apply them to your database. You should be able to see the following 3 migrations applied.

1 SqlMigration:
    [create table "users" ("id" INTEGER NOT NULL PRIMARY KEY,"first" VARCHAR NOT NULL,"last" VARCHAR NOT NULL)]

2 DBIOMigration:
    slick.driver.H2Driver.api.queryInsertActionExtensionMethods[datamodel.v1.schema.tables.Users#TableElementType, Seq](Users).++=(collection.Seq[datamodel.v1.schema.tables.UsersRow](UsersRow(1, "Chris", "Vogt"), UsersRow(2, "Stefan", "Zeiger")))

3 SqlMigration:
    [alter table "users" alter column "first" rename to "firstname" ]
    [alter table "users" alter column "last" rename to "lastname" ]

Alternatively, you can also use ~mg migrate -p to have Scala-Forklift ask for your confirmation before actually applying the migrations.

Congratulations! You have applied all the migration scripts. To see what's in current database, uncomment the code in app/src/main/scala/App.scala and enter the following command in your sbt shell:

app/run

You should be able to see something similar to this in the output:

Users in the database:
UsersRow(1,Chris,Vogt)
UsersRow(2,Yao,Li)

Migrations

The migrations are stored in the src_migrations directory in the migrations sub-project. You can use mg new s (for SQL migrations) or mg new d (for Slick migrations) to create a new migration file.

To apply these migrations, you must first copy them to the src directory. Entering mg update in your sbt shell will first unapplied migration files to the src directory. Then you can use mg preview to preview the migrations going to be applied, and mg apply to actually apply them.

The applied migrations could change the database schemas. In Scala-Forklift, it is recommended to use the source code generator (which uses the Slick source code generator) to generate the Scala model for you. Command mg codegen will generate the models for the latest database. The generated code resides in the generated_code sub-project.

However, using these commands in order for every migration could be unpleasant. Scala-Forklift provides a shortcut command ~mg migrate, which will run update, preview, apply, and codegen subsequently for you. In practice, it is recommended that you ALWAYS use ~mg migrate.

A migration can be written in plain SQL or Slick queries.

SQL Migrations

You can use mg new s to create a new SQL migration in your src_migrations directory.

By using the sqlu interpolator in Slick you can write plain SQL queries in your migrations, as shown in 1.scala:

object M1 {
  MyMigrations.migrations = MyMigrations.migrations :+ SqlMigration(1)(List(
    sqlu"""create table "users" ("id" INTEGER NOT NULL PRIMARY KEY,"first" VARCHAR NOT NULL,"last" VARCHAR NOT NULL)"""
  ))
}

Slick Migrations

Comparing with plain SQL queries, Slick queries are type-safe.

You can use mg new d to create a new Slick migration in your src_migrations directory.

A Slick migration can use the models generated by a previous migration. By convention, you should ALWAYS use code generated for the previous migration. For example, use datamodel.v1.schema.tables.Users in your 2.scala:

import slick.driver.H2Driver.api._
import com.liyaos.forklift.slick.DBIOMigration
import datamodel.v1.schema.tables.Users
import datamodel.v1.schema.tables.UsersRow

object M2 {
  MyMigrations.migrations = MyMigrations.migrations :+ DBIOMigration(2)(
    DBIO.seq(Users ++= Seq(
      UsersRow(1, "Chris","Vogt"),
      UsersRow(2, "Yao","Li")
    )))
}

Migration Manager

In project migration_manager, you can define your own migration manager and code generator.

Scala-Forklift provides a SlickMigrationManager to manage your slick migration scripts. To use SlickMigrationManager, add the following library dependency to your build.sbt in this project.

libraryDependencies += "com.liyaos" %% "scala-forklift-slick" % "0.2.3"

Then you can override original methods or define new methods for your migration manager here:

import com.liyaos.forklift.core.Migration
import com.liyaos.forklift.slick.SlickMigrationManager

trait MyMigrationManager extends SlickMigrationManager {
  // define your methods or override original methods here
}

Code Generator

Scala-Forklift for Slick provides a wrapper for Slick source code generator. You can also customize it in your migration_manager sub-project:

trait MyCodegen extends SlickCodegen {
  // change directory of generated file options here
  // override val generatedDir = ...
  // override val container = ...
  // override val fileName = ...
}

Git Tool

Scala-Forklift provides a git tool to help you manage your dev db with git. Check here for a detailed explanation.

Application

Your application code in app sub-project should look exactly like your other application code does not use Scala-Forklift, except that it does not contain the Scala code for your database models, but depends on the code generated by a source code generator (which is also a good practice when using Slick). Your application should depend on the generated_code sub-project, and import these models from datamodel.latest.schema.tables.

Troubleshooting

  • object v* is not a member of package datamodel, or not found: object datamodel: run mgm rescue to delete the generated files and unlink the migration files in src, and then run mg codegen to generate code for current database before entering ~mg migrate.