Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support data migrations #53

Closed
nrempel opened this issue Sep 29, 2016 · 15 comments
Closed

Support data migrations #53

nrempel opened this issue Sep 29, 2016 · 15 comments
Assignees

Comments

@nrempel
Copy link

nrempel commented Sep 29, 2016

Currently, Adonis only supports schema migrations which only modify the schema of the database.

It would be convenient to also be able to run data migrations which modify the contents of the database.

I can already do this by using the Database provider in a migration but it seems out of place and I can't use co.

@nrempel nrempel changed the title Support data migrations as well as schema migrations Support data migrations Sep 29, 2016
@thetutlage
Copy link
Member

@nrempel I was think of something like

this.table('users', function () {
})

this.db(function * (database) {
  yield database.from('users').select('name')
})

@thetutlage thetutlage self-assigned this Sep 30, 2016
@nrempel
Copy link
Author

nrempel commented Sep 30, 2016

That looks 👌

@nrempel
Copy link
Author

nrempel commented Sep 30, 2016

🎉

@RomainLanz
Copy link
Member

So if we want to migrate data and then remove a field we should do?

this.table('users', function () {
  // add the new columns
})

this.db(function * (database) {
  // migrate the data
})

this.table('users', function () {
  // remove the old column
})

@nrempel
Copy link
Author

nrempel commented Sep 30, 2016

That looks correct to me @RomainLanz. You could also break it out into several migration files too if you want.

@thetutlage I've tested this in my system and everything looks to be working correctly. 👍

@nrempel
Copy link
Author

nrempel commented Oct 3, 2016

@thetutlage so far this is working really well.

One awkward thing is working with transactions.

this.db(function * (database) {


database.transaction(function(trx) {

  var books = [
    {title: 'Canterbury Tales'},
    {title: 'Moby Dick'},
    {title: 'Hamlet'}
  ];

  database.insert({name: 'Old Books'}, 'id')
    .into('catalogues')
    .transacting(trx)
    .then(function(ids) {
      return Promise.map(books, function(book) {
        book.catalogue_id = ids[0];

        // Some validation could take place here.

        return database.insert(info).into('books').transacting(trx);
      });
    })
    .then(trx.commit)
    .catch(trx.rollback);
})


})

I wonder if it's possible to facilitate the use of transactions?

Something like:

database.transaction(function * (trx) {
  yield database.insert({name: 'Old Books'}, 'id')
    .into('catalogues')
    .transacting(trx)
});

Or possibly even (not sure if this is possible):

const trx = yield database.transaction();
yield database.insert({name: 'Old Books'}, 'id')
  .into('catalogues')
  .transacting(trx)

@thetutlage
Copy link
Member

@nrempel
Copy link
Author

nrempel commented Oct 3, 2016

Amazing! thanks.

thetutlage added a commit that referenced this issue Jul 16, 2017
this.db will allow to execute database actions using the database provider

Closes #53
@dustinboss
Copy link

@thetutlage has this functionality been removed in Adonis 4? I'm struggling to get the migration to wait for some data to be migrated. I want to do this:

  1. Create a table
  2. Move some data around
  3. Drop a column on a table

I'm not sure the best way to do this. If I just use an async up call, the migration runs, but the migration action never terminates -- the connection just hangs.

@thetutlage
Copy link
Member

Mind sharing some code :)

@dustinboss
Copy link

dustinboss commented Jan 3, 2018

@thetutlage - I've created a simple example, which show my struggle.

Example 1: Using an async up call. The data migration happens before the photos table is created.

async up () {
  // Create a new table
  this.create('photos', (table) => {
    this.increments()
    this.string('url')
  })
  
  // Move some data
  const photos = await use('App/Models/User').query().where('photo_url', '>', '')
  const photosData = photos.map((record) => {
    return { 
      url: record.photo_url
    })
  await use('App/Models/Photo').createMany(photosData)
  
  // Modify another table
  this.table('users', (table) => {
    table.dropColumn('photo_url')
  })
}

Example 2: I move the data migration into the closure that will modify the second table. This waits until the first table is created, but the second table never ends up getting modified, and the migration script never terminates itself. It completes the migration, but the command doesn't terminate.

up () {
  // Create a new table
  this.create('photos', (table) => {
    this.increments()
    this.string('url')
  })
  
  // Modify another table
  this.table('users', async (table) => {
  
    // Move some data 
    const photos = await use('App/Models/User').query().where('photo_url', '>', '')
    const photosData = photos.map((record) => {
      return { 
        url: record.photo_url
      })
    await use('App/Models/Photo').createMany(photosData)
    
    // now modify the table
    table.dropColumn('photo_url')
  })
}

Example 3: I put the data migration in it's own closure (using a table closure, because the this.db doesn't seem to be available in Adonis 4 -- or at least I can't find it. This doesn't fire in sequence. The third function doesn't wait for the second function.

async up () {
  // Create a new table
  this.create('photos', (table) => {
    this.increments()
    this.string('url')
  })
  
  // Put the data migration in a closure, so it'll be queued with the other migrations
  this.table('photos', async (table) => {
    // Move some data 
    const photos = await use('App/Models/User').query().where('photo_url', '>', '')
    const photosData = photos.map((record) => {
      return { 
        url: record.photo_url
      })
    await use('App/Models/Photo').createMany(photosData)
  })

  // Modify another table
  this.table('users', (table) => {
    table.dropColumn('photo_url')
  })
}

@dustinboss
Copy link

@thetutlage - Any thoughts on this? If it's not possible, then I can sort out another way. Thanks!

@thetutlage
Copy link
Member

@dusbuss Sorry for getting late. Also I recommend creating new issues, since at times closed issues are missed.

I have add a new commit, which let you run arbitrary code in the same sequence as you have wrote code.

Here's the commit for that and related docs.

Would you mind trying it by installing from Github and lemme know, then I will publish it on npm

@thetutlage thetutlage reopened this Jan 9, 2018
@dustinboss
Copy link

@thetutlage - awesome! I just installed, and it works like a dream! Thank you!

@usmanalicc
Copy link

I installed it on MySQL Workbench 8.0 but it don't show any catalog in tool, but the plugin has been installed, how can I work with him? Catalog menu/sub menu is not showing in tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants