Repository: dynamoosejs/dynamoose
Pull request #762 (2020-03-29 04:24:21)

Hide internal properties


Patch:
diff --git a/lib/Document.js b/lib/Document.js
index 9cf75661..263b885c 100644
--- a/lib/Document.js
+++ b/lib/Document.js
@@ -1,19 +1,21 @@
 const aws = require("./aws");
 const utils = require("./utils");
 const Error = require("./Error");
+const {internalProperties} = require("./Internal");
 
 // DocumentCarrier represents an internal concept in Dynamoose used to expose the model to documents that are created.
 // Without this things like `Document.save` wouldn't be able to access things like the TableName needed to save documents.
 // DocumentCarrier is not a concept that needs to be exposed to users of this library.
 function DocumentCarrier(model) {
-	const internalProperties = Symbol("internalProperties");
-
 	// Document represents an item in a Model that is either pending (not saved) or saved
 	class Document {
 		constructor(object = {}, settings = {}) {
 			const documentObject = Document.isDynamoObject(object) ? aws.converter().unmarshall(object) : object;
 			Object.keys(documentObject).forEach((key) => this[key] = documentObject[key]);
-			this[internalProperties] = {};
+			Object.defineProperty(this, internalProperties, {
+				"configurable": false,
+				"value": {}
+			});
 			this[internalProperties].originalObject = {...object};
 			this[internalProperties].originalSettings = {...settings};
 
diff --git a/lib/Internal.js b/lib/Internal.js
index 64e8662b..6e6002ce 100644
--- a/lib/Internal.js
+++ b/lib/Internal.js
@@ -1,5 +1,6 @@
 module.exports = {
 	"Schema": {
 		"internalCache": Symbol("internalCache")
-	}
+	},
+	"internalProperties": Symbol("internalProperties")
 };
diff --git a/lib/Schema.js b/lib/Schema.js
index 1b6d8d1e..29f4f49d 100644
--- a/lib/Schema.js
+++ b/lib/Schema.js
@@ -30,9 +30,12 @@ class Schema {
 		// Anytime `this.schemaObject` is modified, `this[internalCache].attributes` must be set to undefined or null
 		this.schemaObject = object;
 		this.settings = settings;
-		this[internalCache] = {
-			"getAttributeTypeDetails": {}
-		};
+		Object.defineProperty(this, internalCache, {
+			"configurable": false,
+			"value": {
+				"getAttributeTypeDetails": {}
+			}
+		});
 
 		const checkAttributeNameDots = (object/*, existingKey = ""*/) => {
 			return Object.keys(object).forEach((key) => {


Test patch:
diff --git a/test/Document.js b/test/Document.js
index 64c5f811..78e3393f 100644
--- a/test/Document.js
+++ b/test/Document.js
@@ -8,12 +8,20 @@ const Document = require("../lib/Document");
 const util = require("util");
 const Error = require("../lib/Error");
 const utils = require("../lib/utils");
+const Internal = require("../lib/Internal");
 
 describe("Document", () => {
 	it("Should be a function", () => {
 		expect(Document).to.be.an("function");
 	});
 
+	it("Should not have internalProperties if use spread operator on object", () => {
+		const User = new Model("User", {"id": Number, "name": String}, {"create": false, "waitForActive": false});
+		const user = new User({"id": 1, "name": "Bob"});
+		expect(user[Internal.internalProperties]).to.exist;
+		expect({...user}[Internal.internalProperties]).to.not.exist;
+	});
+
 	describe("DynamoDB Conversation Methods", () => {
 		let User;
 		beforeEach(() => {