Skip to content

mongo updateimpl: check update, not field for updates #2729

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 22, 2023

Conversation

benjones
Copy link
Contributor

I'm not sure about this fix since I'm not at all a mongo expert, but this does seem in line with the documentation for what update commands should look like. Figured this was a good starting point.

@benjones
Copy link
Contributor Author

Related to this: https://forum.dlang.org/post/abszouhaybgstqdbatyl@forum.dlang.org

@WebFreak001 seems like you probably know this part of the code better than anyone else

@WebFreak001
Copy link
Contributor

WebFreak001 commented Apr 22, 2023

ah thank you! Actually it looks like the entire check before that is useless then, since it should warn the developer if they do something wrong. And if it only runs on the query and not on the replacement, there is no point to it. It should also use the ubson instead of qbson.

Can you maybe also add a MongoDB test for this? (there is a test folder that runs tests with multiple different MongoDB versions)

@benjones
Copy link
Contributor Author

To be clear the "mustBeDocument" check is useless? I honestly know very little about the mongo stuff :)

Yeah, I can add a test. I think this means that there's no tests for the mongo session store, since it uses a very similar updateOne call to my issue

@benjones benjones force-pushed the mongofix branch 2 times, most recently from 09e124a to 676b570 Compare April 26, 2023 04:49
@benjones
Copy link
Contributor Author

I added a test, but either I didn't fix the issue, or I wrote the test wrong... any ideas?

@@ -157,6 +157,21 @@ int main(string[] args)
.map!(c => c["name"].get!string)
.equal(["collection"]));

auto options = UpdateOptions();
options.upsert = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you forgot to pass the options to the updateOne command, so it never upserts!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ugh, thank you. Tests not quite ready, but that should get me unstuck.

@benjones benjones force-pushed the mongofix branch 2 times, most recently from 570a7d0 to d914506 Compare April 26, 2023 16:40
@benjones
Copy link
Contributor Author

OK, now it looks like the collections.d line 386 is expecting the wrong format for upsert responses. It looks like it expects an array of IDs, and it's actually getting an array of objects with an ID field... I'm assuming that's also untested/out of date and I should fix it?

@benjones benjones force-pushed the mongofix branch 6 times, most recently from 0b99004 to a308323 Compare April 28, 2023 02:35
@benjones
Copy link
Contributor Author

OK, I think this is good to go. it worked for my project that had previously been using update

@WebFreak001
Copy link
Contributor

ok looks good, can you further apply this diff to your modifications? There was the same issue in the code that the changed code was based on, which is resolved with this. Furthermore tests that the asserts are actually triggered in the right place.

diff --git a/mongodb/vibe/db/mongo/collection.d b/mongodb/vibe/db/mongo/collection.d
index 190027dd..1fb5c42f 100644
--- a/mongodb/vibe/db/mongo/collection.d
+++ b/mongodb/vibe/db/mongo/collection.d
@@ -326,23 +326,23 @@ struct MongoCollection {
 			auto updateBson = Bson.emptyObject;
 			auto qbson = serializeToBson(q);
 			updateBson["q"] = qbson;
+			auto ubson = serializeToBson(documents[i]);
 			if (mustBeDocument)
 			{
-				if (qbson.type != Bson.Type.object)
+				if (ubson.type != Bson.Type.object)
 					assert(false, "Passed in non-document into a place where only replacements are expected. "
 						~ "Maybe you want to call updateOne or updateMany instead?");
 
-				foreach (string k, v; qbson.byKeyValue)
+				foreach (string k, v; ubson.byKeyValue)
 				{
 					if (k.startsWith("$"))
 						assert(false, "Passed in atomic modifiers (" ~ k
 							~ ") into a place where only replacements are expected. "
 							~ "Maybe you want to call updateOne or updateMany instead?");
-					debug break; // server checks that the rest is consistent (only $ or only non-$ allowed)
-					// however in debug mode we check the full document, as we can give better error messages to the dev
+					debug {} // server checks that the rest is consistent (only $ or only non-$ allowed)
+					else break; // however in debug mode we check the full document, as we can give better error messages to the dev
 				}
 			}
-			auto ubson = serializeToBson(documents[i]);
 			if (mustBeModification)
 			{
 				if (ubson.type == Bson.Type.object)
@@ -352,8 +352,8 @@ struct MongoCollection {
 					{
 						if (k.startsWith("$"))
 							anyDollar = true;
-						debug break; // server checks that the rest is consistent (only $ or only non-$ allowed)
-						// however in debug mode we check the full document, as we can give better error messages to the dev
+						debug {} // server checks that the rest is consistent (only $ or only non-$ allowed)
+						else break; // however in debug mode we check the full document, as we can give better error messages to the dev
 						// also nice side effect: if this is an empty document, this also matches the assert(false) branch.
 					}
 
diff --git a/tests/mongodb/_connection/source/app.d b/tests/mongodb/_connection/source/app.d
index fa79bb82..d8c8577c 100644
--- a/tests/mongodb/_connection/source/app.d
+++ b/tests/mongodb/_connection/source/app.d
@@ -5,6 +5,7 @@ import vibe.core.log;
 import core.time;
 import std.algorithm;
 import std.conv;
+import core.exception : AssertError;
 import std.exception;
 
 int main(string[] args)
@@ -157,20 +158,24 @@ int main(string[] args)
 		.map!(c => c["name"].get!string)
 		.equal(["collection"]));
 
-    auto options = UpdateOptions();
-    options.upsert = true;
+	auto options = UpdateOptions();
+	options.upsert = true;
 
-    //test updateOne
-    auto newID = BsonObjectID.generate;
-    foreach(const str; ["a", "b", "c"])
-    {
-        coll.updateOne(["_id": newID], ["$push" : ["array" : str ]], options);
-    }
+	//test updateOne
+	auto newID = BsonObjectID.generate;
+	foreach(const str; ["a", "b", "c"])
+	{
+		coll.updateOne(["_id": newID], ["$push" : ["array" : str ]], options);
+	}
+
+	auto arrResult = coll.findOne(["_id" : newID])["array"];
+	assert(arrResult[0].get!string =="a");
+	assert(arrResult[1].get!string =="b");
+	assert(arrResult[2].get!string =="c");
 
-    auto arrResult = coll.findOne(["_id" : newID])["array"];
-    assert(arrResult[0].get!string =="a");
-    assert(arrResult[1].get!string =="b");
-    assert(arrResult[2].get!string =="c");
+	assertThrown!AssertError(coll.updateOne(["_id": newID], ["this is a replacement": "which is not allowed here"]));
+	assertThrown!AssertError(coll.replaceOne(["_id": newID], ["$updateOp": "is not allowed here"]));
+	assertThrown!AssertError(coll.replaceOne(["_id": newID], null));
 
 	coll.drop();
 

Copy link
Contributor

@WebFreak001 WebFreak001 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, @s-ludwig can you merge?

@benjones
Copy link
Contributor Author

@s-ludwig ping

benjones added 2 commits May 22, 2023 20:58
fix parsing of upsert response
add updateOne tests
@s-ludwig s-ludwig enabled auto-merge May 22, 2023 18:58
@s-ludwig s-ludwig merged commit a68fd93 into vibe-d:master May 22, 2023
@benjones benjones deleted the mongofix branch May 22, 2023 20:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants