Knex.JS 移行ツールを使用しています。ただし、テーブルを作成するときに、データベースでレコードが更新されると自動的に更新されるupdated_at
という名前の列が必要です。
たとえば、ここにテーブルがあります:
knex.schema.createTable('table_name', function(table) {
table.increments();
table.string('name');
table.timestamp("created_at").defaultTo(knex.fn.now());
table.timestamp("updated_at").defaultTo(knex.fn.now());
table.timestamp("deleted_at");
})
created_at
列とupdated_at
列のデフォルトは、レコードが作成された時刻ですが、これで問題ありません。しかし、そのレコードが更新されたときに、updated_at
列に、自動的に更新された新しい時刻を表示したいと考えています。
私は生のpostgresで書いたくない。
ありがとう!
ベニーの答えは完全に正しいです。しかし、私はあなたがPostgresに具体的に言及していることに気づきます。その場合、彼のknex.raw
構文はあなたのために機能しません。これが私がうまく使った方法です。
設定された順序で複数の移行ファイルがある場合、ファイル名の日付スタンプを人為的に変更して、これを最初に実行する(または最初の移行ファイルに追加する)必要がある場合があります。ロールバックできない場合は、psql
を使用してこの手順を手動で実行する必要があります。ただし、新しいプロジェクトの場合:
const ON_UPDATE_TIMESTAMP_FUNCTION = `
CREATE OR REPLACE FUNCTION on_update_timestamp()
RETURNS trigger AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$ language 'plpgsql';
`
const DROP_ON_UPDATE_TIMESTAMP_FUNCTION = `DROP FUNCTION on_update_timestamp`
exports.up = knex => knex.raw(ON_UPDATE_TIMESTAMP_FUNCTION)
exports.down = knex => knex.raw(DROP_ON_UPDATE_TIMESTAMP_FUNCTION)
これで、関数は後続のすべての移行で使用できるようになります。
knex.raw
トリガーヘルパーを定義する回避できる場合は、移行ファイルでSQLの大きなチャンクを繰り返さないほうが表現力があると思います。ここではknexfile.js
を使用しましたが、複雑にしたくない場合は、どこにでも定義できます。
module.exports = {
development: {
// ...
},
production: {
// ...
},
onUpdateTrigger: table => `
CREATE TRIGGER ${table}_updated_at
BEFORE UPDATE ON ${table}
FOR EACH ROW
EXECUTE PROCEDURE on_update_timestamp();
`
}
最後に、自動更新トリガーをかなり便利に定義できます。
const { onUpdateTrigger } = require('../knexfile')
exports.up = knex =>
knex.schema.createTable('posts', t => {
t.increments()
t.string('title')
t.string('body')
t.timestamps(true, true)
})
.then(() => knex.raw(onUpdateTrigger('posts')))
exports.down = knex => knex.schema.dropTable('posts')
テーブルを削除するだけでトリガーを取り除くことができます。明示的なDROP TRIGGER
は必要ありません。
これはすべて大変な作業のように思えるかもしれませんが、一度実行すればかなり簡単に設定でき、ORMの使用を避けたい場合には便利です。
timestamps を使用してknexマイグレーションを作成できます:
exports.up = (knex, Promise) => {
return Promise.all([
knex.schema.createTable('table_name', (table) => {
table.increments();
table.string('name');
table.timestamps(false, true);
table.timestamp('deleted_at').defaultTo(knex.fn.now());
})
]);
};
exports.down = (knex, Promise) => {
return Promise.all([
knex.schema.dropTableIfExists('table_name')
]);
};
timestamps の場合、created_at
列とupdated_at
列を追加するデータベーススキーマが作成され、それぞれに初期タイムスタンプが含まれます。
updated_at
列を最新に保つには、knex.raw
が必要です。
table.timestamp('updated_at').defaultTo(knex.raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
knex.raw
ソリューションをスキップするには、 Objection.js のような高レベルのORMを使用することをお勧めします。 Objection.js を使用すると、独自のBaseModel
を実装して、updated_at
列を更新できます。
Something.js
const BaseModel = require('./BaseModel');
class Something extends BaseModel {
constructor() {
super();
}
static get tableName() {
return 'table_name';
}
}
module.exports = Something;
BaseModel
const knexfile = require('../../knexfile');
const knex = require('knex')(knexfile.development);
const Model = require('objection').Model;
class BaseModel extends Model {
$beforeUpdate() {
this.updated_at = knex.fn.now();
}
}
module.exports = BaseModel;
これはKnexの機能ではありません。 Knexは列を作成するだけで、最新の状態に保ちません。
ただし、Bookshelf ORMを使用する場合は、テーブルにタイムスタンプがあることを指定でき、期待どおりに列を設定および更新します。
これはMysql 5.6+でそれを行う私の方法です
Table.timestampsを使用しなかった理由は、タイムスタンプではなくDATETIMEを使用しているためです。
table.dateTime('created_on')
.notNullable()
.defaultTo(knex.raw('CURRENT_TIMESTAMP'))
table.dateTime('updated_on')
.notNullable()
.defaultTo(knex.raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))