Skip to content

Commit 84f5d1c

Browse files
committed
Improve exception message when replace would modify the _id
1 parent 045d6e6 commit 84f5d1c

File tree

3 files changed

+47
-8
lines changed

3 files changed

+47
-8
lines changed

core/src/main/java/de/bwaldvogel/mongo/backend/AbstractMongoCollection.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ public Document findAndModify(Document query) {
457457
return result;
458458
}
459459

460-
private static class FindAndModifyPlanExecutorError extends MongoServerError {
460+
public static class FindAndModifyPlanExecutorError extends MongoServerError {
461461

462462
private static final long serialVersionUID = 1L;
463463

@@ -466,6 +466,11 @@ private static class FindAndModifyPlanExecutorError extends MongoServerError {
466466
private FindAndModifyPlanExecutorError(MongoServerError cause) {
467467
super(cause.getCode(), cause.getCodeName(), PREFIX + cause.getMessageWithoutErrorCode(), cause);
468468
}
469+
470+
@Override
471+
public synchronized MongoServerError getCause() {
472+
return (MongoServerError) super.getCause();
473+
}
469474
}
470475

471476
@Override

core/src/main/java/de/bwaldvogel/mongo/backend/aggregation/stage/MergeStage.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
import de.bwaldvogel.mongo.MongoCollection;
1515
import de.bwaldvogel.mongo.MongoDatabase;
16+
import de.bwaldvogel.mongo.backend.AbstractMongoCollection.FindAndModifyPlanExecutorError;
17+
import de.bwaldvogel.mongo.backend.Assert;
1618
import de.bwaldvogel.mongo.backend.DatabaseResolver;
1719
import de.bwaldvogel.mongo.backend.Index;
1820
import de.bwaldvogel.mongo.backend.IndexKey;
@@ -220,12 +222,18 @@ private Document getJoinQuery(Document document) {
220222

221223
private void replaceDocument(MongoCollection<?> collection, Document existingDocument, Document document) {
222224
Document documentSelector = new Document("_id", existingDocument.get("_id"));
223-
Document result = collection.findAndModify(new Document("query", documentSelector)
224-
.append("new", false)
225-
.append("upsert", false)
226-
.append("update", document));
227-
if (!result.get("ok").equals(1.0)) {
228-
throw new RuntimeException("Unexpected result: " + result);
225+
try {
226+
Document result = collection.findAndModify(new Document("query", documentSelector)
227+
.append("new", false)
228+
.append("upsert", false)
229+
.append("update", document));
230+
Assert.equals(result.get("ok"), 1.0);
231+
} catch (FindAndModifyPlanExecutorError e) {
232+
MongoServerError cause = e.getCause();
233+
throw new MongoServerError(cause.getCode(), cause.getCodeName(),
234+
"$merge failed to update the matching document,"
235+
+ " did you attempt to modify the _id or the shard key? :: caused by :: "
236+
+ cause.getMessageWithoutErrorCode(), cause);
229237
}
230238
}
231239

test-common/src/main/java/de/bwaldvogel/mongo/backend/AbstractAggregationTest.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2384,7 +2384,7 @@ void testAggregateWithMerge_stringParameter() throws Exception {
23842384
}
23852385

23862386
@Test
2387-
void testAggregateWithMerge_idMustNotBeModified() throws Exception {
2387+
void testAggregateWithMerge_idMustNotBeModified_merge() throws Exception {
23882388
collection.insertMany(jsonList(
23892389
"_id: 1, name: 'Ant'",
23902390
"_id: 2, name: 'Bee'",
@@ -2409,6 +2409,32 @@ void testAggregateWithMerge_idMustNotBeModified() throws Exception {
24092409
"Performing an update on the path '_id' would modify the immutable field '_id''");
24102410
}
24112411

2412+
@Test
2413+
void testAggregateWithMerge_idMustNotBeModified_replace() throws Exception {
2414+
collection.insertMany(jsonList(
2415+
"_id: 1, name: 'Ant'",
2416+
"_id: 2, name: 'Bee'",
2417+
"_id: 3, name: 'Cat'"
2418+
));
2419+
2420+
MongoCollection<Document> otherCollection = db.getCollection("other");
2421+
2422+
otherCollection.insertMany(jsonList(
2423+
"_id: 10, name: 'Ant'",
2424+
"_id: 11, name: 'Bee'",
2425+
"_id: 12, name: 'Cat'"
2426+
));
2427+
2428+
otherCollection.createIndex(json("name: 1"), new IndexOptions().unique(true));
2429+
2430+
assertThatExceptionOfType(MongoCommandException.class)
2431+
.isThrownBy(() -> collection.aggregate(jsonList("$merge : { into: 'other', on: 'name', whenMatched: 'replace' }")).first())
2432+
.withMessageStartingWith("Command failed with error 66 (ImmutableField): " +
2433+
"'PlanExecutor error during aggregation :: caused by :: " +
2434+
"$merge failed to update the matching document, did you attempt to modify the _id or the shard key? :: caused by :: " +
2435+
"After applying the update, the (immutable) field '_id' was found to have been altered to _id: 1'");
2436+
}
2437+
24122438
@Test
24132439
void testAggregateWithMerge_onWithoutUniqueIndex() throws Exception {
24142440
collection.insertOne(json("_id: 1"));

0 commit comments

Comments
 (0)