まだknexで移行を行う方法がわかりません。これが私がこれまで持ってきたものです。 up
で機能しますが、foreign_key_checks = 0であってもdown
はFK制約エラーを表示します。
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;')
]);
};
jedd.ahyoungは正しいです。接続プールを1に制限する必要はありません。Promiseをチェーンして、並行して実行されないようにするだけです。
例えば:
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();
});
}
};
また、何か不足している可能性がありますが、メンバーテーブルの前にアドレステーブルを作成した場合は、外部キーチェックを削除して復元する必要がないようです。
最終的なコードは次のようになります。
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();
});
}
};
接続プールのために機能していないことがわかりました。別の接続を使用して各移行タスクを実行すると、外部キーチェックが正しく設定されませんでした。設定
pool:{
max:1
}
マイグレーション設定ファイルでこれを修正しました。
トランザクションを使用してこの問題を解決しました
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;');
});
});
};
}
移行ファイル
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);
inTable()
はreferences()
の後に配置する必要があります:
inTablecolumn.inTable(table)
column.references
を呼び出した後に外部キー列が配置されるtable
を設定します。
ドキュメント 。
これをかなり簡単にするJavascriptへの追加がいくつかあったので、私はこれを更新すると思いました。 knex
でもPromise
を返す必要がありますが、その内部ではPromise
を使用して、テーブルの作成/変更に関連するコードをクリーンアップできます。私の好みは、async
/await
と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);
}
})
}
各テーブルを個別に作成したい場合は、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);
}
})
}
これにより、一連のthen
sをデイジーチェーン接続したり、それらを周囲の関数にラップしたりする必要がなくなり、物事がよりクリーンに保たれます。解決するテーブルの作成ごとにawait
するだけで、カプセル化を解決してから解決しますPromise
! async
/await
!
down
マイグレーションでのテーブルのドロップについても、このパターンに従うことができます。 knex.schema.createTable
ステートメントをknex.schema.dropTable
ステートメントに置き換えるだけです。
主観的にそれを行う最もクリーンな方法として、次のようなものを移行ファイルに含めることをお勧めします。
exports.up = function (knex) {
return Promise.all([
knex.schema.createTable('users', function (table) {
table.increments('id')
table.string('username').notNullable()
table.string('password').notNullable()
table.string('service').notNullable()
table.text('cookies')
table.enu('status', ['active', 'disabled', 'need_login', 'failed']).defaultTo('need_login').notNullable()
table.datetime('last_checked')
table.timestamps()
}),
knex.schema.createTable('products', function (table) {
table.increments()
table.integer('user_id').unsigned().notNullable()
table.string('title')
table.decimal('price', 8, 2)
table.text('notes')
table.enu('status', ['to_publish', 'published', 'hidden', 'not_found']).notNullable()
table.timestamps()
table.foreign('user_id').references('id').inTable('users')
}),
knex.schema.createTable('messages', function (table) {
table.increments()
table.integer('user_id').unsigned().notNullable()
table.integer('product_id').unsigned().notNullable()
table.boolean('incoming')
table.boolean('unread')
table.text('text')
table.timestamps()
table.foreign('user_id').references('id').inTable('users')
table.foreign('product_id').references('id').inTable('products')
})
])
}
exports.down = function (knex) {
return Promise.all([
knex.schema.dropTable('messages'),
knex.schema.dropTable('products'),
knex.schema.dropTable('users')
])
}