Skip to content

Commit 205bfc5

Browse files
committed
BUG32778827: Raise an error if the _id is different when replacing a document
If a document provided for replacement, using the Collection.replace_one() or Collection.add_or_replace_one() methods, contains an "_id" different from the original document, the new "_id" is ignored. This patch fixes this error by raising an error if the "_id" in the document provided for replacement is different from the original. Tests were added for regression.
1 parent 391e371 commit 205bfc5

File tree

4 files changed

+38
-2
lines changed

4 files changed

+38
-2
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ v8.0.26
1414
- WL#14542: Deprecate TLS 1.0 and 1.1
1515
- WL#14440: Support for authentication_kerberos_client authentication plugin
1616
- WL#14237: Support query attributes
17+
- BUG#32778827: Raise an error if the _id is different when replacing a document
1718
- BUG#32623479: The X DevAPI returns str for binary types values
1819

1920
v8.0.25

lib/mysqlx/crud.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,11 @@ def replace_one(self, doc_id, doc):
551551
doc_id (str): Document ID
552552
doc (:class:`mysqlx.DbDoc` or `dict`): New Document
553553
"""
554+
if "_id" in doc and doc["_id"] != doc_id:
555+
raise ProgrammingError(
556+
"Replacement document has an _id that is different than the "
557+
"matched document"
558+
)
554559
return self.modify("_id = :id").set("$", doc) \
555560
.bind("id", doc_id).execute()
556561

@@ -562,6 +567,11 @@ def add_or_replace_one(self, doc_id, doc):
562567
doc_id (str): Document ID
563568
doc (:class:`mysqlx.DbDoc` or dict): New Document
564569
"""
570+
if "_id" in doc and doc["_id"] != doc_id:
571+
raise ProgrammingError(
572+
"Replacement document has an _id that is different than the "
573+
"matched document"
574+
)
565575
if not isinstance(doc, DbDoc):
566576
doc = DbDoc(doc)
567577
return self.add(doc.copy(doc_id)).upsert(True).execute()

lib/mysqlx/dbdoc.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
22
#
33
# This program is free software; you can redistribute it and/or modify
44
# it under the terms of the GNU General Public License, version 2.0, as
@@ -74,6 +74,9 @@ def __setitem__(self, index, value):
7474
def __getitem__(self, index):
7575
return self.__dict__[index]
7676

77+
def __contains__(self, item):
78+
return item in self.__dict__
79+
7780
def copy(self, doc_id=None):
7881
"""Returns a new copy of a :class:`mysqlx.DbDoc` object containing the
7982
`doc_id` provided. If `doc_id` is not provided, it will be removed from

tests/test_mysqlx_crud.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1840,6 +1840,17 @@ def test_replace_one(self):
18401840
result = collection.find("age = 21").execute().fetch_one()
18411841
self.assertEqual("George", result["name"])
18421842

1843+
doc = {"_id": "5", "name": "Fred", "age": 21}
1844+
self.assertRaises(
1845+
mysqlx.ProgrammingError,
1846+
collection.replace_one, "1", doc
1847+
)
1848+
doc = mysqlx.DbDoc({"_id": "5", "name": "Fred", "age": 21})
1849+
self.assertRaises(
1850+
mysqlx.ProgrammingError,
1851+
collection.replace_one, "1", doc
1852+
)
1853+
18431854
self.schema.drop_collection(collection_name)
18441855

18451856
@unittest.skipIf(tests.MYSQL_VERSION < (8, 0, 2), "Upsert not supported")
@@ -1863,12 +1874,23 @@ def test_add_or_replace_one(self):
18631874

18641875
result = collection.find("_id = 'new_id'").execute().fetch_all()
18651876
self.assertEqual(0, len(result))
1866-
upsert = {"_id": "11", 'name': 'Melissandre', "age": 99999}
1877+
upsert = {'name': 'Melissandre', "age": 99999}
18671878
collection.add_or_replace_one("new_id", upsert)
18681879
result = collection.find("age = 99999").execute().fetch_one()
18691880
self.assertEqual("Melissandre", result["name"])
18701881
self.assertEqual("new_id", result["_id"])
18711882

1883+
doc = {"_id": "5", "name": "Fred", "age": 21}
1884+
self.assertRaises(
1885+
mysqlx.ProgrammingError,
1886+
collection.add_or_replace_one, "1", doc
1887+
)
1888+
doc = mysqlx.DbDoc({"_id": "5", "name": "Fred", "age": 21})
1889+
self.assertRaises(
1890+
mysqlx.ProgrammingError,
1891+
collection.add_or_replace_one, "1", doc
1892+
)
1893+
18721894
self.schema.drop_collection(collection_name)
18731895

18741896
def test_get_one(self):

0 commit comments

Comments
 (0)