javascript knex.js

javascript - ¿Cómo hacer las migraciones de knex.js?



(5)

Todavía no estoy seguro de cómo hacer mis migraciones con Knex. Esto es lo que tengo hasta ahora. Funciona en up , pero down me da un error de restricción FK aunque 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;'') ]); };


Descubrí que no estaba funcionando debido a la agrupación de conexiones. Se usaría una conexión diferente para ejecutar cada tarea de migración, lo que provocó que las comprobaciones de clave externa no se configuren correctamente. ajuste

pool:{ max:1 }

en el archivo de configuración de migración arreglado esto.


Pensé que actualizaría esto, ya que ha habido algunas adiciones a Javascript que lo hacen un poco más fácil. knex aún requiere que devuelvas una Promise pero dentro de esa Promise puedes hacer muchas cosas para limpiar el código relacionado con la creación / modificación de tablas. Mi preferencia es usar una combinación de async / Promise.all y 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 prefieres crear cada tabla individualmente, entonces solo uso 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); } }) }

Esto mantiene las cosas mucho más limpias, ya que no es necesario que encadene un montón de cosas ni las envuelva en las funciones adyacentes. ¡Solo await que la creación de cada tabla se resuelva y luego resuelva su Promise encapsulación! Yay por async / await !

También puede seguir este patrón para down tablas en su migración down . Simplemente reemplace las declaraciones knex.schema.dropTable con knex.schema.dropTable declaraciones knex.schema.dropTable .


Resolví este problema usando una transacción

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;''); }); }); }; }

Archivo de migración

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);


jedd.ahyoung es correcto. No necesita limitar su grupo de conexiones a 1. Solo necesita encadenar sus promesas para que no se ejecuten en paralelo.

Por ejemplo:

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(); }); } };

También es posible que me falte algo, pero parece que no tendrá que eliminar y luego restablecer las comprobaciones de clave externa si crea la tabla de direcciones antes que la tabla de miembros.

Así es como se vería el código 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(); }); } };


inTable() debe colocarse después de las references() :

inTablecolumn.inTable(table)

Establece la table donde se encuentra la columna de clave externa después de llamar a column.references .

Documentation