Skip to content

Commit

Permalink
fixed; compat w/ Object.create(null)
Browse files Browse the repository at this point in the history
fixes #1484
fixes #1485
  • Loading branch information
aheckmann committed May 14, 2013
1 parent edd1598 commit a0232f8
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 13 deletions.
10 changes: 7 additions & 3 deletions lib/document.js
Expand Up @@ -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 + '.');
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down
24 changes: 14 additions & 10 deletions lib/schema.js
Expand Up @@ -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]);
}
}
};
Expand Down Expand Up @@ -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"
Expand Down
141 changes: 141 additions & 0 deletions test/object.create.null.test.js
@@ -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.