Handle null vals properly

When converting null values
to database column values,
return null if column is
nullable, otherwise try
to cast it to the property
type, and if not, return
'null'.
This commit is contained in:
biniam 2017-06-05 16:32:12 -04:00
parent 54e2aa9e26
commit 66dcf9b70d
2 changed files with 121 additions and 10 deletions

View File

@ -331,12 +331,26 @@ MySQL.prototype.getInsertedId = function(model, info) {
* @returns {*} The escaped value of DB column * @returns {*} The escaped value of DB column
*/ */
MySQL.prototype.toColumnValue = function(prop, val) { MySQL.prototype.toColumnValue = function(prop, val) {
if (val == null) { if (val === undefined && this.isNullable(prop)) {
if (prop.autoIncrement || prop.id) {
return new ParameterizedSQL('DEFAULT');
}
return null; return null;
} }
if (val === null) {
if (this.isNullable(prop)) {
return val;
} else {
try {
var castNull = prop.type(val);
if (prop.type === Object) {
return JSON.stringify(castNull);
}
return castNull;
} catch (err) {
//if we can't coerce null to a certain type,
//we just return it
return 'null';
}
}
}
if (!prop) { if (!prop) {
return val; return val;
} }

View File

@ -6,7 +6,7 @@
'use strict'; 'use strict';
var should = require('./init.js'); var should = require('./init.js');
var Post, PostWithStringId, PostWithUniqueTitle, db; var Post, PostWithStringId, PostWithUniqueTitle, PostWithNumId, db;
// Mock up mongodb ObjectID // Mock up mongodb ObjectID
function ObjectID(id) { function ObjectID(id) {
@ -41,13 +41,22 @@ describe('mysql', function() {
title: {type: String, length: 255, index: true}, title: {type: String, length: 255, index: true},
content: {type: String}, content: {type: String},
}); });
PostWithNumId = db.define('PostWithNumId', {
id: {type: Number, id: true, null: false},
title: {type: String, length: 255, null: false, index: true},
content: {type: String, null: false},
buffProp: {type: Buffer, null: false},
objProp: {type: Object, null: false},
arrProp: {type: [Number], null: false},
dateProp: {type: Date, null: false},
pointProp: {type: 'GeoPoint', null: false},
});
PostWithUniqueTitle = db.define('PostWithUniqueTitle', { PostWithUniqueTitle = db.define('PostWithUniqueTitle', {
title: {type: String, length: 255, index: {unique: true}}, title: {type: String, length: 255, index: {unique: true}},
content: {type: String}, content: {type: String},
}); });
db.automigrate(['PostWithDefaultId', 'PostWithStringId', 'PostWithUniqueTitle'], function(err) { db.automigrate(['PostWithDefaultId', 'PostWithStringId', 'PostWithUniqueTitle', 'PostWithNumId'], function(err) {
should.not.exist(err); should.not.exist(err);
done(err); done(err);
}); });
@ -56,9 +65,7 @@ describe('mysql', function() {
beforeEach(function(done) { beforeEach(function(done) {
Post.destroyAll(function() { Post.destroyAll(function() {
PostWithStringId.destroyAll(function() { PostWithStringId.destroyAll(function() {
PostWithUniqueTitle.destroyAll(function() { PostWithUniqueTitle.destroyAll(done);
done();
});
}); });
}); });
}); });
@ -424,6 +431,96 @@ describe('mysql', function() {
}); });
}); });
}); });
context('null vals in different operators', function() {
var defaultPost = {
id: 3,
title: 'defTitle',
content: 'defContent',
buffProp: new Buffer('defBuffer'),
objProp: {defKey: 'defVal'},
arrProp: [0],
dateProp: new Date('2017-06-14'),
pointProp: {lng: 4.51515, lat: 57.2314},
};
beforeEach(function(done) {
PostWithNumId.destroyAll(done);
});
after(function(done) {
PostWithNumId.destroyAll(done);
});
it('should handle null in inq operator', function(done) {
defaultPost.id = 1;
defaultPost.title = 'Foo';
defaultPost.content = 'Bar';
PostWithNumId.create(defaultPost, function(err, post) {
should.not.exist(err);
post.id.should.equal(defaultPost.id);
PostWithNumId.find({where: {id: {inq: [null, 1]}}}, function(err, posts) {
should.not.exist(err);
posts.length.should.equal(1);
posts[0].title.should.equal('Foo');
posts[0].id.should.equal(1);
done();
});
});
});
it('should handle null in nin operator', function(done) {
defaultPost.id = 2;
defaultPost.title = 'Make';
defaultPost.content = 'Toyota';
PostWithNumId.create(defaultPost, function(err, post) {
should.not.exist(err);
post.id.should.equal(defaultPost.id);
PostWithNumId.find({where: {id: {nin: [null, 3]}}}, function(err, posts) {
should.not.exist(err);
posts.length.should.equal(1);
posts[0].content.should.equal('Toyota');
posts[0].id.should.equal(2);
done();
});
});
});
it('should handle null in neq operator', function(done) {
defaultPost.id = 3;
defaultPost.title = 'Model';
defaultPost.content = 'Corolla';
PostWithNumId.create(defaultPost, function(err, post) {
should.not.exist(err);
post.id.should.equal(defaultPost.id);
PostWithNumId.find({where: {id: {neq: null}}}, function(err, posts) {
should.not.exist(err);
posts.length.should.equal(1);
posts[0].content.should.equal('Corolla');
posts[0].id.should.equal(3);
done();
});
});
});
it('should handle null in nin op for different datatypes', function(done) {
PostWithNumId.create(defaultPost, function(err, post) {
should.not.exist(err);
post.id.should.equal(defaultPost.id);
PostWithNumId.find({where: {and: [
{id: {nin: [null]}},
{title: {nin: [null]}},
{content: {nin: [null]}},
{buffProp: {nin: [null]}},
{objProp: {nin: [null]}},
{arrProp: {nin: [null]}},
{dateProp: {nin: [null]}},
{pointProp: {nin: [null]}},
]}}, function(err, posts) {
should.not.exist(err);
posts.length.should.equal(1);
posts[0].toObject().should.deepEqual(defaultPost);
done();
});
});
});
});
// The where object should be parsed by the connector // The where object should be parsed by the connector
it('should support where for count', function(done) { it('should support where for count', function(done) {