From d39f539413a760aa9bb5de58a9b45c2291ac75ad Mon Sep 17 00:00:00 2001 From: Christian Enevoldsen Date: Tue, 20 Jan 2015 20:58:52 +0100 Subject: [PATCH 1/2] adds support for protected properties. --- lib/list.js | 4 +-- lib/model.js | 46 ++++++++++++++++++++++++------- test/model-definition.test.js | 51 ++++++++++++++++++++++++++++++----- 3 files changed, 84 insertions(+), 17 deletions(-) diff --git a/lib/list.js b/lib/list.js index 27c2a534..93bcb755 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, removeHidden) { +List.prototype.toObject = function (onlySchema, removeHidden, removeProtected) { var items = []; this.forEach(function (item) { if (item && typeof item === 'object' && item.toObject) { - items.push(item.toObject(onlySchema, removeHidden)); + items.push(item.toObject(onlySchema, removeHidden, removeProtected)); } else { items.push(item); } diff --git a/lib/model.js b/lib/model.js index 773e2c59..cf44d678 100644 --- a/lib/model.js +++ b/lib/model.js @@ -302,7 +302,7 @@ 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, removeHidden) { +ModelBaseClass.prototype.toObject = function (onlySchema, removeHidden, removeProtected) { if (onlySchema === undefined) { onlySchema = true; } @@ -334,11 +334,15 @@ ModelBaseClass.prototype.toObject = function (onlySchema, removeHidden) { continue; } + if (removeProtected && Model.isProtectedProperty(propertyName)) { + continue; + } + if (val instanceof List) { - data[propertyName] = val.toObject(!schemaLess, removeHidden); + data[propertyName] = val.toObject(!schemaLess, removeHidden, true); } else { if (val !== undefined && val !== null && val.toObject) { - data[propertyName] = val.toObject(!schemaLess, removeHidden); + data[propertyName] = val.toObject(!schemaLess, removeHidden, true); } else { data[propertyName] = val; } @@ -362,13 +366,16 @@ ModelBaseClass.prototype.toObject = function (onlySchema, removeHidden) { if (removeHidden && Model.isHiddenProperty(propertyName)) { continue; } + if (removeProtected && Model.isProtectedProperty(propertyName)) { + continue; + } val = self[propertyName]; if (val !== undefined && data[propertyName] === undefined) { if (typeof val === 'function') { continue; } if (val !== null && val.toObject) { - data[propertyName] = val.toObject(!schemaLess, removeHidden); + data[propertyName] = val.toObject(!schemaLess, removeHidden, true); } else { data[propertyName] = val; } @@ -386,16 +393,18 @@ ModelBaseClass.prototype.toObject = function (onlySchema, removeHidden) { if (removeHidden && Model.isHiddenProperty(propertyName)) { continue; } + if (removeHidden && Model.isProtectedProperty(propertyName)) { + continue; + } var ownVal = self[propertyName]; // The ownVal can be a relation function - val = (ownVal !== undefined && (typeof ownVal !== 'function')) - ? ownVal : self.__data[propertyName]; + val = (ownVal !== undefined && (typeof ownVal !== 'function')) ? ownVal : self.__data[propertyName]; if (typeof val === 'function') { continue; } if (val !== undefined && val !== null && val.toObject) { - data[propertyName] = val.toObject(!schemaLess, removeHidden); + data[propertyName] = val.toObject(!schemaLess, removeHidden, true); } else { data[propertyName] = val; } @@ -406,6 +415,25 @@ ModelBaseClass.prototype.toObject = function (onlySchema, removeHidden) { return data; }; +ModelBaseClass.isProtectedProperty = function (propertyName) { + var model = this; + var settings = Model.definition && Model.definition.settings; + var protectedProperties = settings & (settings.protectedProperties || settings.protected); + + if (Array.isArray(protectedProperties)) { + settings.protectedProperties = {}; + for (var i = 0; i < protectedProperties.length; i++) { + settings.protectedProperties[protectedProperties[i]] = true; + } + protectedProperties = settings.protectedProperties; + } + if (protectedProperties) { + return protectedProperties[propertyName]; + } else { + return false; + } +}; + ModelBaseClass.isHiddenProperty = function (propertyName) { var Model = this; var settings = Model.definition && Model.definition.settings; @@ -423,10 +451,10 @@ ModelBaseClass.isHiddenProperty = function (propertyName) { } else { return false; } -} +}; ModelBaseClass.prototype.toJSON = function () { - return this.toObject(false, true); + return this.toObject(false, true, false); }; ModelBaseClass.prototype.fromObject = function (obj) { diff --git a/test/model-definition.test.js b/test/model-definition.test.js index 342dfde3..c81f518d 100644 --- a/test/model-definition.test.js +++ b/test/model-definition.test.js @@ -36,9 +36,9 @@ describe('ModelDefinition class', function () { assert.equal(json.properties.approved.type, "Boolean"); assert.equal(json.properties.joinedAt.type, "Date"); assert.equal(json.properties.age.type, "Number"); - + assert.deepEqual(User.toJSON(), json); - + done(); }); @@ -55,7 +55,7 @@ describe('ModelDefinition class', function () { }); User.build(); - + var json = User.toJSON(); User.defineProperty("id", {type: "number", id: true}); @@ -64,12 +64,12 @@ describe('ModelDefinition class', function () { assert.equal(User.properties.approved.type, Boolean); assert.equal(User.properties.joinedAt.type, Date); assert.equal(User.properties.age.type, Number); - + assert.equal(User.properties.id.type, Number); - + json = User.toJSON(); assert.deepEqual(json.properties.id, {type: 'Number', id: true}); - + done(); }); @@ -270,6 +270,45 @@ describe('ModelDefinition class', function () { assert(grandChild.prototype instanceof child); }); + it('should serialize protected properties into JSON', function() { + var memory = new DataSoruce({connector: Memory}); + var modelBuilder = memory.modelBuilder; + var ProtectedModel = memory.createModel('protected', {}, { + protected: ['protectedProperty'] + }); + var pm = new ProtectedModel({ + id: 1, foo: 'bar', protectedProperty: 'protected' + }); + var serialized = pm.toJSON(); + assert.deepEqual(serialized, { + id: 1, foo: 'bar', protectedProperty: 'protected' + }); + }); + + it('should not serialized protected 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', {}, {protected: ['protectedProperty']}); + Parent.hasMany(Child); + Parent.create({ + name: 'parent' + }, function(err, parent) { + parent.children.create({ + name: 'child', + protectedProperty: 'protectedValue' + }, 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.protectedProperty, 'protectedValue'); + done(); + }); + }); + }); + }); + it('should not serialize hidden properties into JSON', function () { var memory = new DataSource({connector: Memory}); var modelBuilder = memory.modelBuilder; From 7372fafc976a5b927a2ad3fe2d385a42e73b0902 Mon Sep 17 00:00:00 2001 From: Christian Enevoldsen Date: Tue, 20 Jan 2015 21:32:31 +0100 Subject: [PATCH 2/2] Fixed typos and logic for protected properties --- lib/model.js | 9 +++++---- test/model-definition.test.js | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/model.js b/lib/model.js index cf44d678..3c39f2a6 100644 --- a/lib/model.js +++ b/lib/model.js @@ -321,6 +321,7 @@ ModelBaseClass.prototype.toObject = function (onlySchema, removeHidden, removePr var props = Model.definition.properties; var keys = Object.keys(props); var propertyName, val; + for (var i = 0; i < keys.length; i++) { propertyName = keys[i]; val = self[propertyName]; @@ -393,7 +394,7 @@ ModelBaseClass.prototype.toObject = function (onlySchema, removeHidden, removePr if (removeHidden && Model.isHiddenProperty(propertyName)) { continue; } - if (removeHidden && Model.isProtectedProperty(propertyName)) { + if (removeProtected && Model.isProtectedProperty(propertyName)) { continue; } var ownVal = self[propertyName]; @@ -416,11 +417,11 @@ ModelBaseClass.prototype.toObject = function (onlySchema, removeHidden, removePr }; ModelBaseClass.isProtectedProperty = function (propertyName) { - var model = this; + var Model = this; var settings = Model.definition && Model.definition.settings; - var protectedProperties = settings & (settings.protectedProperties || settings.protected); - + var protectedProperties = settings && (settings.protectedProperties || settings.protected); if (Array.isArray(protectedProperties)) { + // Cache the protected properties as an object for quick lookup settings.protectedProperties = {}; for (var i = 0; i < protectedProperties.length; i++) { settings.protectedProperties[protectedProperties[i]] = true; diff --git a/test/model-definition.test.js b/test/model-definition.test.js index c81f518d..9f394f05 100644 --- a/test/model-definition.test.js +++ b/test/model-definition.test.js @@ -271,7 +271,7 @@ describe('ModelDefinition class', function () { }); it('should serialize protected properties into JSON', function() { - var memory = new DataSoruce({connector: Memory}); + var memory = new DataSource({connector: Memory}); var modelBuilder = memory.modelBuilder; var ProtectedModel = memory.createModel('protected', {}, { protected: ['protectedProperty'] @@ -285,7 +285,7 @@ describe('ModelDefinition class', function () { }); }); - it('should not serialized protected properties of nested models into JSON', function(done){ + it('should not serialize protected properties of nested models into JSON', function(done){ var memory = new DataSource({connector: Memory}); var modelBuilder = memory.modelBuilder; var Parent = memory.createModel('parent');