Search code examples
node.jsadonis.jsadonisjs-ace

Is there a way to squash migrations or baseline a database in Adonis Lucid?


I would like a way to generate migrations programmatically from an existing database in the Adonis ecosystem. Having to run 500 migrations, for example, during every test run is annoying and takes time, and I would like to squash migrations up to a certain point into one initial migration. Is there a way to do this in Adonis CLI? So far my research has concluded no, and I simply have to create an initial migration by hand to match the current state of the db which seems extremely error prone.


Solution

  • There is no official way.

    I had the same problem and decided to solve it by running all migrations on clean database and then exporting entire database dump to sql file which will be run as 1st migration like this:

    export default class NewVersion extends BaseSchema {
      public async up() {
        this.defer(async (db) => {
          const sql = await readFile(path.join(__dirname, '../versions/dumps/v1.0.0.sql'), 'utf-8')
          await db.rawQuery(sql)
        })
      }
    

    To keep everything organized I made folder structure like this: enter image description here

    This way I have access to all migrations if I need to check something specific.

    One more thing... My last migration in v0.0.0 was:

    import BaseSchema from '@ioc:Adonis/Lucid/Schema'

    export default class EndVersion extends BaseSchema {
      public async up() {
        this.defer(async (db) => {
          const lastBatch = await db.from('adonis_schema').orderBy('batch', 'desc').firstOrFail()
          await db.table('adonis_schema').insert({
            name: 'database/migrations/1644361478305_VERSION_1.0.0',
            batch: lastBatch.batch + 1,
          })
        })
      }
    
      public async down() {
        this.defer(async (db) => {
          await db
            .from('adonis_schema')
            .where('name', 'database/migrations/1644361478305_VERSION_1.0.0')
            .delete()
        })
      }
    }
    

    This migration sets new first migration (the sql dump one) as completed because I don't want it to run on database where I already have all migrations run.

    This way I have clean state of migrations on production server. And new migrations can continue to pile up.

    One more good this about this is that my from scratch migrations run was down from more then few minutes to 20ish seconds.