web-dev-qa-db-fra.com

Comment faire les migrations knex.js?

Je ne sais toujours pas comment effectuer mes migrations avec knex. Voici ce que j'ai jusqu'à présent. Cela fonctionne sur up, mais down me donne une erreur de contrainte FK même si foreign_key_checks = 0.

exports.up = function(knex, Promise) {
  return Promise.all([
    knex.raw('SET foreign_key_checks = 0;'),

    /* CREATE Member table */
    knex.schema.createTable('Member', function (table) {
      table.bigIncrements('id').primary().unsigned();
      table.string('email',50);
      table.string('password');

      /* CREATE FKS */
      table.bigInteger('ReferralId').unsigned().index();
      table.bigInteger('AddressId').unsigned().index().inTable('Address').references('id');
    }),

    /* CREATE Address table */
    knex.schema.createTable('Address', function (table) {
      table.bigIncrements('id').primary().unsigned();
      table.index(['city','state','Zip']);

      table.string('city',50).notNullable();
      table.string('state',2).notNullable();
      table.integer('Zip',5).unsigned().notNullable();
    }),

    knex.raw('SET foreign_key_checks = 1;')
  ]);
};

exports.down = function(knex, Promise) {
  return Promise.all([
    knex.raw('SET foreign_key_checks = 0;'),

    knex.schema.dropTable('Address'),

    knex.schema.dropTable('Member'),

    knex.raw('SET foreign_key_checks = 1;')

  ]);
};
17
Eric Shell

jedd.ahyoung est correct. Vous n'avez pas besoin de limiter votre pool de connexions à 1. Vous devez simplement chaîner vos promesses pour qu'elles ne soient pas exécutées en parallèle.

Par exemple:

exports.up = function(knex, Promise) {
  return removeForeignKeyChecks()
    .then(createMemberTable)
    .then(createAddressTable)
    .then(addForeignKeyChecks);

  function removeForeignKeyChecks() {
    return knex.raw('SET foreign_key_checks = 0;');
  }

  function addForeignKeyChecks() {
    return knex.raw('SET foreign_key_checks = 1;');
  }

  function createMemberTable() {
    return knex.schema.createTable('Member', function (table) {
      table.bigIncrements('id').primary().unsigned();
      table.string('email',50);
      table.string('password');

      /* CREATE FKS */
      table.bigInteger('ReferralId').unsigned().index();
      table.bigInteger('AddressId').unsigned().index().inTable('Address').references('id');
    });
  }

  function createAddressTable() {
    return knex.schema.createTable('Address', function (table) {
      table.bigIncrements('id').primary().unsigned();
      table.index(['city','state','Zip']);

      table.string('city',50).notNullable();
      table.string('state',2).notNullable();
      table.integer('Zip',5).unsigned().notNullable();
    });
  }
};

Il se peut également que quelque chose me manque, mais il semblerait que vous n’ayez pas besoin de supprimer puis de rétablir les contrôles de clé étrangère si vous créez la table d’adresses avant la table de membres.

Voici à quoi ressemblerait le code final:

exports.up = function(knex, Promise) {
  return createAddressTable()
    .then(createMemberTable);

  function createMemberTable() {
    return knex.schema.createTable('Member', function (table) {
      table.bigIncrements('id').primary().unsigned();
      table.string('email',50);
      table.string('password');

      /* CREATE FKS */
      table.bigInteger('ReferralId').unsigned().index();
      table.bigInteger('AddressId').unsigned().index().inTable('Address').references('id');
    });
  }

  function createAddressTable() {
    return knex.schema.createTable('Address', function (table) {
      table.bigIncrements('id').primary().unsigned();
      table.index(['city','state','Zip']);

      table.string('city',50).notNullable();
      table.string('state',2).notNullable();
      table.integer('Zip',5).unsigned().notNullable();
    });
  }
};
10
nzhenry

Compris que cela ne fonctionnait pas à cause du regroupement des connexions. Il utiliserait une connexion différente pour exécuter chaque tâche de migration, ce qui empêcherait la définition correcte des contrôles de clé étrangère. réglage 

pool:{
  max:1
}

dans le fichier de configuration de la migration a résolu ce problème.

9
Eric Shell

J'ai résolu ce problème en utilisant une transaction

transation.js

module.exports = function transaction(fn) {
    return function _transaction(knex, Promise) {
        return knex.transaction(function(trx) {
            return trx
                .raw('SET foreign_key_checks = 0;')
                .then(function() {
                    return fn(trx, Promise);
                })
                .finally(function() {
                    return trx.raw('SET foreign_key_checks = 1;');
                });
        });
    };
}

Fichier de migration

var transaction = require('../transaction');

function up(trx, Promise) {
    return trx.schema
       .createTable('contract', function(table) {
           table.boolean('active').notNullable();                                              
           table.integer('defaultPriority').unsigned().references('priority.id');                             
           table.integer('defaultIssueStatus').unsigned().references('issueStatus.id');
           table.integer('owner').notNullable().unsigned().references('user.id'); 
       })

       .createTable('user', function (table) {
           table.increments('id').primary();
           table.datetime('createdAt');
           table.datetime('updatedAt');

           table.string('phoneNumber').notNullable().unique();
           table.string('password').notNullable();            
           table.string('name').notNullable().unique();       
           table.string('email');                             
           table.string('status');                            
           table.string('roles').defaultTo('user');           
           table.integer('contract').unsigned().references('contract.id');
       });
}

function down(trx, Promise) {
    return trx.schema
        .dropTable('contract')
        .dropTable('user');
}

exports.up = transaction(up);
exports.down = transaction(down);
4
Plasticut

Je pensais que je mettrais à jour ceci, car il y a eu quelques ajouts à Javascript qui facilitent un peu cette tâche knex nécessite toujours que vous retourniez un Promise mais à l'intérieur de celui-ci Promise, vous pouvez faire beaucoup de choses pour nettoyer le code lié à la création/modification de tables. Je préfère utiliser une combinaison de async/await et Promise.all.

exports.up = function(knex, Promise) {
    return new Promise(async (resolve, reject) => {
        try {
            await Promise.all([
                knex.schema.createTable('videos', table => {
                    table.increments('id');
                    table.string('title');
                    table.string('director');
                    table.json('meta');
                }),
                knex.schema.createTable('books', table => {
                    table.increments('id');
                    table.string('title');
                    table.string('author');
                    table.json('meta');
                })
            ]);

            console.log('Tables created successfully');
            resolve();
        } catch(error) {
            reject(error);
        }
    })
}

Si vous préférez créer chaque table individuellement, utilisez plutôt async/await.

exports.up = function(knex, Promise) {
    return new Promise(async (resolve, reject) => {
        try {
            await knex.schema.createTable('videos', table => {
                table.increments('id');
                table.string('title');
                table.string('director');
                table.json('meta');
            });
            console.log('videos table created successfully!');
            await knex.schema.createTable('books', table => {
                table.increments('id');
                table.string('title');
                table.string('author');
                table.json('meta');
            });
            console.log('books table created successfully!');
            resolve();
        } catch(error){
            reject(error);
        }
    })
}

Cela garde les choses beaucoup plus propres, ne vous obligeant pas à enchaîner une série de thens ou à les envelopper dans les fonctions environnantes. Il vous suffit await pour chaque création de table de résoudre, puis de résoudre leur encapsulation, Promise! Oui pour async/await!

Vous pouvez également suivre ce modèle pour la suppression de tables dans votre migration down. Remplacez simplement les instructions knex.schema.createTable par des instructions knex.schema.dropTable.

0
Hank Andre