From 99597460f07445f02f175e9e2bd3caa9d3978e39 Mon Sep 17 00:00:00 2001 From: Eric Dowell Date: Tue, 8 Aug 2017 19:40:40 -0500 Subject: [PATCH] Use MySQL DEFAULT Clause/Constant (#319) * Adding ability to use MySQL DEFAULT clause Adding mysql.default option and documentation on special case for date. Adding unit tests for Default Clause. * Handle unsupported types, don't stringify numbers * Adding note about unsupported column types. * Update readme. --- README.md | 31 ++++++++++++++ lib/migration.js | 24 ++++++++++- test/migration.test.js | 91 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 144 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bebd1e8..bb411de 100644 --- a/README.md +++ b/README.md @@ -258,6 +258,37 @@ Use the `limit` option to alter the display width. Example: } ``` +### Default Clause/Constant +Use the `default` property to have MySQL handle setting column `DEFAULT` value. +```javascript +"status": { + "type": "string", + "mysql": { + "default": "pending" + } +}, +"number": { + "type": "number", + "mysql": { + "default": 256 + } +} +``` +For the date or timestamp types use `CURRENT_TIMESTAMP` or `now`: +```javascript +"last_modified": { + "type": "date", + "mysql": { + "default":"CURRENT_TIMESTAMP" + } +} +``` +**NOTE**: The following column types do **NOT** supported [MySQL Default Values](https://dev.mysql.com/doc/refman/5.7/en/data-type-defaults.html): +- BLOB +- TEXT +- GEOMETRY +- JSON + ### Floating-point types For Float and Double data types, use the `precision` and `scale` options to specify custom precision. Default is (16,8). For example: diff --git a/lib/migration.js b/lib/migration.js index f309df1..fc98f49 100644 --- a/lib/migration.js +++ b/lib/migration.js @@ -701,7 +701,7 @@ function mixinMigration(MySQL, mysql) { var p = this.getModelDefinition(model).properties[prop]; var line = this.columnDataType(model, prop) + ' ' + (this.isNullable(p) ? 'NULL' : 'NOT NULL'); - return line; + return columnDefault(p, line); }; // override this function from base connector to allow mysql connector to @@ -770,6 +770,28 @@ function mixinMigration(MySQL, mysql) { return dt; }; + function columnDefault(p, line) { + if (typeof p.type === 'undefined' || typeof p.type.name !== 'string') { + return line; + } + // Unsupported column types + if (['blob', 'json', 'text'].indexOf(p.type.name.toLowerCase()) !== -1) { + return line; + } + if (typeof p.mysql !== 'undefined' && p.mysql.default) { + var columnDefault = p.mysql.default; + if (typeof columnDefault === 'number') { + return line + ' DEFAULT ' + columnDefault; + } + if (typeof columnDefault === 'string') { + return line + ' DEFAULT ' + + (columnDefault.toUpperCase() === 'CURRENT_TIMESTAMP' || columnDefault.toLowerCase() === 'now' ? + 'CURRENT_TIMESTAMP' : '"' + columnDefault + '"'); + } + } + return line; + } + function columnType(p, defaultType) { var dt = defaultType; if (p.mysql && p.mysql.dataType) { diff --git a/test/migration.test.js b/test/migration.test.js index 227f06e..43eaf03 100644 --- a/test/migration.test.js +++ b/test/migration.test.js @@ -10,7 +10,7 @@ var platform = require('./helpers/platform'); var should = require('./init'); var Schema = require('loopback-datasource-juggler').Schema; -var db, UserData, StringData, NumberData, DateData, SimpleEmployee; +var db, UserData, StringData, NumberData, DateData, DefaultData, SimpleEmployee; var mysqlVersion; describe('migrations', function() { @@ -373,6 +373,84 @@ describe('migrations', function() { ], done); }); + it('should take on database default CURRENT_TIMESTAMP, boolean 0 and pending string for columns', function(done) { + DefaultData.create({}, function(err, obj) { + assert.ok(!err); + assert.ok(obj); + var now = new Date(); + DefaultData.findById(obj.id, function(err, found) { + now.setSeconds(0); + found.dateTime.setSeconds(0); + found.timestamp.setSeconds(0); + + assert.equal(found.dateTime.toGMTString(), now.toGMTString()); + assert.equal(found.timestamp.toGMTString(), now.toGMTString()); + assert.equal(found.isAdmin, '0'); + assert.equal(found.number, 256); + assert.equal(found.data, null); + assert.equal(found.text, null); + assert.equal(found.status, 'pending'); + done(); + }); + }); + }); + + it('DefaultData should have correct columns', function(done) { + getFields('DefaultData', function(err, fields) { + fields.should.be.eql({ + id: {Field: 'id', + Type: 'int(11)', + Null: 'NO', + Key: 'PRI', + Default: null, + Extra: 'auto_increment'}, + dateTime: {Field: 'dateTime', + Type: 'datetime', + Null: 'YES', + Key: '', + Default: 'CURRENT_TIMESTAMP', + Extra: ''}, + timestamp: {Field: 'timestamp', + Type: 'timestamp', + Null: 'YES', + Key: '', + Default: 'CURRENT_TIMESTAMP', + Extra: ''}, + isAdmin: {Field: 'isAdmin', + Type: 'tinyint(1)', + Null: 'YES', + Key: '', + Default: '0', + Extra: ''}, + number: {Field: 'number', + Type: 'int(10) unsigned', + Null: 'NO', + Key: 'MUL', + Default: '256', + Extra: ''}, + data: {Field: 'data', + Type: 'longtext', + Null: 'YES', + Key: '', + Default: null, + Extra: ''}, + text: {Field: 'text', + Type: 'varchar(1024)', + Null: 'YES', + Key: '', + Default: null, + Extra: ''}, + status: {Field: 'status', + Type: 'varchar(512)', + Null: 'YES', + Key: '', + Default: 'pending', + Extra: ''}, + }); + done(); + }); + }); + it('should allow both kinds of date columns', function(done) { DateData.create({ dateTime: new Date('Aug 9 1996 07:47:33 GMT'), @@ -503,6 +581,17 @@ function setup(done) { floater: {type: Number, dataType: 'double', precision: 14, scale: 6}, }); + DefaultData = db.define('DefaultData', { + dateTime: {type: Date, dataType: 'datetime', mysql: {default: 'now'}}, + timestamp: {type: Date, dataType: 'timestamp', mysql: {default: 'CURRENT_TIMESTAMP'}}, + isAdmin: {type: Boolean, mysql: {default: '0'}}, + number: {type: Number, null: false, index: true, unsigned: true, + dataType: 'int', mysql: {default: 256}}, + data: {type: Schema.JSON, dataType: 'longText', mysql: {default: 'Not Supported'}}, + text: {type: Schema.Text, dataType: 'varchar', limit: 1024, mysql: {default: 'Not Supported'}}, + status: {type: String, dataType: 'varchar', mysql: {default: 'pending'}}, + }); + DateData = db.define('DateData', { dateTime: {type: Date, dataType: 'datetime'}, timestamp: {type: Date, dataType: 'timestamp'},