From 86571409d1154ae1ecaac27ea866905f39e041f8 Mon Sep 17 00:00:00 2001 From: Charlie Fish Date: Wed, 19 Feb 2020 18:07:44 -0700 Subject: [PATCH 01/10] Formatting changes --- docs/api/Model.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/Model.md b/docs/api/Model.md index ed77a4252..3e1df674c 100644 --- a/docs/api/Model.md +++ b/docs/api/Model.md @@ -135,7 +135,7 @@ User.get({"id": 1, "name": "Tim"}, (error, myUser) => { }); ``` -### Model.create(document, [settings], [callback]) +## Model.create(document, [settings], [callback]) This function lets you create a new document for a given model. This function is almost identical to creating a new document and calling `document.save`, with one key difference, this function will default to setting `overwrite` to false. @@ -162,7 +162,7 @@ User.create({"id": 1, "name": "Tim"}, (error, user) => { // If a user with `id= }); ``` -### Model.update(keyObj[, updateObj],[ callback]) +## Model.update(keyObj[, updateObj],[ callback]) This function lets you update an existing document in the database. You can either pass in one object combining both the hashKey you wish to update along with the update object, or keep them separate by passing in two objects. From 5f99225c35b79dd37626aca9358f4ab72bb5965f Mon Sep 17 00:00:00 2001 From: Charlie Fish Date: Wed, 19 Feb 2020 18:07:57 -0700 Subject: [PATCH 02/10] Adding support for getting table creation request --- lib/Model.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/Model.js b/lib/Model.js index 8df54de75..633ea1e4a 100644 --- a/lib/Model.js +++ b/lib/Model.js @@ -49,7 +49,13 @@ function Model(name, schema, options = {}) { setupFlowPromise.then(() => this.ready = true).then(() => {this.pendingTasks.forEach((task) => task()); this.pendingTasks = [];}); this.Document = Document(this); - return this.Document; + const returnObject = this.Document; + returnObject.table = { + "create": { + "request": () => createTableRequest(this) + } + }; + return returnObject; } // Utility functions @@ -58,12 +64,14 @@ async function createTable(model) { return {"promise": () => Promise.resolve()}; } - const object = { + return aws.ddb().createTable(await createTableRequest(model)); +} +async function createTableRequest(model) { + return { "TableName": model.name, ...getProvisionedThroughput(model), ...await model.schema.getCreateTableAttributeParams() }; - return aws.ddb().createTable(object); } function getProvisionedThroughput(model) { if (model.options.throughput === "ON_DEMAND") { From 99456af73d972062f16edd4883d0163827b487b9 Mon Sep 17 00:00:00 2001 From: Charlie Fish Date: Wed, 19 Feb 2020 18:08:06 -0700 Subject: [PATCH 03/10] Adding documentation for get table creation request --- docs/api/Model.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/api/Model.md b/docs/api/Model.md index 3e1df674c..70e72fa7d 100644 --- a/docs/api/Model.md +++ b/docs/api/Model.md @@ -85,6 +85,39 @@ In order to revert to the default and remove custom defaults you can set it to a dynamoose.Model.defaults = {}; ``` +## Model.table.create.request() + +This function will return the object used to create the table with AWS. You can use this to create the table manually, for things like the Serverless deployment toolkit, or just to peak behind the scenes and see what Dynamoose is doing to create the table. + +This function is an async function so you must wait for the promise to resolve before you are able to access the result. + +```js +const User = dynamoose.Model("User", {"id": Number, "name": String}); + +async function printTableRequest() { + console.log(await User.table.create.request()); + // { + // "TableName": "User", + // "ProvisionedThroughput": { + // "ReadCapacityUnits": 5, + // "WriteCapacityUnits": 5 + // }, + // "AttributeDefinitions": [ + // { + // "AttributeName": "id", + // "AttributeType": "N" + // } + // ], + // "KeySchema": [ + // { + // "AttributeName": "id", + // "KeyType": "HASH" + // } + // ] + // } +} +``` + ## Model.get(hashKey[, callback]) You can use Model.get to retrieve a document from DynamoDB. This method uses the `getItem` DynamoDB API call to retrieve the object. From 10601f36129d8dc7dcd2952690a7285a1cfa8133 Mon Sep 17 00:00:00 2001 From: Charlie Fish Date: Wed, 19 Feb 2020 18:08:12 -0700 Subject: [PATCH 04/10] Adding tests for Model.table.create.request --- test/Model.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/Model.js b/test/Model.js index f797afa4a..fc5bfc6d1 100644 --- a/test/Model.js +++ b/test/Model.js @@ -1816,6 +1816,34 @@ describe("Model", () => { }); }); }); + + describe("Model.table.create.request", () => { + it("Should be a function", () => { + expect(new dynamoose.Model("User", {"id": String}).table.create.request).to.be.a("function"); + }); + + it("Should return correct result", async () => { + expect(await new dynamoose.Model("User", {"id": String}).table.create.request()).to.eql({ + "TableName": "User", + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + }, + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "KeySchema": [ + { + "AttributeName": "id", + "KeyType": "HASH" + } + ] + }); + }); + }); }); describe("model", () => { From 1ff199d78757fde06e5931aedc5c90343eefe3ba Mon Sep 17 00:00:00 2001 From: Charlie Fish Date: Wed, 19 Feb 2020 18:08:21 -0700 Subject: [PATCH 05/10] Adding Model.table.create.request to breaking changes --- BREAKING_CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BREAKING_CHANGES.md b/BREAKING_CHANGES.md index 674c0dd32..2abc4d2e2 100644 --- a/BREAKING_CHANGES.md +++ b/BREAKING_CHANGES.md @@ -9,3 +9,5 @@ - `$DELETE` now maps to the correct underlying DynamoDB method instead of the previous behavior of mapping to `$REMOVE` - `dynamoose.model` has been renamed to `dynamoose.Model` - `dynamoose.local` has been renamed to `dynamoose.aws.ddb.local` +- `Model.getTableReq` has been renamed to `Model.table.create.request` +- `Model.table.create.request` (formerly `Model.getTableReq`) is now an async function From 534a0e61baaa7328667902caa1d23e041d39311b Mon Sep 17 00:00:00 2001 From: Charlie Fish Date: Wed, 19 Feb 2020 18:08:52 -0700 Subject: [PATCH 06/10] Formatting changes --- test/Document.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Document.js b/test/Document.js index 4b0f91513..e40dda52d 100644 --- a/test/Document.js +++ b/test/Document.js @@ -79,7 +79,7 @@ describe("Document", () => { }); }); - describe("save", () => { + describe("document.save", () => { let User, user, putParams = [], putItemFunction; beforeEach(() => { Model.defaults = { From a62ed378dd496f1eaef32d3d22f1d3f78f2bcb36 Mon Sep 17 00:00:00 2001 From: Charlie Fish Date: Wed, 19 Feb 2020 18:20:32 -0700 Subject: [PATCH 07/10] Adding support for getting original document --- lib/Document.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/Document.js b/lib/Document.js index 1c516760b..34194a1ec 100644 --- a/lib/Document.js +++ b/lib/Document.js @@ -14,6 +14,8 @@ function DocumentCarrier(model) { const documentObject = Document.isDynamoObject(object) ? aws.converter().unmarshall({...object}) : object; Object.keys(documentObject).forEach((key) => this[key] = documentObject[key]); this[internalProperties] = {}; + this[internalProperties].originalObject = {...object}; + this[internalProperties].originalSettings = {...settings}; if (settings.fromDynamo) { this[internalProperties].storedInDynamo = true; @@ -258,6 +260,10 @@ function DocumentCarrier(model) { return this; }; + Document.prototype.original = function() { + return this[internalProperties].originalSettings.type === "fromDynamo" ? this[internalProperties].originalObject : null; + }; + Document.Model = model; // TODO: figure out if there is a better way to do this below. From d5edc43e0e10effee9702c1ab2289bd97f762c2f Mon Sep 17 00:00:00 2001 From: Charlie Fish Date: Wed, 19 Feb 2020 18:20:39 -0700 Subject: [PATCH 08/10] Adding tests for document.original --- test/Document.js | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/Document.js b/test/Document.js index e40dda52d..f9106f681 100644 --- a/test/Document.js +++ b/test/Document.js @@ -933,6 +933,35 @@ describe("Document", () => { }); }); + describe("document.original", () => { + let model; + beforeEach(() => { + model = new Model("User", {"id": Number}, {"create": false, "waitForActive": false}); + }); + afterEach(() => { + model = null; + }); + + it("Should be a function", () => { + expect(new model({}).original).to.be.a("function"); + }); + + it("Should return null if not retrieving from database", () => { + expect(new model({}).original()).to.eql(null); + }); + + it("Should return original object if retrieving from database", () => { + expect(new model({"id": 1}, {"type": "fromDynamo"}).original()).to.eql({"id": 1}); + }); + + it("Should return original object if retrieving from database even after modifying document", () => { + const document = new model({"id": 1}, {"type": "fromDynamo"}); + document.id = 2; + expect(document.original()).to.eql({"id": 1}); + expect({...document}).to.eql({"id": 2}); + }); + }); + describe("conformToSchema", () => { beforeEach(() => { Model.defaults = { From 34b53258abeed0d6faa8631d537b1dc266621a7c Mon Sep 17 00:00:00 2001 From: Charlie Fish Date: Wed, 19 Feb 2020 18:20:46 -0700 Subject: [PATCH 09/10] Adding documentation for document.original --- docs/api/Document.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/api/Document.md b/docs/api/Document.md index ee15049f6..f71fec4af 100644 --- a/docs/api/Document.md +++ b/docs/api/Document.md @@ -52,3 +52,16 @@ myUser.save((error) => { } }); ``` + +## document.original() + +This function returns the original item that was received from DynamoDB. This function will return a JSON object that represents the original item. In the event no item has been retrieved from DynamoDB `null` will be returned. + +```js +const user = await User.get(1); +console.log(user); // {"id": 1, "name": "Bob"} +user.name = "Tim"; + +console.log(user); // {"id": 1, "name": "Tim"} +console.log(user.original()); // {"id": 1, "name": "Bob"} +``` From 3ba8423f7245c1355b33e6fa0d7281888f89abc3 Mon Sep 17 00:00:00 2001 From: Charlie Fish Date: Wed, 19 Feb 2020 18:20:52 -0700 Subject: [PATCH 10/10] Adding breaking changes for document.original --- BREAKING_CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BREAKING_CHANGES.md b/BREAKING_CHANGES.md index 674c0dd32..5430e1c64 100644 --- a/BREAKING_CHANGES.md +++ b/BREAKING_CHANGES.md @@ -9,3 +9,5 @@ - `$DELETE` now maps to the correct underlying DynamoDB method instead of the previous behavior of mapping to `$REMOVE` - `dynamoose.model` has been renamed to `dynamoose.Model` - `dynamoose.local` has been renamed to `dynamoose.aws.ddb.local` +- `model.originalItem` has been renamed to `model.original` (or `Document.original`) +- `Document.original` formerly (`model.originalItem`) no longer returns the last item saved, but the item first retrieved from DynamoDB