[英]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.