Skip to content

Commit

Permalink
Support nullable timestamps on MySQL (#3100)
Browse files Browse the repository at this point in the history
* Add test to recreate the issue

* Improve test, add some documentation

* Improve test

* Add explicit nullable flag to column

* Set nullability explicitly on MySQL to deal with timestamp edge case

* Use same assertion for everything
  • Loading branch information
kibertoad authored and elhigu committed Mar 30, 2019
1 parent b15ee3d commit fe6083e
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/dialects/mysql/schema/columncompiler.js
Expand Up @@ -117,6 +117,13 @@ Object.assign(ColumnCompiler_MySQL.prototype, {
// ------

defaultTo(value) {
// MySQL defaults to null by default, but breaks down if you pass it explicitly
// Note that in MySQL versions up to 5.7, logic related to updating
// timestamps when no explicit value is passed is quite insane - https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_explicit_defaults_for_timestamp
if (value === null || value === undefined) {
return;
}

const defaultVal = ColumnCompiler_MySQL.super_.prototype.defaultTo.apply(
this,
arguments
Expand Down
3 changes: 3 additions & 0 deletions src/dialects/mysql/schema/tablecompiler.js
Expand Up @@ -97,6 +97,9 @@ assign(TableCompiler_MySQL.prototype, {

if (String(column.Null).toUpperCase() !== 'YES') {
sql += ` NOT NULL`;
} else {
// This doesn't matter for most cases except Timestamp, where this is important
sql += ` NULL`;
}
if (column.Default !== void 0 && column.Default !== null) {
sql += ` DEFAULT '${column.Default}'`;
Expand Down
24 changes: 24 additions & 0 deletions test/integration/migrate/index.js
Expand Up @@ -19,6 +19,30 @@ module.exports = function(knex) {
});

describe('knex.migrate', function() {
it('should not fail on null default for timestamp', () => {
return knex.migrate
.latest({
directory: 'test/integration/migrate/null_timestamp_default',
})
.then(() => {
return knex.into('null_date').insert({});
})
.then(() => {
return knex
.from('null_date')
.select()
.first();
})
.then((rows) => {
expect(rows.deleted_at).to.equal(null);
})
.then(() => {
return knex.migrate.rollback({
directory: 'test/integration/migrate/null_timestamp_default',
});
});
});

it('should not fail drop-and-recreate-column operation when using promise chain', () => {
return knex.migrate
.latest({
Expand Down
14 changes: 14 additions & 0 deletions test/integration/migrate/null_timestamp_default/01_create.js
@@ -0,0 +1,14 @@
exports.up = function(knex, Promise) {
return Promise.all([
knex.schema.createTable('null_date', function(t) {
t.increments('id').primary();
t.timestamp('deleted_at')
.nullable()
.defaultTo(null);
}),
]);
};

exports.down = (knex) => {
return knex.schema.dropTable('null_date');
};

0 comments on commit fe6083e

Please sign in to comment.