Permalink
Browse files

fixed; compat w/ Object.create(null)

fixes #1484
fixes #1485
  • Loading branch information...
1 parent edd1598 commit a0232f8f8cb904edf87dfb83164a15955e429363 @aheckmann aheckmann committed May 14, 2013
Showing with 162 additions and 13 deletions.
  1. +7 −3 lib/document.js
  2. +14 −10 lib/schema.js
  3. +141 −0 test/object.create.null.test.js
View
@@ -267,7 +267,8 @@ function init (self, obj, doc, prefix) {
path = prefix + i;
schema = self.schema.path(path);
- if (!schema && obj[i] && 'Object' === obj[i].constructor.name) {
+ if (!schema && utils.isObject(obj[i]) &&
+ (!obj[i].constructor || 'Object' == obj[i].constructor.name)) {
// assume nested object
if (!doc[i]) doc[i] = {};
init(self, obj[i], doc[i], path + '.');
@@ -432,7 +433,9 @@ Document.prototype.set = function (path, val, type, options) {
key = keys[i];
pathtype = this.schema.pathType(prefix + key);
if (null != path[key]
- && 'Object' == path[key].constructor.name
+ // need to know if plain object - no Buffer, ObjectId, etc
+ && utils.isObject(path[key])
+ && (!path[key].constructor || 'Object' == path[key].constructor.name)
&& 'virtual' != pathtype
&& !(this.$__path(prefix + key) instanceof MixedSchema)) {
this.set(path[key], prefix + key, constructing);
@@ -455,7 +458,8 @@ Document.prototype.set = function (path, val, type, options) {
// docschema = new Schema({ path: { nest: 'string' }})
// doc.set('path', obj);
var pathType = this.schema.pathType(path);
- if ('nested' == pathType && val && 'Object' == val.constructor.name) {
+ if ('nested' == pathType && val && utils.isObject(val) &&
+ (!val.constructor || 'Object' == val.constructor.name)) {
if (!merge) this.setValue(path, null);
this.set(val, path, constructing);
return this;
View
@@ -186,21 +186,25 @@ Schema.prototype.defaultOptions = function (options) {
Schema.prototype.add = function add (obj, prefix) {
prefix = prefix || '';
- for (var i in obj) {
- if (null == obj[i]) {
- throw new TypeError('Invalid value for schema path `'+ prefix + i +'`');
+ var keys = Object.keys(obj);
+
+ for (var i = 0; i < keys.length; ++i) {
+ var key = keys[i];
+
+ if (null == obj[key]) {
+ throw new TypeError('Invalid value for schema path `'+ prefix + key +'`');
}
- if (obj[i].constructor.name == 'Object' && (!obj[i].type || obj[i].type.type)) {
- if (Object.keys(obj[i]).length) {
+ if (utils.isObject(obj[key]) && (!obj[key].constructor || 'Object' == obj[key].constructor.name) && (!obj[key].type || obj[key].type.type)) {
+ if (Object.keys(obj[key]).length) {
// nested object { last: { name: String }}
- this.nested[prefix + i] = true;
- this.add(obj[i], prefix + i + '.');
+ this.nested[prefix + key] = true;
+ this.add(obj[key], prefix + key + '.');
} else {
- this.path(prefix + i, obj[i]); // mixed type
+ this.path(prefix + key, obj[key]); // mixed type
}
} else {
- this.path(prefix + i, obj[i]);
+ this.path(prefix + key, obj[key]);
}
}
};
@@ -299,7 +303,7 @@ Schema.prototype.path = function (path, obj) {
*/
Schema.interpretAsType = function (path, obj) {
- if (obj.constructor.name != 'Object')
+ if (obj.constructor && obj.constructor.name != 'Object')
obj = { type: obj };
// Get the type making sure to allow keys named "type"
@@ -0,0 +1,141 @@
+
+
+/**
+ * Test dependencies.
+ */
+
+var start = require('./common')
+ , assert = require('assert')
+ , mongoose = start.mongoose
+ , DivergentArrayError = mongoose.Error.DivergentArrayError
+ , utils = require('../lib/utils')
+ , random = utils.random
+ , Schema = mongoose.Schema
+ , ObjectId = Schema.ObjectId
+
+var schema = new Schema({
+ a: String
+ , b: {
+ c: Number
+ , d: [{ e: String }]
+ }
+ , f: { g: Date }
+ , h: {}
+});
+
+describe('is compatible with object created using Object.create(null) (gh-1484)', function(){
+ var db;
+ var M;
+
+ before(function(){
+ db = start();
+ M = db.model('1484', schema);
+ })
+
+ after(function(done){
+ db.close(done);
+ })
+
+ it('during construction', function(done){
+ assert.doesNotThrow(function () {
+ new M(Object.create(null));
+ });
+
+ assert.doesNotThrow(function () {
+ var o = Object.create(null);
+ o.b = Object.create(null);
+ new M(o);
+ });
+
+ assert.doesNotThrow(function () {
+ var o = Object.create(null);
+
+ o.b = Object.create(null);
+ o.b.c = 9;
+
+ var e = Object.create(null);
+ e.e = 'hi i am a string';
+ o.b.d = [e];
+
+ var date = new Date;
+ var f = Object.create(null);
+ f.g = date;
+ o.f = f;
+
+ var h = Object.create(null);
+ h.ad = 1;
+ h.hoc = 2;
+ h.obj = Object.create(null);
+ o.h = h
+
+ var m = new M(o);
+
+ assert.equal(9, m.b.c);
+ assert.equal('hi i am a string', m.b.d[0].e);
+ assert.equal(date, m.f.g);
+ assert.equal(1, m.h.ad);
+ assert.equal(2, m.h.hoc);
+ assert.deepEqual({},m.h.obj);
+ });
+
+ done();
+ })
+
+ it('with .set(path, obj)', function(done){
+ var m = new M;
+
+ var b = Object.create(null);
+ b.c = 9;
+ m.set('b', b);
+
+ var ee = Object.create(null);
+ ee.e = 'hi i am a string';
+ var e = [ee];
+ m.set('b.d', e);
+
+ var date = new Date;
+ var f = Object.create(null);
+ f.g = date;
+ m.set('f', f);
+
+ var thing = Object.create(null);
+ thing.h = 'yes';
+ m.set('h.obj.thing', thing);
+
+ assert.equal(9, m.b.c);
+ assert.equal('hi i am a string', m.b.d[0].e);
+ assert.equal(date, m.f.g);
+ assert.deepEqual('yes', m.h.obj.thing.h);
+ done();
+ })
+
+ it('with schema', function(done){
+ var o = Object.create(null);
+ o.name = String;
+ o.created = Date;
+ o.nested = Object.create(null);
+ o.nested.n = Number;
+
+ assert.doesNotThrow(function () {
+ new Schema(o);
+ });
+
+ assert.doesNotThrow(function () {
+ var s = new Schema;
+ var o = Object.create(null);
+ o.yay = Number;
+ s.path('works', o);
+ });
+
+ assert.doesNotThrow(function () {
+ var s = new Schema;
+ var o = Object.create(null);
+ var o = {};
+ o.name = String;
+ var x = { type: [o] };
+ s.path('works', x);
+ });
+
+ done();
+ })
+})

0 comments on commit a0232f8

Please sign in to comment.