Database Migration in Grails 2.x

La best-practice in questione riguarda il plugin database-migration per Grails. Il plugin si basa su Liquibase e si occupa di generare il DDL SQL riflettendo il domain model della nostra applicazione in Grails. E' ovvio che stiamo parlando di applicazioni Grails che utilizzando un database relazionale. In questo momento il plugin ha raggiunto la versione 3.0.3 e offre il pieno supporto a Grails 3.

Come opera il plugin

Il plugin si occupa di analizzare tutte le classi del nostro domain model e sulla base di questi, creare una lista di comandi SQL per la modellazione automatica delle nostre tabelle. Fin qui non c'è niente di nuovo rispetto alle funzionalità di base di jpa/hibernate incluse in Grails "vanilla". Il discorso cambia quando facciamo refactoring del nostro domain model. Aggiungere una proprietà, un nuovo vincolo o cambiare il tipo di una variabile, ci obbliga a metter mano al DB. Con questo plugin invece, si tiene traccia di tutte le modifiche (diff) del domain model che poi saranno replicate sul db in maniera sequenziale.

In parole povere è stata replicata 'as is' la funzionalità rake db:migrate di Rails. (Beh credo che sia ovvio che gRAILS sia una trasposizione in Groovy/JVM di Rails)

Let's GO!

1) Se stiamo utilizzando Grails 2.x dobbiamo innanzitutto includere il plugin nella nostra app modificando il `BuildConfig.groovy'

runtime ":database-migration:x.y.z"

Dopo aver importato il plugin nella nostra applicazione, avremo a disposizione una serie di task aggiuntivi, quelli che ci interessaranno di più saranno: dbm-create-changelog,dbm-generate-changelog, dbm-generate-gorm-changelog e dbm-gorm-diff.

2) Poichè sarà il plugin ad occuparsi di scrivere sul nostro database, dobbiamo evitare che lo faccia JPA/Hibernate. Quindi andremo a settare il flag dbCreate = "none"

enviroments {
    development {
        datasource {
            dbCreate = "none"
            [...]

3) Ora dobbiamo configurare il plugin all'interno del Config.groovy

grails.plugin.databasemigration.updateOnStart = true
grails.plugin.databasemigration.updateOnStartFileNames = ['changelog.groovy']

Abbiamo quindi deciso di eseguire l'update del DB ad ogni avvio della nostra app e di inserie tutte le diff nel file changelog.groovy

4) Inizializziamo il nonstro changelog ed eseguiamo il task dbm-create-changelog. Se utilizziamo la riga di comando, basterà eseguire nella root del progetto grails

grails dbm-create-changelog

Come risultato, troveremo una nuova directory /grails-app/migrations con all'intenrno il nostro changelog.groovy vuoto.

5) Ipotizzando che stiamo scrivendo un'app da zero, ora non ci resta che eseguire il seg. comando:

grails dbm-generate-changelog --add changelog-0.1.groovy

Cosi facendo abbiamo generato il file changelog-0.1.groovy che sarà aggiunto nella sequenza delle operazioni in changelog.groovy. Il file appena creato conterrà il DDL che replica lo stato attuale dei nostri domain model class.

6) D'ora in avanti se eseguiremo delle modifiche sulle nostre classi di domain, dovremo generare un nuovo changelog-0.x.groovy da appendere in changelog.groovy, per farlo il comando è

dbm-gorm-diff -add changelog-x.y.groovy

Dove x e y sono le versioni del nostro changelog e che vanno scelte in modo arbitrario.

7) Per trasferire su DB la struttura del nostro domain model non ci resta che eseguire il comando:

dbm-update

Et voilà! Il nostro DB seguirà fedelmente quanto scritto nelle domain class.

N.B. Non ho ancora testato il plugin in Grails 3. Ma la procedura è la stessa. I task sono richiamabili direttamente da Gradle e per quanto riguarda la configurazione, bisognerà rispettare la nuova convenzione all'interno del file application.yml.

A presto e Happy Coding!

LINK - DATABASE MIGRATION PLUGIN