Search code examples
javaclojurejvmflyway

Clojure: How to run complex DB migration in production?


Imagine you have a task to perform a complex DB migration as part of a new version release into production, how would you usually do it in a Clojure project?

An example for a new "big" release, migrations:

  • V1__create_new_tables (easy, just use vanilla SQL with CREATE TABLE)
  • V2__perform_complex_migration (CREATE TABLE foo, loop through another table and fill in new foo table with some data using custom Clojure code)
  • V3__do_something_else (easy, could be another simple SQL query

How would you do that 2nd migration in an automated way? All 3 migrations have to be executed in order for a new release to be successful.

Looks like Flyway DB has Java migrations which looks like exactly what is needed but is there any way to use it from Clojure?

Perhaps one can add another .clj file along with other .sql migrations and Flyway would pick it up?

I'm a bit surprised I can't any examples for what seems like a very common task in Clojure, only simple SQL queries.


Solution

  • Quoting Migratus README:

    Defining a code-based migration

    Create a code-based migration by adding a .edn file to your migrations directory that contains the namespace and up/down functions to run, e.g. resources/migrations/20170331141500-import-users.edn:

    {:ns app.migrations.import-users
     :up-fn migrate-up
     :down-fn migrate-down} 
    

    Then, in src/app/migrations/import_users.clj:

    (ns app.migrations.import-users)
    
    (defn migrate-up [config]
    ;; do stuff here
    )
    
    (defn migrate-down [config]    
    ;; maybe undo stuff here
    ) 
    

    The up and down migration functions should both accept a single parameter, which is the config map passed to Migratus (so your migrations can be configurable). You can omit the up or down migration by setting :up-fn or down-fn to nil in the EDN file.