Expected:
When creating the updated_ts
column in table.timestamps()
, its DDL should be:
timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
Actual:
The ON UPDATE CURRENT_TIMESTAMP
part is missing - the updated_ts
column is never autoupdated.
The syntax I'm describing works for MySQL, I'm not sure how compatible across database engines it is.
At least with postgres syntax is not exactly that nice:
http://stackoverflow.com/questions/1035980/update-timestamp-when-row-is-updated-in-postgresql
Though I would like to have .autoUpdate()
builder method for timestamp
column, then it would be trivial to enable that for .timestamps()
helper too.
Looks like SQLite3 also has triggers which could be used to implement this. Oracle and mssql might have also some nicer syntax for it or at least it could be done with triggers.
This would be so nice! currently we need to depend on bookshelf updating our timestamps right?
Instead of relying on bookshelf you can create the datetime-fields manually (mysql):
table.dateTime('created_at').notNullable().defaultTo(knex.raw('CURRENT_TIMESTAMP'))
table.dateTime('updated_at').defaultTo(knex.raw('NULL ON UPDATE CURRENT_TIMESTAMP'))
Or if you prefer updated_at
to default to creation time as well:
table.dateTime('created_at').notNullable().defaultTo(knex.raw('CURRENT_TIMESTAMP'))
table.dateTime('updated_at').notNullable().defaultTo(knex.raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))
Instead of relying on bookshelf you can create the datetime-fields manually (mysql):
table.dateTime('created_at').notNullable().defaultTo(knex.raw('CURRENT_TIMESTAMP')) table.dateTime('updated_at').defaultTo(knex.raw('NULL ON UPDATE CURRENT_TIMESTAMP'))
Using the code you posted for updated_at with null default still inserts current timestamp for updated_at.
const UserModel = bookshelf.Model.extend({
tableName: 'users',
hasTimestamps: ['createdAt', 'updatedAt'],
});
This test fails:
it('doesntStoreUpdatedAtForCreation', async () => {
// arrange && act
const inserted = await new UserModel().save();
// assert
const retrievedModel = await UserModel.where({ id: inserted.id }).fetch();
assert.notExists(retrievedModel.get('updatedAt'));
});
Edit:
Nevermind, seems that completely removing hasTimestamps
from model definition fixes this.
We're mixing Knex and Bookshelf issues here, but @Ice32 if you don't want to use the automatic timestamp feature of Bookshelf, you have to remove hasTimestamps: ['createdAt', 'updatedAt']
from your model definition. The code that @codeclown posted above will then work as expected.
My Solution:
const Database = use("Database");
/*......*/
table
.timestamp("created_at")
.notNullable()
.defaultTo(Database.raw("CURRENT_TIMESTAMP"));
table
.timestamp("updated_at")
.notNullable()
.defaultTo(
Database.raw("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
);
I think timestamps()
needs to either provide this auto-update functionality or the docs need to explicitly state that it does not. I simply assumed that functionality was a critical reason for why the timestamps()
method exists at all.
The timestamps()
method is useless for me because can't set on update current_timestamp
.
Most helpful comment
I think
timestamps()
needs to either provide this auto-update functionality or the docs need to explicitly state that it does not. I simply assumed that functionality was a critical reason for why thetimestamps()
method exists at all.