Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Database migrations in Scala
David Geirola
David Geirola

Posted on • Edited on

     

Database migrations in Scala

https://github.com/geirolz/fly4s

The most famous library to handle database migrations in Java is for sure Flyway.
It works very well and the community edition has a lot of features as well.

Problem

Flyway APIs are written in the standard OOP paradigm, so throwing exceptions, manually managing resources, etc...

Solution

Fly4s is a lightweight, simple and functional wrapper for Flyway.
The aim ofFly4s is straightforward, wrapping theFlyway APIs in order to guarantee referential transparency, pureness, resource handling and type safety. To achieve this goal,Fly4s use the typelevel librariescats andcats-effect.

Getting started

The first step, import theFly4s library in our SBT project.
So, add the dependency in yourbuild.sbt file.
Fly4s depends on Flyway, so we'll have access to Flyway as well

(check the GitHub repo for the latest version)

libraryDependencies += "com.github.geirolz" %% "fly4s-core" % "0.0.4"
Enter fullscreen modeExit fullscreen mode

Migrations files

As the plain Flyway, we have to create a folder that will contain our migrations scripts, often inresources/db.

In this folder, we have to put all our migration. We can have:

For this example, we are going to use a simplebaseline migration to add a table to our database schema.

Baseline migrations are versioned and executed only when needed. The version is retrieved from the script file name.

So in this case,V001__create_user_table.sql, the version will be001(remember the double underscore afterV).

Here we have our first migration(for MySQL database)

resources/db/V001__create_user_table.sql

CREATETABLE`user`(`id`bigint(20)NOTNULLAUTO_INCREMENTPRIMARYKEY,`name`varchar(30)NOTNULL,`surname`varchar(30)NOTNULL);
Enter fullscreen modeExit fullscreen mode

Defining database configuration (optional)

A good practice is to create a case class to handle the database configuration(this combined with PureConfig or other config libraries makes your app very robust from the configuration point of view)

Let's create a simple case class to achieve this.

caseclassDatabaseConfig(url:String,user:Option[String],password:Option[Array[Char]],migrationsTable:String,migrationsLocations:List[String])
Enter fullscreen modeExit fullscreen mode

N.B. apart from the common fields suchurl,user andpassword we'll use:migrationsTable to define the Flyway table name(used to store the migration status) andmigrationsLocations to specify a list of the folders that contain our migration scripts.

Instantiating Fly4s

Ok so, now we have all our migration scripts in our folder(resources/db), we haveFly4s as a dependency of our project, and we have a case class that will contain the database configuration.

To instantiateFly4s we can usemake to create a new DataSource(under the hood) starting from the parameters ormakeFor in order to create it for an already existentDataSource(for example from Doobie HikariDataSource).
make andmakeFor method returns aResource type class that when released/interrupted safely close theDataSource connection.

In bothmake andmakeFor methods, we can specify the parameterconfig.Fly4sConfig is a trivial wrapper for flywayConfiguration but instead of having a builder, we have a case class.

valdbConfig:DatabaseConfig=???valfly4sRes:Resource[IO,Fly4s]=Fly4s.make[IO](url=dbConfig.url,user=dbConfig.user,password=dbConfig.password,config=Fly4sConfig(table=dbConfig.migrationsTable,locations=Location.of(dbConfig.migrationsLocations)))
Enter fullscreen modeExit fullscreen mode

Using Fly4s

Ok, we have done with the configuration!
We are ready to migrate our database schema with the power of Flyway and the safety of Functional Programming!

We can useuse orevalMap fromResource to safely access to the Fly4s instance. In case we have multipleResources in our application probablyevalMap allow us to better combine them using and release them all together at the same time.

We can create a simple utility method to do this

privatedefmigrateDb(dbConfig:DatabaseConfig):Resource[IO,Unit]=Fly4s.make[IO](url=dbConfig.url,user=dbConfig.user,password=dbConfig.password,config=Fly4sConfig(table=dbConfig.migrationsTable,locations=Location.of(dbConfig.migrationsLocations))).evalMap(fly4s=>for{_<-logger.debug(s"Applying migration for ${dbConfig.name}")migrationResult<-fly4s.validateAndMigrate[IO].result_<-logger.info(s" Applied ${migrationResult.migrationsExecuted} migrations to ${dbConfig.name} database")}yield())
Enter fullscreen modeExit fullscreen mode

Conclusions

We have done it! So, to recap, we have:

  1. Created a folder underresources to put our migrations(db)
  2. ImportedFly4s as a dependency in our project
  3. Created a configuration case class to describe our database configuration
  4. Instantiated aFly4s instance creating a newDataSource
  5. Migrated our database usingvalidateAndMigrate
  6. At the application shutdown/interruptionResource(from cats-effect) will safely release theDataSource

With a few lines, we have migrated our database safely handling the connection and the configuration.

As flyway, Fly4s provides multiple methods such as:

  • validateAndMigrate
  • migrate
  • undo
  • validate
  • clean
  • info
  • baseline
  • repair
Useful links

https://github.com/geirolz/fly4s
https://flywaydb.org/documentation
https://typelevel.org/cats/
https://typelevel.org/cats-effect/
https://pureconfig.github.io/

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Scala backend engineer at Codacy.Passionate about Functional Programming.
  • Location
    Italy
  • Work
    Backend Engineer at Permutive
  • Joined

More fromDavid Geirola

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp