nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: dynamoosejs/dynamoose
Pull request #751 (2020-03-21 21:24:27)

Undefined value
This PR has better support for setting a document attribute value to undefined.


Patch:
diff --git a/BREAKING_CHANGES.md b/BREAKING_CHANGES.md
index 0f5536a0..5d0e6e65 100644
--- a/BREAKING_CHANGES.md
+++ b/BREAKING_CHANGES.md
@@ -28,3 +28,4 @@
 - `List` attribute type has been replaced with `Array`
 - `Scan.null` & `Query.null` have been removed. In most cases this can be replaced with `.not().exists()`.
 - DynamoDB set types are now returned as JavaScript Set's instead of Array's
+- Trying to save a Document with a property set to `null` will now throw an error. If you would like to remove the property set it to `dynamoose.undefined` to set it to undefined without taking into account the `default` setting, or `undefined` to set it to undefined while taking into account the `default` setting.
diff --git a/lib/Document.js b/lib/Document.js
index 556eb60f..29b44534 100644
--- a/lib/Document.js
+++ b/lib/Document.js
@@ -111,6 +111,10 @@ function DocumentCarrier(model) {
 		const dynamooseUndefined = require("./index").undefined;
 		function mainCheck(finalObjectPre, key, value) {
 			const finalObject = {...finalObjectPre};
+			if (value === undefined) {
+				utils.object.set(finalObject, key, undefined);
+				return finalObject;
+			}
 			const genericKey = key.replace(/\d+/gu, "0"); // This is a key replacing all list numbers with 0 to standardize things like checking if it exists in the schema
 			const existsInSchema = model.schema.attributes().includes(genericKey);
 			const typeDetails = existsInSchema && model.schema.getAttributeTypeDetails(key);


Test patch:
diff --git a/test/Document.js b/test/Document.js
index 475b054f..a2a83a18 100644
--- a/test/Document.js
+++ b/test/Document.js
@@ -1287,6 +1287,21 @@ describe("Document", () => {
 				"output": {"id": 1, "name": "Charlie"},
 				"schema": {"id": Number, "name": String}
 			},
+			{
+				"input": [{"id": 1, "name": undefined}, {"defaults": true}],
+				"output": {"id": 1, "name": undefined},
+				"schema": {"id": Number, "name": String}
+			},
+			{
+				"input": [{"id": 1, "name": undefined}, {"defaults": true}],
+				"output": {"id": 1, "name": "Charlie"},
+				"schema": {"id": Number, "name": {"type": String, "default": "Charlie"}}
+			},
+			{
+				"input": [{"id": 1, "name": dynamoose.undefined}, {"defaults": true}],
+				"output": {"id": 1, "name": undefined},
+				"schema": {"id": Number, "name": {"type": String, "default": "Charlie"}}
+			},
 			// TODO: uncomment these lines below
 			// {
 			// 	"input": {"id": "1"},
Repository: dynamoosejs/dynamoose
Pull request #760 (2020-03-28 21:57:36)

Fixing bug where TTL/expires wouldn’t save as whole number


Patch:
diff --git a/lib/Schema.js b/lib/Schema.js
index e1929013..1b6d8d1e 100644
--- a/lib/Schema.js
+++ b/lib/Schema.js
@@ -222,7 +222,7 @@ Schema.prototype.getAttributeTypeDetails = function(key, settings = {}) {
 
 					const action = (val) => {
 						if (typeSettings.storage === "seconds") {
-							return val.getTime() / 1000;
+							return Math.round(val.getTime() / 1000);
 						} else {
 							return val.getTime();
 						}


Test patch:
diff --git a/test/Document.js b/test/Document.js
index 642ea43f..64c5f811 100644
--- a/test/Document.js
+++ b/test/Document.js
@@ -559,6 +559,14 @@ describe("Document", () => {
 					expect(parseInt(putParams[0].Item.ttl.N)).to.be.within(expectedTTL - 1000, expectedTTL + 1000);
 				});
 
+				it("Should store whole number for expires", async () => {
+					putItemFunction = () => Promise.resolve();
+					User = new Model("User", new Schema({"id": Number, "name": String}), {"create": false, "waitForActive": false, "expires": 10000});
+					user = new User({"id": 1, "name": "Charlie", "ttl": new Date(1002)});
+					await callType.func(user).bind(user)();
+					expect(parseFloat(putParams[0].Item.ttl.N) % 1).to.eql(0);
+				});
+
 				it("Should save with correct object with expires set to object", async () => {
 					putItemFunction = () => Promise.resolve();
 					User = new Model("User", new Schema({"id": Number, "name": String}), {"create": false, "waitForActive": false, "expires": {"attribute": "expires", "ttl": 10000}});
Repository: dynamoosejs/dynamoose
Pull request #830 (2020-04-19 21:49:13)

Model.transaction.condition now accepts condition instance


Patch:
diff --git a/docs/docs/api/Model.md b/docs/docs/api/Model.md
index a99d041a..ee06a486 100644
--- a/docs/docs/api/Model.md
+++ b/docs/docs/api/Model.md
@@ -704,11 +704,15 @@ You can pass in the same parameters into each method that you do for the normal
 
 These methods are only meant to only be called to instantiate the `dynamoose.transaction` array.
 
-### Model.transaction.condition(key, additionalParameters)
+### Model.transaction.condition(key, condition)
 
-This method allows you to run a conditionCheck when running a DynamoDB transaction.
+This method allows you to run a `conditionCheck` when running a DynamoDB transaction.
 
-The `additionalParameters` property will be appended to the result to allow you to set custom conditions.
+The `condition` parameter is a `dynamoose.Condition` instance that represents the conditional you want to run.
+
+```js
+User.transaction.condition(1, new dynamoose.Condition("age").gt(13));
+```
 
 ## Model.methods.set(name, function)
 
diff --git a/lib/Model/index.js b/lib/Model/index.js
index 0e51703e..d83adf0c 100644
--- a/lib/Model/index.js
+++ b/lib/Model/index.js
@@ -95,10 +95,10 @@ class Model {
 				delete response.ReturnValues;
 				return response;
 			}},
-			{"key": "condition", "settingsIndex": -1, "dynamoKey": "ConditionCheck", "function": (key, options) => ({
-				...options,
+			{"key": "condition", "settingsIndex": -1, "dynamoKey": "ConditionCheck", "function": (key, condition) => ({
 				"Key": this.Document.toDynamo(convertObjectToKey.bind(this)(key)),
-				"TableName": this.name
+				"TableName": this.name,
+				...(condition ? condition.requestObject() : {})
 			})}
 		].reduce((accumulator, currentValue) => {
 			const {key, modifier} = currentValue;


Test patch:
diff --git a/test/Model.js b/test/Model.js
index b2340ff6..28618c23 100644
--- a/test/Model.js
+++ b/test/Model.js
@@ -3184,12 +3184,28 @@ describe("Model", () => {
 				});
 			});
 
-			it("Should return correct result with options", async () => {
-				expect(await User.transaction.condition(1, {"hello": "world"})).to.eql({
+			it("Should return correct result for object based key", async () => {
+				User = dynamoose.model("User", {"id": Number, "name": {"type": String, "rangeKey": true}});
+				expect(await User.transaction.condition({"id": 1, "name": "Bob"})).to.eql({
 					"ConditionCheck": {
+						"Key": {"id": {"N": "1"}, "name": {"S": "Bob"}},
+						"TableName": "User"
+					}
+				});
+			});
+
+			it("Should return correct result with conditional", async () => {
+				expect(await User.transaction.condition(1, new dynamoose.Condition("age").gt(13))).to.eql({
+					"ConditionCheck": {
+						"ConditionExpression": "#a0 > :v0",
+						"ExpressionAttributeNames": {
+							"#a0": "age"
+						},
+						"ExpressionAttributeValues": {
+							":v0": {"N": "13"}
+						},
 						"Key": {"id": {"N": "1"}},
-						"TableName": "User",
-						"hello": "world"
+						"TableName": "User"
 					}
 				});
 			});
Repository: dynamoosejs/dynamoose
Pull request #728 (2020-03-10 23:17:13)

Document.isDynamoObject Empty Map Bug
There is a bug where an object (ex. `{"data": {"M": {}}}`) with an empty map being passed into `Document.isDynamoObject` returns `false` instead of the expected `true` value. This PR fixes that bug.


Patch:
diff --git a/lib/Document.js b/lib/Document.js
index 421fdb3a..59835a56 100644
--- a/lib/Document.js
+++ b/lib/Document.js
@@ -30,7 +30,7 @@ function DocumentCarrier(model) {
 			const keys = Object.keys(value);
 			const key = keys[0];
 			const nestedResult = (typeof value[key] === "object" && !(value[key] instanceof Buffer) ? (Array.isArray(value[key]) ? value[key].every((value) => Document.isDynamoObject(value, true)) : Document.isDynamoObject(value[key])) : true);
-			return typeof value === "object" && keys.length === 1 && utils.dynamodb.attribute_types.includes(key) && (nestedResult || utils.attribute_types.find((a) => a.dynamodbType === key).isSet);
+			return typeof value === "object" && keys.length === 1 && utils.dynamodb.attribute_types.includes(key) && (nestedResult || Object.keys(value[key]).length === 0 || utils.attribute_types.find((a) => a.dynamodbType === key).isSet);
 		}
 
 		const keys = Object.keys(object);


Test patch:
diff --git a/test/Document.js b/test/Document.js
index 7a3bcf40..73f50260 100644
--- a/test/Document.js
+++ b/test/Document.js
@@ -1124,6 +1124,14 @@ describe("Document", () => {
 			{
 				"input": {"id": {"N": "1"}, "friends": {"L": [{"S": "Tim"}, {"S": "Bob"}]}},
 				"output": true
+			},
+			{
+				"input": {"data": {"M": {}}},
+				"output": true
+			},
+			{
+				"input": {"data": {"L": []}},
+				"output": true
 			}
 		];
Repository: dynamoosejs/dynamoose
Pull request #737 (2020-03-20 00:13:38)

Empty document initializer bug


Patch:
diff --git a/lib/Document.js b/lib/Document.js
index 3850fd27..4db20eac 100644
--- a/lib/Document.js
+++ b/lib/Document.js
@@ -10,7 +10,7 @@ function DocumentCarrier(model) {
 
 	// Document represents an item in a Model that is either pending (not saved) or saved
 	class Document {
-		constructor(object, settings = {}) {
+		constructor(object = {}, settings = {}) {
 			const documentObject = Document.isDynamoObject(object) ? aws.converter().unmarshall({...object}) : object;
 			Object.keys(documentObject).forEach((key) => this[key] = documentObject[key]);
 			this[internalProperties] = {};


Test patch:
diff --git a/test/Document.js b/test/Document.js
index fb5fe023..cd04bfe2 100644
--- a/test/Document.js
+++ b/test/Document.js
@@ -922,6 +922,19 @@ describe("Document", () => {
 					}]);
 				});
 
+				it("Should work correctly if attributes added to document after initalization", async () => {
+					putItemFunction = () => Promise.resolve();
+					User = new Model("User", {"id": Number, "name": String}, {"create": false, "waitForActive": false});
+					user = new User();
+					user.id = 1;
+					user.name = "Charlie";
+					await callType.func(user).bind(user)();
+					expect(putParams).to.eql([{
+						"Item": {"id": {"N": "1"}, "name": {"S": "Charlie"}},
+						"TableName": "User"
+					}]);
+				});
+
 				it("Should throw error if object contains properties that have type mismatch with schema", () => {
 					putItemFunction = () => Promise.resolve();
 					User = new Model("User", {"id": Number, "name": String, "age": Number}, {"create": false, "waitForActive": false});
Repository: dynamoosejs/dynamoose
Pull request #738 (2020-03-20 03:23:42)

Fixing bug with falsey default attributes


Patch:
diff --git a/lib/Document.js b/lib/Document.js
index 4db20eac..a6e8576a 100644
--- a/lib/Document.js
+++ b/lib/Document.js
@@ -159,7 +159,8 @@ function DocumentCarrier(model) {
 					utils.object.set(returnObject, key, undefined);
 				} else {
 					const defaultValue = await model.schema.defaultCheck(key, value, settings);
-					if (defaultValue) {
+					const isDefaultValueUndefined = typeof defaultValue === "undefined" || defaultValue === null;
+					if (!isDefaultValueUndefined) {
 						const newObject = mainCheck({}, key, defaultValue);
 						utils.object.set(returnObject, key, utils.object.get(newObject, key));
 					}
diff --git a/lib/Schema.js b/lib/Schema.js
index 45683fe6..5694e061 100644
--- a/lib/Schema.js
+++ b/lib/Schema.js
@@ -79,7 +79,8 @@ Schema.prototype.defaultCheck = async function(key, value, settings) {
 	const isValueUndefined = typeof value === "undefined" || value === null;
 	if ((settings.defaults && isValueUndefined) || (settings.forceDefault && await this.getAttributeSettingValue("forceDefault", key))) {
 		const defaultValue = await this.getAttributeSettingValue("default", key);
-		if (defaultValue) {
+		const isDefaultValueUndefined = typeof defaultValue === "undefined" || defaultValue === null;
+		if (!isDefaultValueUndefined) {
 			return defaultValue;
 		}
 	}


Test patch:
diff --git a/test/Document.js b/test/Document.js
index cd04bfe2..7161748e 100644
--- a/test/Document.js
+++ b/test/Document.js
@@ -1344,6 +1344,11 @@ describe("Document", () => {
 				"output": {"id": "id"},
 				"schema": {"id": {"type": String, "default": async () => "id"}}
 			},
+			{
+				"input": [{}, {"defaults": true}],
+				"output": {"id": 0},
+				"schema": {"id": {"type": Number, "default": 0}}
+			},
 			{
 				"input": [{"id": "test"}, {"validate": true}],
 				"error": new Error.ValidationError("id with a value of test had a validation error when trying to save the document"),
Repository: dynamoosejs/dynamoose
Pull request #743 (2020-03-21 01:12:07)

Model.update Multiple Updates Race Condition
There was an issue where if passing in an object to update with update types (ex. `$SET`) and multiple updates inside of that one object type, there would be a race condition and the resulting request to DynamoDB would be corrupted and fail. This PR fixes that bug.


Patch:
diff --git a/lib/Model.js b/lib/Model.js
index d513289f..1097cd4f 100644
--- a/lib/Model.js
+++ b/lib/Model.js
@@ -292,7 +292,9 @@ Model.prototype.update = function(keyObj, updateObj, settings = {}, callback) {
 				key = "$SET";
 			}
 
-			await Promise.all(Object.keys(value).map(async (subKey) => {
+			const valueKeys = Object.keys(value);
+			for (let i = 0; i < valueKeys.length; i++) {
+				let subKey = valueKeys[i];
 				let subValue = value[subKey];
 
 				let updateType = updateTypes.find((a) => a.name === key);
@@ -331,7 +333,7 @@ Model.prototype.update = function(keyObj, updateObj, settings = {}, callback) {
 				accumulator.UpdateExpression[updateType.name.slice(1)].push(`${expressionKey}${operator}${expressionValue}`);
 
 				index++;
-			}));
+			}
 
 			return accumulator;
 		}, Promise.resolve((async () => {


Test patch:
diff --git a/test/Model.js b/test/Model.js
index d6dd754b..a9bf9048 100644
--- a/test/Model.js
+++ b/test/Model.js
@@ -1307,6 +1307,34 @@ describe("Model", () => {
 					});
 				});
 
+				it("Should send correct params to updateItem with $SET update expression and multiple property updates", async () => {
+					updateItemFunction = () => Promise.resolve({});
+					await callType.func(User).bind(User)({"id": 1}, {"$SET": {"name": "Charlie", "age": 5}});
+					expect(updateItemParams).to.be.an("object");
+					expect(updateItemParams).to.eql({
+						"ExpressionAttributeNames": {
+							"#a0": "name",
+							"#a1": "age"
+						},
+						"ExpressionAttributeValues": {
+							":v0": {
+								"S": "Charlie"
+							},
+							":v1": {
+								"N": "5"
+							}
+						},
+						"UpdateExpression": "SET #a0 = :v0, #a1 = :v1",
+						"Key": {
+							"id": {
+								"N": "1"
+							}
+						},
+						"TableName": "User",
+						"ReturnValues": "ALL_NEW"
+					});
+				});
+
 				it("Should send correct params to updateItem with $SET update expression for list", async () => {
 					updateItemFunction = () => Promise.resolve({});
 					User = new dynamoose.Model("User", {"id": Number, "friends": {"type": Array, "schema": [String]}});