Repository: dynamoosejs/dynamoose
Pull request #718 (2020-02-21 00:36:57)

Model.delete


Patch:
diff --git a/docs/FAQ.md b/docs/FAQ.md
index 358745c7..9a9bbf79 100644
--- a/docs/FAQ.md
+++ b/docs/FAQ.md
@@ -12,6 +12,7 @@ The following is a chart of IAM permissions you need in order to run Dynamoose f
 | Model.query | `query` | This permission is only required on `query.exec` |
 | Model.create | `putItem` |  |
 | Model.update | `updateItem` |  |
+| Model.delete | `deleteItem` |  |
 | document.save | `putItem` |  |
 
 ## Why is it recommended to set `create` & `waitForActive` model options to false for production environments?
diff --git a/docs/api/Model.md b/docs/api/Model.md
index 70e72fa7..1f14c71b 100644
--- a/docs/api/Model.md
+++ b/docs/api/Model.md
@@ -250,3 +250,53 @@ await User.update({"id": 1}, {"name": "Bob", "$ADD": {"age": 1}});
 ```
 
 The `validate` Schema attribute property will only be run on `$SET` values. This is due to the fact that Dynamoose is unaware of what the existing value is in the database for `$ADD` properties.
+
+## Model.delete(hashKey[, callback])
+
+You can use Model.delete to delete a document from DynamoDB. This method uses the `deleteItem` DynamoDB API call to retrieve the object.
+
+This method returns a promise that will resolve when the operation is complete, this promise will reject upon failure. You can also pass in a function into the `callback` parameter to have it be used in a callback format as opposed to a promise format. In the event the operation was successful, noting will be returned to you. Otherwise an error will be thrown.
+
+```js
+const User = dynamoose.Model("User", {"id": Number, "name": String});
+
+try {
+	await User.delete(1);
+	console.log("Successfully deleted item");
+} catch (error) {
+	console.error(error);
+}
+
+// OR
+
+User.delete(1, (error) => {
+	if (error) {
+		console.error(error);
+	} else {
+		console.log("Successfully deleted item");
+	}
+});
+```
+
+In the event you have a rangeKey for your model, you can pass in an object for the `hashKey` parameter.
+
+```js
+const User = dynamoose.Model("User", {"id": Number, "name": {"type": String, "rangeKey": true}});
+
+try {
+	await User.get({"id": 1, "name": "Tim"});
+	console.log("Successfully deleted item");
+} catch (error) {
+	console.error(error);
+}
+
+// OR
+
+User.get({"id": 1, "name": "Tim"}, (error) => {
+	if (error) {
+		console.error(error);
+	} else {
+		console.log("Successfully deleted item");
+	}
+});
+```
diff --git a/lib/Model.js b/lib/Model.js
index 633ea1e4..33633c91 100644
--- a/lib/Model.js
+++ b/lib/Model.js
@@ -317,6 +317,21 @@ Model.prototype.update = function(keyObj, updateObj, callback) {
 	}
 };
 
+Model.prototype.delete = function (key, callback) {
+	const promise = this.pendingTaskPromise().then(() => aws.ddb().deleteItem({
+		"Key": this.Document.toDynamo(typeof key === "object" ? key : {
+			[this.schema.getHashKey()]: key
+		}),
+		"TableName": this.name
+	}).promise());
+
+	if (callback) {
+		promise.then(() => callback()).catch((error) => callback(error));
+	} else {
+		return promise;
+	}
+};
+
 Model.prototype.scan = {"carrier": require("./DocumentRetriever")("scan")};
 Model.prototype.query = {"carrier": require("./DocumentRetriever")("query")};
 


Test patch:
diff --git a/test/Model.js b/test/Model.js
index fc5bfc6d..9d021021 100644
--- a/test/Model.js
+++ b/test/Model.js
@@ -1817,6 +1817,82 @@ describe("Model", () => {
 		});
 	});
 
+	describe("Model.delete", () => {
+		let User, deleteItemParams, deleteItemFunction;
+		beforeEach(() => {
+			User = new dynamoose.Model("User", {"id": Number, "name": String});
+			dynamoose.aws.ddb.set({
+				"deleteItem": (params) => {
+					deleteItemParams = params;
+					return {"promise": deleteItemFunction};
+				}
+			});
+		});
+		afterEach(() => {
+			User = null;
+			deleteItemParams = null;
+			deleteItemFunction = null;
+			dynamoose.aws.ddb.revert();
+		});
+
+		it("Should be a function", () => {
+			expect(User.delete).to.be.a("function");
+		});
+
+		const functionCallTypes = [
+			{"name": "Promise", "func": (Model) => Model.delete},
+			{"name": "Callback", "func": (Model) => util.promisify(Model.delete)}
+		];
+		functionCallTypes.forEach((callType) => {
+			describe(callType.name, () => {
+				it("Should should send correct parameters to deleteItem", async () => {
+					deleteItemFunction = () => Promise.resolve();
+					await callType.func(User).bind(User)(1);
+					expect(deleteItemParams).to.be.an("object");
+					expect(deleteItemParams).to.eql({
+						"Key": {
+							"id": {
+								"N": "1"
+							}
+						},
+						"TableName": "User"
+					});
+				});
+
+				it("Should send correct params to deleteItem if we pass in an object", async () => {
+					deleteItemFunction = () => Promise.resolve();
+					await callType.func(User).bind(User)({"id": 1, "name": "Charlie"});
+					expect(deleteItemParams).to.be.an("object");
+					expect(deleteItemParams).to.eql({
+						"Key": {
+							"id": {
+								"N": "1"
+							},
+							"name": {
+								"S": "Charlie"
+							}
+						},
+						"TableName": "User"
+					});
+				});
+
+				it("Should throw error if error is returned from DynamoDB", async () => {
+					deleteItemFunction = () => Promise.reject({"error": "ERROR"});
+					let result, error;
+					try {
+						result = await callType.func(User).bind(User)({"id": 1, "name": "Charlie"});
+					} catch (e) {
+						error = e;
+					}
+					expect(result).to.not.exist;
+					expect(error).to.eql({
+						"error": "ERROR"
+					});
+				});
+			});
+		});
+	});
+
 	describe("Model.table.create.request", () => {
 		it("Should be a function", () => {
 			expect(new dynamoose.Model("User", {"id": String}).table.create.request).to.be.a("function");