[英]Knex.JS Auto Update Trigger
我正在使用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,你需要一個trigger 。 這是我成功使用的方法。
如果您有多個按設定順序排列的遷移文件,您可能需要人為地更改文件名中的日期戳以使其首先運行(或者只是將其添加到您的第一個遷移文件中)。 如果無法回滾,則可能需要通過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
但如果你不想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,它會很方便。
您可以使用時間戳創建 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')
]);
};
使用時間戳將創建一個數據庫模式,該模式添加一個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
列:
東西.js
const BaseModel = require('./BaseModel');
class Something extends BaseModel {
constructor() {
super();
}
static get tableName() {
return 'table_name';
}
}
module.exports = Something;
基礎模型
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;
這是我在 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'))
exports.up = (knex) => { return knex.raw( create or replace function table_name_update() RETURNS trigger AS $$ begin new.updated_at = now(); RETURN NEW; end; $$ language 'plpgsql'; create or replace trigger tg_table_name_update on table_name before update for each row execute table_name_update();
) };
exports.down = (knex) => { return knex.raw( drop table if exists table_name; drop function if exists table_name_update;
) };
可以直接使用這個功能
table.timestamps()
這將默認創建“created_at”和“updated_at”列並相應地更新它們
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.