From aea5836569b08fb8f83fad27a5ca58bfa075b0b1 Mon Sep 17 00:00:00 2001 From: Ritchie Martori Date: Fri, 11 Apr 2014 11:39:57 -0700 Subject: [PATCH] Add hidden property support --- lib/list.js | 4 ++-- lib/model.js | 28 +++++++++++++++++++----- test/model-definition.test.js | 41 +++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 8 deletions(-) diff --git a/lib/list.js b/lib/list.js index 2a2da03a..3e6faa1e 100644 --- a/lib/list.js +++ b/lib/list.js @@ -72,11 +72,11 @@ List.prototype.push = function (obj) { return item; }; -List.prototype.toObject = function (onlySchema) { +List.prototype.toObject = function (onlySchema, removeHidden) { var items = []; this.forEach(function (item) { if (item.toObject) { - items.push(item.toObject(onlySchema)); + items.push(item.toObject(onlySchema, removeHidden)); } else { items.push(item); } diff --git a/lib/model.js b/lib/model.js index 3e57ee67..3a3b3999 100644 --- a/lib/model.js +++ b/lib/model.js @@ -234,22 +234,24 @@ ModelBaseClass.toString = function () { * * @param {Boolean} onlySchema Restrict properties to dataSource only. Default is false. If true, the function returns only properties defined in the schema; Otherwise it returns all enumerable properties. */ -ModelBaseClass.prototype.toObject = function (onlySchema) { +ModelBaseClass.prototype.toObject = function (onlySchema, removeHidden) { if(onlySchema === undefined) { onlySchema = true; } var data = {}; var self = this; + var Model = this.constructor; var strict = this.__strict; var schemaLess = (strict === false) || !onlySchema; this.constructor.forEachProperty(function (propertyName) { + if(removeHidden && Model.isHiddenProperty(propertyName)) return; if (self[propertyName] instanceof List) { - data[propertyName] = self[propertyName].toObject(!schemaLess); + data[propertyName] = self[propertyName].toObject(!schemaLess, removeHidden); } else if (self.__data.hasOwnProperty(propertyName)) { if (self[propertyName] !== undefined && self[propertyName] !== null && self[propertyName].toObject) { - data[propertyName] = self[propertyName].toObject(!schemaLess); + data[propertyName] = self[propertyName].toObject(!schemaLess, removeHidden); } else { data[propertyName] = self[propertyName]; } @@ -264,10 +266,11 @@ ModelBaseClass.prototype.toObject = function (onlySchema) { // If the property is not declared in the model definition, no setter will be // triggered to add it to __data for (var propertyName in self) { + if(removeHidden && Model.isHiddenProperty(propertyName)) continue; if(self.hasOwnProperty(propertyName) && (!data.hasOwnProperty(propertyName))) { val = self[propertyName]; if (val !== undefined && val !== null && val.toObject) { - data[propertyName] = val.toObject(!schemaLess); + data[propertyName] = val.toObject(!schemaLess, removeHidden); } else { data[propertyName] = val; } @@ -276,20 +279,33 @@ ModelBaseClass.prototype.toObject = function (onlySchema) { // Now continue to check __data for (propertyName in self.__data) { if (!data.hasOwnProperty(propertyName)) { + if(removeHidden && Model.isHiddenProperty(propertyName)) continue; val = self.hasOwnProperty(propertyName) ? self[propertyName] : self.__data[propertyName]; if (val !== undefined && val !== null && val.toObject) { - data[propertyName] = val.toObject(!schemaLess); + data[propertyName] = val.toObject(!schemaLess, removeHidden); } else { data[propertyName] = val; } } } } + return data; }; +ModelBaseClass.isHiddenProperty = function(propertyName) { + var Model = this; + var settings = Model.definition && Model.definition.settings; + var hiddenProperties = settings && settings.hidden; + if(hiddenProperties) { + return ~hiddenProperties.indexOf(propertyName); + } else { + return false; + } +} + ModelBaseClass.prototype.toJSON = function () { - return this.toObject(false); + return this.toObject(false, true); }; ModelBaseClass.prototype.fromObject = function (obj) { diff --git a/test/model-definition.test.js b/test/model-definition.test.js index a50d87d6..562e236e 100644 --- a/test/model-definition.test.js +++ b/test/model-definition.test.js @@ -242,5 +242,46 @@ describe('ModelDefinition class', function () { assert(anotherChild.prototype instanceof baseChild); }); + it('should not serialize hidden properties into JSON', function () { + var memory = new DataSource({connector: Memory}); + var modelBuilder = memory.modelBuilder; + var HiddenModel = memory.createModel('hidden', {}, { + hidden: ['secret'] + }); + var hm = new HiddenModel({ + id: 1, + foo: 'bar', + secret: 'secret' + }); + var serialized = hm.toJSON(); + assert.deepEqual(serialized, { + id: 1, + foo: 'bar' + }); + }); + + it('should not serialize hidden properties of nested models into JSON', function (done) { + var memory = new DataSource({connector: Memory}); + var modelBuilder = memory.modelBuilder; + var Parent = memory.createModel('parent'); + var Child = memory.createModel('child', {}, {hidden: ['secret']}); + Parent.hasMany(Child); + Parent.create({ + name: 'parent' + }, function(err, parent) { + parent.children.create({ + name: 'child', + secret: 'secret' + }, function(err, child) { + Parent.find({include: 'children'}, function(err, parents) { + var serialized = parents[0].toJSON(); + var child = serialized.children[0]; + assert.equal(child.name, 'child'); + assert.notEqual(child.secret, 'secret'); + done(); + }); + }); + }); + }); });