From ddb661444220474bcb448a7adbd13ef9220a588a Mon Sep 17 00:00:00 2001 From: Julius Park Date: Wed, 9 Feb 2022 15:12:02 -0800 Subject: [PATCH] PYTHON-2682 Add support for the comment field to all helpers (#847) --- pymongo/aggregation.py | 3 + pymongo/bulk.py | 5 +- pymongo/change_stream.py | 5 +- pymongo/collection.py | 252 ++++++++- pymongo/cursor.py | 2 +- pymongo/database.py | 70 ++- pymongo/mongo_client.py | 41 +- .../unified/change-streams.json | 146 +++++- test/crud/unified/aggregate.json | 280 ++++++++++ test/crud/unified/bulkWrite-comment.json | 494 ++++++++++++++++++ test/crud/unified/deleteMany-comment.json | 244 +++++++++ test/crud/unified/deleteOne-comment.json | 242 +++++++++ test/crud/unified/find-comment.json | 298 +++++++++++ .../unified/findOneAndDelete-comment.json | 211 ++++++++ .../unified/findOneAndReplace-comment.json | 234 +++++++++ .../unified/findOneAndUpdate-comment.json | 228 ++++++++ test/crud/unified/insertMany-comment.json | 225 ++++++++ test/crud/unified/insertOne-comment.json | 219 ++++++++ test/crud/unified/replaceOne-comment.json | 229 ++++++++ test/crud/unified/updateMany-comment.json | 244 +++++++++ test/crud/unified/updateOne-comment.json | 241 +++++++++ test/test_comment.py | 183 +++++++ 22 files changed, 4048 insertions(+), 48 deletions(-) create mode 100644 test/crud/unified/bulkWrite-comment.json create mode 100644 test/crud/unified/deleteMany-comment.json create mode 100644 test/crud/unified/deleteOne-comment.json create mode 100644 test/crud/unified/find-comment.json create mode 100644 test/crud/unified/findOneAndDelete-comment.json create mode 100644 test/crud/unified/findOneAndReplace-comment.json create mode 100644 test/crud/unified/findOneAndUpdate-comment.json create mode 100644 test/crud/unified/insertMany-comment.json create mode 100644 test/crud/unified/insertOne-comment.json create mode 100644 test/crud/unified/replaceOne-comment.json create mode 100644 test/crud/unified/updateMany-comment.json create mode 100644 test/crud/unified/updateOne-comment.json create mode 100644 test/test_comment.py diff --git a/pymongo/aggregation.py b/pymongo/aggregation.py index 2b8cafe7c..51be0dfa8 100644 --- a/pymongo/aggregation.py +++ b/pymongo/aggregation.py @@ -39,6 +39,7 @@ class _AggregationCommand(object): let=None, user_fields=None, result_processor=None, + comment=None, ): if "explain" in options: raise ConfigurationError( @@ -57,6 +58,8 @@ class _AggregationCommand(object): if let: common.validate_is_mapping("let", let) options["let"] = let + if comment is not None: + options["comment"] = comment self._options = options # This is the batchSize that will be used for setting the initial diff --git a/pymongo/bulk.py b/pymongo/bulk.py index e043e09fd..fae55a5c1 100644 --- a/pymongo/bulk.py +++ b/pymongo/bulk.py @@ -138,13 +138,14 @@ def _raise_bulk_write_error(full_result): class _Bulk(object): """The private guts of the bulk write API.""" - def __init__(self, collection, ordered, bypass_document_validation): + def __init__(self, collection, ordered, bypass_document_validation, comment=None): """Initialize a _Bulk instance.""" self.collection = collection.with_options( codec_options=collection.codec_options._replace( unicode_decode_error_handler="replace", document_class=dict ) ) + self.comment = comment self.ordered = ordered self.ops = [] self.executed = False @@ -308,6 +309,8 @@ class _Bulk(object): write_concern = final_write_concern or write_concern cmd = SON([(cmd_name, self.collection.name), ("ordered", self.ordered)]) + if self.comment: + cmd["comment"] = self.comment if not write_concern.is_server_default: cmd["writeConcern"] = write_concern.document if self.bypass_doc_val: diff --git a/pymongo/change_stream.py b/pymongo/change_stream.py index a35c9cb84..50f6f72b7 100644 --- a/pymongo/change_stream.py +++ b/pymongo/change_stream.py @@ -95,6 +95,7 @@ class ChangeStream(Generic[_DocumentType]): start_at_operation_time: Optional[Timestamp], session: Optional["ClientSession"], start_after: Optional[Mapping[str, Any]], + comment: Optional[Any] = None, ) -> None: if pipeline is None: pipeline = [] @@ -125,7 +126,7 @@ class ChangeStream(Generic[_DocumentType]): self._collation = collation self._start_at_operation_time = start_at_operation_time self._session = session - + self._comment = comment # Initialize cursor. self._cursor = self._create_cursor() @@ -209,8 +210,8 @@ class ChangeStream(Generic[_DocumentType]): self._command_options(), explicit_session, result_processor=self._process_result, + comment=self._comment, ) - return self._client._retryable_read( cmd.get_cursor, self._target._read_preference_for(session), session ) diff --git a/pymongo/collection.py b/pymongo/collection.py index b17bb61f3..df8db3f10 100644 --- a/pymongo/collection.py +++ b/pymongo/collection.py @@ -423,6 +423,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): ordered: bool = True, bypass_document_validation: bool = False, session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, ) -> BulkWriteResult: """Send a batch of write operations to the server. @@ -472,6 +473,8 @@ class Collection(common.BaseObject, Generic[_DocumentType]): ``False``. - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. :Returns: An instance of :class:`~pymongo.results.BulkWriteResult`. @@ -481,6 +484,9 @@ class Collection(common.BaseObject, Generic[_DocumentType]): .. note:: `bypass_document_validation` requires server version **>= 3.2** + .. versionchanged:: 4.1 + Added ``comment`` parameter. + .. versionchanged:: 3.6 Added ``session`` parameter. @@ -491,7 +497,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): """ common.validate_list("requests", requests) - blk = _Bulk(self, ordered, bypass_document_validation) + blk = _Bulk(self, ordered, bypass_document_validation, comment=comment) for request in requests: try: request._add_to_bulk(blk) @@ -504,11 +510,15 @@ class Collection(common.BaseObject, Generic[_DocumentType]): return BulkWriteResult(bulk_api_result, True) return BulkWriteResult({}, False) - def _insert_one(self, doc, ordered, write_concern, op_id, bypass_doc_val, session): + def _insert_one( + self, doc, ordered, write_concern, op_id, bypass_doc_val, session, comment=None + ): """Internal helper for inserting a single document.""" write_concern = write_concern or self.write_concern acknowledged = write_concern.acknowledged command = SON([("insert", self.name), ("ordered", ordered), ("documents", [doc])]) + if comment is not None: + command["comment"] = comment if not write_concern.is_server_default: command["writeConcern"] = write_concern.document @@ -538,6 +548,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): document: _DocumentIn, bypass_document_validation: bool = False, session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, ) -> InsertOneResult: """Insert a single document. @@ -558,6 +569,8 @@ class Collection(common.BaseObject, Generic[_DocumentType]): ``False``. - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. :Returns: - An instance of :class:`~pymongo.results.InsertOneResult`. @@ -567,6 +580,9 @@ class Collection(common.BaseObject, Generic[_DocumentType]): .. note:: `bypass_document_validation` requires server version **>= 3.2** + .. versionchanged:: 4.1 + Added ``comment`` parameter. + .. versionchanged:: 3.6 Added ``session`` parameter. @@ -588,6 +604,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): op_id=None, bypass_doc_val=bypass_document_validation, session=session, + comment=comment, ), write_concern.acknowledged, ) @@ -598,6 +615,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): ordered: bool = True, bypass_document_validation: bool = False, session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, ) -> InsertManyResult: """Insert an iterable of documents. @@ -621,6 +639,8 @@ class Collection(common.BaseObject, Generic[_DocumentType]): ``False``. - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. :Returns: An instance of :class:`~pymongo.results.InsertManyResult`. @@ -630,6 +650,9 @@ class Collection(common.BaseObject, Generic[_DocumentType]): .. note:: `bypass_document_validation` requires server version **>= 3.2** + .. versionchanged:: 4.1 + Added ``comment`` parameter. + .. versionchanged:: 3.6 Added ``session`` parameter. @@ -657,7 +680,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): yield (message._INSERT, document) write_concern = self._write_concern_for(session) - blk = _Bulk(self, ordered, bypass_document_validation) + blk = _Bulk(self, ordered, bypass_document_validation, comment=comment) blk.ops = [doc for doc in gen()] blk.execute(write_concern, session=session) return InsertManyResult(inserted_ids, write_concern.acknowledged) @@ -679,6 +702,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): session=None, retryable_write=False, let=None, + comment=None, ): """Internal update / replace helper.""" common.validate_boolean("upsert", upsert) @@ -704,7 +728,6 @@ class Collection(common.BaseObject, Generic[_DocumentType]): if not isinstance(hint, str): hint = helpers._index_document(hint) update_doc["hint"] = hint - command = SON([("update", self.name), ("ordered", ordered), ("updates", [update_doc])]) if let: common.validate_is_mapping("let", let) @@ -712,6 +735,8 @@ class Collection(common.BaseObject, Generic[_DocumentType]): if not write_concern.is_server_default: command["writeConcern"] = write_concern.document + if comment is not None: + command["comment"] = comment # Update command. if bypass_doc_val: command["bypassDocumentValidation"] = True @@ -757,6 +782,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): hint=None, session=None, let=None, + comment=None, ): """Internal update / replace helper.""" @@ -777,6 +803,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): session=session, retryable_write=retryable_write, let=let, + comment=comment, ) return self.__database.client._retryable_write( @@ -793,6 +820,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): hint: Optional[_IndexKeyHint] = None, session: Optional["ClientSession"] = None, let: Optional[Mapping[str, Any]] = None, + comment: Optional[Any] = None, ) -> UpdateResult: """Replace a single document matching the filter. @@ -845,12 +873,14 @@ class Collection(common.BaseObject, Generic[_DocumentType]): constant or closed expressions that do not reference document fields. Parameters can then be accessed as variables in an aggregate expression context (e.g. "$$var"). - + - `comment` (optional): A user-provided comment to attach to this + command. :Returns: - An instance of :class:`~pymongo.results.UpdateResult`. .. versionchanged:: 4.1 Added ``let`` parameter. + Added ``comment`` parameter. .. versionchanged:: 3.11 Added ``hint`` parameter. .. versionchanged:: 3.6 @@ -878,6 +908,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): hint=hint, session=session, let=let, + comment=comment, ), write_concern.acknowledged, ) @@ -893,6 +924,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): hint: Optional[_IndexKeyHint] = None, session: Optional["ClientSession"] = None, let: Optional[Mapping[str, Any]] = None, + comment: Optional[Any] = None, ) -> UpdateResult: """Update a single document matching the filter. @@ -938,12 +970,15 @@ class Collection(common.BaseObject, Generic[_DocumentType]): constant or closed expressions that do not reference document fields. Parameters can then be accessed as variables in an aggregate expression context (e.g. "$$var"). + - `comment` (optional): A user-provided comment to attach to this + command. :Returns: - An instance of :class:`~pymongo.results.UpdateResult`. .. versionchanged:: 4.1 Added ``let`` parameter. + Added ``comment`` parameter. .. versionchanged:: 3.11 Added ``hint`` parameter. .. versionchanged:: 3.9 @@ -974,6 +1009,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): hint=hint, session=session, let=let, + comment=comment, ), write_concern.acknowledged, ) @@ -989,6 +1025,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): hint: Optional[_IndexKeyHint] = None, session: Optional["ClientSession"] = None, let: Optional[Mapping[str, Any]] = None, + comment: Optional[Any] = None, ) -> UpdateResult: """Update one or more documents that match the filter. @@ -1034,12 +1071,15 @@ class Collection(common.BaseObject, Generic[_DocumentType]): constant or closed expressions that do not reference document fields. Parameters can then be accessed as variables in an aggregate expression context (e.g. "$$var"). + - `comment` (optional): A user-provided comment to attach to this + command. :Returns: - An instance of :class:`~pymongo.results.UpdateResult`. .. versionchanged:: 4.1 Added ``let`` parameter. + Added ``comment`` parameter. .. versionchanged:: 3.11 Added ``hint`` parameter. .. versionchanged:: 3.9 @@ -1071,22 +1111,32 @@ class Collection(common.BaseObject, Generic[_DocumentType]): hint=hint, session=session, let=let, + comment=comment, ), write_concern.acknowledged, ) - def drop(self, session: Optional["ClientSession"] = None) -> None: + def drop( + self, + session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, + ) -> None: """Alias for :meth:`~pymongo.database.Database.drop_collection`. :Parameters: - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. The following two calls are equivalent: >>> db.foo.drop() >>> db.drop_collection("foo") + .. versionchanged:: 4.1 + Added ``comment`` parameter. + .. versionchanged:: 3.7 :meth:`drop` now respects this :class:`Collection`'s :attr:`write_concern`. @@ -1100,7 +1150,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): self.write_concern, self.read_concern, ) - dbo.drop_collection(self.__name, session=session) + dbo.drop_collection(self.__name, session=session, comment=comment) def _delete( self, @@ -1115,6 +1165,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): session=None, retryable_write=False, let=None, + comment=None, ): """Internal delete helper.""" common.validate_is_mapping("filter", criteria) @@ -1143,6 +1194,9 @@ class Collection(common.BaseObject, Generic[_DocumentType]): common.validate_is_document_type("let", let) command["let"] = let + if comment is not None: + command["comment"] = comment + # Delete command. result = sock_info.command( self.__database.name, @@ -1167,6 +1221,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): hint=None, session=None, let=None, + comment=None, ): """Internal delete helper.""" @@ -1183,6 +1238,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): session=session, retryable_write=retryable_write, let=let, + comment=comment, ) return self.__database.client._retryable_write( @@ -1196,6 +1252,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): hint: Optional[_IndexKeyHint] = None, session: Optional["ClientSession"] = None, let: Optional[Mapping[str, Any]] = None, + comment: Optional[Any] = None, ) -> DeleteResult: """Delete a single document matching the filter. @@ -1223,12 +1280,15 @@ class Collection(common.BaseObject, Generic[_DocumentType]): constant or closed expressions that do not reference document fields. Parameters can then be accessed as variables in an aggregate expression context (e.g. "$$var"). + - `comment` (optional): A user-provided comment to attach to this + command. :Returns: - An instance of :class:`~pymongo.results.DeleteResult`. .. versionchanged:: 4.1 Added ``let`` parameter. + Added ``comment`` parameter. .. versionchanged:: 3.11 Added ``hint`` parameter. .. versionchanged:: 3.6 @@ -1247,6 +1307,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): hint=hint, session=session, let=let, + comment=comment, ), write_concern.acknowledged, ) @@ -1258,6 +1319,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): hint: Optional[_IndexKeyHint] = None, session: Optional["ClientSession"] = None, let: Optional[Mapping[str, Any]] = None, + comment: Optional[Any] = None, ) -> DeleteResult: """Delete one or more documents matching the filter. @@ -1285,12 +1347,15 @@ class Collection(common.BaseObject, Generic[_DocumentType]): constant or closed expressions that do not reference document fields. Parameters can then be accessed as variables in an aggregate expression context (e.g. "$$var"). + - `comment` (optional): A user-provided comment to attach to this + command. :Returns: - An instance of :class:`~pymongo.results.DeleteResult`. .. versionchanged:: 4.1 Added ``let`` parameter. + Added ``comment`` parameter. .. versionchanged:: 3.11 Added ``hint`` parameter. .. versionchanged:: 3.6 @@ -1309,6 +1374,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): hint=hint, session=session, let=let, + comment=comment, ), write_concern.acknowledged, ) @@ -1339,10 +1405,10 @@ class Collection(common.BaseObject, Generic[_DocumentType]): are the same as the arguments to :meth:`find`. >>> collection.find_one(max_time_ms=100) + """ if filter is not None and not isinstance(filter, abc.Mapping): filter = {"_id": filter} - cursor = self.find(filter, *args, **kwargs) for result in cursor.limit(-1): return result @@ -1566,7 +1632,6 @@ class Collection(common.BaseObject, Generic[_DocumentType]): # OP_MSG is required to support encryption. if self.__database.client._encrypter: raise InvalidOperation("find_raw_batches does not support auto encryption") - return RawBatchCursor(self, *args, **kwargs) def _count_cmd(self, session, sock_info, read_preference, cmd, collation): @@ -1605,7 +1670,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): batch = result["cursor"]["firstBatch"] return batch[0] if batch else None - def estimated_document_count(self, **kwargs: Any) -> int: + def estimated_document_count(self, comment: Optional[Any] = None, **kwargs: Any) -> int: """Get an estimate of the number of documents in this collection using collection metadata. @@ -1619,12 +1684,17 @@ class Collection(common.BaseObject, Generic[_DocumentType]): operation to run, in milliseconds. :Parameters: + - `comment` (optional): A user-provided comment to attach to this + command. - `**kwargs` (optional): See list of options above. + .. versionadded:: 3.7 """ if "session" in kwargs: raise ConfigurationError("estimated_document_count does not support sessions") + if comment is not None: + kwargs["comment"] = comment def _cmd(session, server, sock_info, read_preference): if sock_info.max_wire_version >= 12: @@ -1650,7 +1720,11 @@ class Collection(common.BaseObject, Generic[_DocumentType]): return self.__database.client._retryable_read(_cmd, self.read_preference, None) def count_documents( - self, filter: Mapping[str, Any], session: Optional["ClientSession"] = None, **kwargs: Any + self, + filter: Mapping[str, Any], + session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, + **kwargs: Any, ) -> int: """Count the number of documents in this collection. @@ -1696,8 +1770,11 @@ class Collection(common.BaseObject, Generic[_DocumentType]): documents. - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. - `**kwargs` (optional): See list of options above. + .. versionadded:: 3.7 .. _$expr: https://docs.mongodb.com/manual/reference/operator/query/expr/ @@ -1710,6 +1787,8 @@ class Collection(common.BaseObject, Generic[_DocumentType]): pipeline.append({"$skip": kwargs.pop("skip")}) if "limit" in kwargs: pipeline.append({"$limit": kwargs.pop("limit")}) + if comment is not None: + kwargs["comment"] = comment pipeline.append({"$group": {"_id": 1, "n": {"$sum": 1}}}) cmd = SON([("aggregate", self.__name), ("pipeline", pipeline), ("cursor", {})]) if "hint" in kwargs and not isinstance(kwargs["hint"], str): @@ -1731,6 +1810,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): self, indexes: Sequence[IndexModel], session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, **kwargs: Any, ) -> List[str]: """Create one or more indexes on this collection. @@ -1747,9 +1827,14 @@ class Collection(common.BaseObject, Generic[_DocumentType]): instances. - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. - `**kwargs` (optional): optional arguments to the createIndexes command (like maxTimeMS) can be passed as keyword arguments. + + + .. note:: The :attr:`~pymongo.collection.Collection.write_concern` of this collection is automatically applied to this operation. @@ -1765,6 +1850,8 @@ class Collection(common.BaseObject, Generic[_DocumentType]): .. _createIndexes: https://docs.mongodb.com/manual/reference/command/createIndexes/ """ common.validate_list("indexes", indexes) + if comment is not None: + kwargs["comment"] = comment return self.__create_indexes(indexes, session, **kwargs) def __create_indexes(self, indexes, session, **kwargs): @@ -1811,7 +1898,11 @@ class Collection(common.BaseObject, Generic[_DocumentType]): return names def create_index( - self, keys: _IndexKeyHint, session: Optional["ClientSession"] = None, **kwargs: Any + self, + keys: _IndexKeyHint, + session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, + **kwargs: Any, ) -> str: """Creates an index on this collection. @@ -1886,10 +1977,14 @@ class Collection(common.BaseObject, Generic[_DocumentType]): pairs specifying the index to create - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + arguments + - `comment` (optional): A user-provided comment to attach to this + command. - `**kwargs` (optional): any additional index creation options (see the above list) should be passed as keyword - arguments + .. versionchanged:: 4.1 + Added ``comment`` parameter. .. versionchanged:: 3.11 Added the ``hidden`` option. .. versionchanged:: 3.6 @@ -1912,10 +2007,17 @@ class Collection(common.BaseObject, Generic[_DocumentType]): cmd_options = {} if "maxTimeMS" in kwargs: cmd_options["maxTimeMS"] = kwargs.pop("maxTimeMS") + if comment is not None: + cmd_options["comment"] = comment index = IndexModel(keys, **kwargs) return self.__create_indexes([index], session, **cmd_options)[0] - def drop_indexes(self, session: Optional["ClientSession"] = None, **kwargs: Any) -> None: + def drop_indexes( + self, + session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, + **kwargs: Any, + ) -> None: """Drops all indexes on this collection. Can be used on non-existant collections or collections with no indexes. @@ -1924,9 +2026,14 @@ class Collection(common.BaseObject, Generic[_DocumentType]): :Parameters: - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + arguments + - `comment` (optional): A user-provided comment to attach to this + command. - `**kwargs` (optional): optional arguments to the createIndexes command (like maxTimeMS) can be passed as keyword arguments. + + .. note:: The :attr:`~pymongo.collection.Collection.write_concern` of this collection is automatically applied to this operation. @@ -1939,10 +2046,16 @@ class Collection(common.BaseObject, Generic[_DocumentType]): when connected to MongoDB >= 3.4. """ + if comment is not None: + kwargs["comment"] = comment self.drop_index("*", session=session, **kwargs) def drop_index( - self, index_or_name: _IndexKeyHint, session: Optional["ClientSession"] = None, **kwargs: Any + self, + index_or_name: _IndexKeyHint, + session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, + **kwargs: Any, ) -> None: """Drops the specified index on this collection. @@ -1964,12 +2077,17 @@ class Collection(common.BaseObject, Generic[_DocumentType]): - `index_or_name`: index (or name of index) to drop - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. - `**kwargs` (optional): optional arguments to the createIndexes command (like maxTimeMS) can be passed as keyword arguments. + + .. note:: The :attr:`~pymongo.collection.Collection.write_concern` of this collection is automatically applied to this operation. + .. versionchanged:: 3.6 Added ``session`` parameter. Added support for arbitrary keyword arguments. @@ -1988,6 +2106,8 @@ class Collection(common.BaseObject, Generic[_DocumentType]): cmd = SON([("dropIndexes", self.__name), ("index", name)]) cmd.update(kwargs) + if comment is not None: + cmd["comment"] = comment with self._socket_for_writes(session) as sock_info: self._command( sock_info, @@ -1999,7 +2119,9 @@ class Collection(common.BaseObject, Generic[_DocumentType]): ) def list_indexes( - self, session: Optional["ClientSession"] = None + self, + session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, ) -> CommandCursor[MutableMapping[str, Any]]: """Get a cursor over the index documents for this collection. @@ -2011,10 +2133,15 @@ class Collection(common.BaseObject, Generic[_DocumentType]): :Parameters: - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. :Returns: An instance of :class:`~pymongo.command_cursor.CommandCursor`. + .. versionchanged:: 4.1 + Added ``comment`` parameter. + .. versionchanged:: 3.6 Added ``session`` parameter. @@ -2028,6 +2155,9 @@ class Collection(common.BaseObject, Generic[_DocumentType]): def _cmd(session, server, sock_info, read_preference): cmd = SON([("listIndexes", self.__name), ("cursor", {})]) + if comment is not None: + cmd["comment"] = comment + with self.__database.client._tmp_session(session, False) as s: try: cursor = self._command( @@ -2048,7 +2178,9 @@ class Collection(common.BaseObject, Generic[_DocumentType]): return self.__database.client._retryable_read(_cmd, read_pref, session) def index_information( - self, session: Optional["ClientSession"] = None + self, + session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, ) -> MutableMapping[str, Any]: """Get information on this collection's indexes. @@ -2071,11 +2203,16 @@ class Collection(common.BaseObject, Generic[_DocumentType]): :Parameters: - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. + + .. versionchanged:: 4.1 + Added ``comment`` parameter. .. versionchanged:: 3.6 Added ``session`` parameter. """ - cursor = self.list_indexes(session=session) + cursor = self.list_indexes(session=session, comment=comment) info = {} for index in cursor: index["key"] = list(index["key"].items()) @@ -2083,7 +2220,11 @@ class Collection(common.BaseObject, Generic[_DocumentType]): info[index.pop("name")] = index return info - def options(self, session: Optional["ClientSession"] = None) -> MutableMapping[str, Any]: + def options( + self, + session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, + ) -> MutableMapping[str, Any]: """Get the options set on this collection. Returns a dictionary of options and their values - see @@ -2094,6 +2235,8 @@ class Collection(common.BaseObject, Generic[_DocumentType]): :Parameters: - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. .. versionchanged:: 3.6 Added ``session`` parameter. @@ -2105,7 +2248,9 @@ class Collection(common.BaseObject, Generic[_DocumentType]): self.write_concern, self.read_concern, ) - cursor = dbo.list_collections(session=session, filter={"name": self.__name}) + cursor = dbo.list_collections( + session=session, filter={"name": self.__name}, comment=comment + ) result = None for doc in cursor: @@ -2130,8 +2275,11 @@ class Collection(common.BaseObject, Generic[_DocumentType]): session, explicit_session, let=None, + comment=None, **kwargs, ): + if comment is not None: + kwargs["comment"] = comment cmd = aggregation_command( self, cursor_class, @@ -2154,6 +2302,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): pipeline: _Pipeline, session: Optional["ClientSession"] = None, let: Optional[Mapping[str, Any]] = None, + comment: Optional[Any] = None, **kwargs: Any, ) -> CommandCursor[_DocumentType]: """Perform an aggregation using the aggregation framework on this @@ -2196,12 +2345,16 @@ class Collection(common.BaseObject, Generic[_DocumentType]): fields. Parameters can then be accessed as variables in an aggregate expression context (e.g. ``"$$var"``). This option is only supported on MongoDB >= 5.0. + - `comment` (optional): A user-provided comment to attach to this + command. + :Returns: A :class:`~pymongo.command_cursor.CommandCursor` over the result set. .. versionchanged:: 4.1 + Added ``comment`` parameter. Added ``let`` parameter. Support $merge and $out executing on secondaries according to the collection's :attr:`read_preference`. @@ -2228,6 +2381,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): .. _aggregate command: https://docs.mongodb.com/manual/reference/command/aggregate """ + with self.__database.client._tmp_session(session, close=False) as s: return self._aggregate( _CollectionAggregationCommand, @@ -2236,11 +2390,16 @@ class Collection(common.BaseObject, Generic[_DocumentType]): session=s, explicit_session=session is not None, let=let, + comment=comment, **kwargs, ) def aggregate_raw_batches( - self, pipeline: _Pipeline, session: Optional["ClientSession"] = None, **kwargs: Any + self, + pipeline: _Pipeline, + session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, + **kwargs: Any, ) -> RawBatchCursor[_DocumentType]: """Perform an aggregation and retrieve batches of raw BSON. @@ -2268,7 +2427,8 @@ class Collection(common.BaseObject, Generic[_DocumentType]): # OP_MSG is required to support encryption. if self.__database.client._encrypter: raise InvalidOperation("aggregate_raw_batches does not support auto encryption") - + if comment is not None: + kwargs["comment"] = comment with self.__database.client._tmp_session(session, close=False) as s: return self._aggregate( _CollectionRawAggregationCommand, @@ -2290,6 +2450,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): start_at_operation_time: Optional[Timestamp] = None, session: Optional["ClientSession"] = None, start_after: Optional[Mapping[str, Any]] = None, + comment: Optional[Any] = None, ) -> CollectionChangeStream[_DocumentType]: """Watch changes on this collection. @@ -2368,10 +2529,16 @@ class Collection(common.BaseObject, Generic[_DocumentType]): - `start_after` (optional): The same as `resume_after` except that `start_after` can resume notifications after an invalidate event. This option and `resume_after` are mutually exclusive. + - `comment` (optional): A user-provided comment to attach to this + command. :Returns: A :class:`~pymongo.change_stream.CollectionChangeStream` cursor. + + .. versionchanged:: 4.1 + Added ``comment`` parameter. + .. versionchanged:: 3.9 Added the ``start_after`` parameter. @@ -2396,10 +2563,15 @@ class Collection(common.BaseObject, Generic[_DocumentType]): start_at_operation_time, session, start_after, + comment=comment, ) def rename( - self, new_name: str, session: Optional["ClientSession"] = None, **kwargs: Any + self, + new_name: str, + session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, + **kwargs: Any, ) -> MutableMapping[str, Any]: """Rename this collection. @@ -2413,6 +2585,8 @@ class Collection(common.BaseObject, Generic[_DocumentType]): - `new_name`: new name for this collection - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. - `**kwargs` (optional): additional arguments to the rename command may be passed as keyword arguments to this helper method (i.e. ``dropTarget=True``) @@ -2441,6 +2615,8 @@ class Collection(common.BaseObject, Generic[_DocumentType]): new_name = "%s.%s" % (self.__database.name, new_name) cmd = SON([("renameCollection", self.__full_name), ("to", new_name)]) cmd.update(kwargs) + if comment is not None: + cmd["comment"] = comment write_concern = self._write_concern_for_cmd(cmd, session) with self._socket_for_writes(session) as sock_info: @@ -2459,6 +2635,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): key: str, filter: Optional[Mapping[str, Any]] = None, session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, **kwargs: Any, ) -> List: """Get a list of distinct values for `key` among all documents @@ -2485,6 +2662,8 @@ class Collection(common.BaseObject, Generic[_DocumentType]): from which to retrieve the distinct values. - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. - `**kwargs` (optional): See list of options above. .. versionchanged:: 3.6 @@ -2503,6 +2682,8 @@ class Collection(common.BaseObject, Generic[_DocumentType]): kwargs["query"] = filter collation = validate_collation_or_none(kwargs.pop("collation", None)) cmd.update(kwargs) + if comment is not None: + cmd["comment"] = comment def _cmd(session, server, sock_info, read_preference): return self._command( @@ -2611,6 +2792,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): hint: Optional[_IndexKeyHint] = None, session: Optional["ClientSession"] = None, let: Optional[Mapping[str, Any]] = None, + comment: Optional[Any] = None, **kwargs: Any, ) -> _DocumentType: """Finds a single document and deletes it, returning the document. @@ -2656,13 +2838,15 @@ class Collection(common.BaseObject, Generic[_DocumentType]): on MongoDB 4.4 and above. - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. - - `**kwargs` (optional): additional command arguments can be passed - as keyword arguments (for example maxTimeMS can be used with - recent server versions). - `let` (optional): Map of parameter names and values. Values must be constant or closed expressions that do not reference document fields. Parameters can then be accessed as variables in an aggregate expression context (e.g. "$$var"). + - `comment` (optional): A user-provided comment to attach to this + command. + - `**kwargs` (optional): additional command arguments can be passed + as keyword arguments (for example maxTimeMS can be used with + recent server versions). .. versionchanged:: 4.1 Added ``let`` parameter. @@ -2684,6 +2868,8 @@ class Collection(common.BaseObject, Generic[_DocumentType]): .. versionadded:: 3.0 """ kwargs["remove"] = True + if comment is not None: + kwargs["comment"] = comment return self.__find_and_modify( filter, projection, sort, let=let, hint=hint, session=session, **kwargs ) @@ -2699,6 +2885,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): hint: Optional[_IndexKeyHint] = None, session: Optional["ClientSession"] = None, let: Optional[Mapping[str, Any]] = None, + comment: Optional[Any] = None, **kwargs: Any, ) -> _DocumentType: """Finds a single document and replaces it, returning either the @@ -2754,11 +2941,13 @@ class Collection(common.BaseObject, Generic[_DocumentType]): constant or closed expressions that do not reference document fields. Parameters can then be accessed as variables in an aggregate expression context (e.g. "$$var"). + - `comment` (optional): A user-provided comment to attach to this + command. - `**kwargs` (optional): additional command arguments can be passed as keyword arguments (for example maxTimeMS can be used with recent server versions). - .. versionchanged:: 4.1 + Added ``let`` parameter. .. versionchanged:: 3.11 Added the ``hint`` option. @@ -2779,6 +2968,8 @@ class Collection(common.BaseObject, Generic[_DocumentType]): """ common.validate_ok_for_replace(replacement) kwargs["update"] = replacement + if comment is not None: + kwargs["comment"] = comment return self.__find_and_modify( filter, projection, @@ -2803,6 +2994,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): hint: Optional[_IndexKeyHint] = None, session: Optional["ClientSession"] = None, let: Optional[Mapping[str, Any]] = None, + comment: Optional[Any] = None, **kwargs: Any, ) -> _DocumentType: """Finds a single document and updates it, returning either the @@ -2897,12 +3089,12 @@ class Collection(common.BaseObject, Generic[_DocumentType]): constant or closed expressions that do not reference document fields. Parameters can then be accessed as variables in an aggregate expression context (e.g. "$$var"). + - `comment` (optional): A user-provided comment to attach to this + command. - `**kwargs` (optional): additional command arguments can be passed as keyword arguments (for example maxTimeMS can be used with recent server versions). - .. versionchanged:: 4.1 - Added ``let`` parameter. .. versionchanged:: 3.11 Added the ``hint`` option. .. versionchanged:: 3.9 @@ -2925,6 +3117,8 @@ class Collection(common.BaseObject, Generic[_DocumentType]): common.validate_ok_for_update(update) common.validate_list_or_none("array_filters", array_filters) kwargs["update"] = update + if comment is not None: + kwargs["comment"] = comment return self.__find_and_modify( filter, projection, diff --git a/pymongo/cursor.py b/pymongo/cursor.py index ba9e5956f..be4b998d3 100644 --- a/pymongo/cursor.py +++ b/pymongo/cursor.py @@ -183,7 +183,7 @@ class Cursor(Generic[_DocumentType]): return_key: Optional[bool] = None, show_record_id: Optional[bool] = None, snapshot: Optional[bool] = None, - comment: Any = None, + comment: Optional[Any] = None, session: Optional["ClientSession"] = None, allow_disk_use: Optional[bool] = None, let: Optional[bool] = None, diff --git a/pymongo/database.py b/pymongo/database.py index 675db132f..e6633ed23 100644 --- a/pymongo/database.py +++ b/pymongo/database.py @@ -471,6 +471,7 @@ class Database(common.BaseObject, Generic[_DocumentType]): start_at_operation_time: Optional[Timestamp] = None, session: Optional["ClientSession"] = None, start_after: Optional[Mapping[str, Any]] = None, + comment: Optional[Any] = None, ) -> DatabaseChangeStream[_DocumentType]: """Watch changes on this database. @@ -542,10 +543,15 @@ class Database(common.BaseObject, Generic[_DocumentType]): - `start_after` (optional): The same as `resume_after` except that `start_after` can resume notifications after an invalidate event. This option and `resume_after` are mutually exclusive. + - `comment` (optional): A user-provided comment to attach to this + command. :Returns: A :class:`~pymongo.change_stream.DatabaseChangeStream` cursor. + .. versionchanged:: 4.1 + Added ``comment`` parameter. + .. versionchanged:: 3.9 Added the ``start_after`` parameter. @@ -567,6 +573,7 @@ class Database(common.BaseObject, Generic[_DocumentType]): start_at_operation_time, session, start_after, + comment=comment, ) def _command( @@ -611,6 +618,7 @@ class Database(common.BaseObject, Generic[_DocumentType]): read_preference: Optional[_ServerMode] = None, codec_options: Optional[CodecOptions] = DEFAULT_CODEC_OPTIONS, session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, **kwargs: Any, ) -> Dict[str, Any]: """Issue a MongoDB command. @@ -665,9 +673,12 @@ class Database(common.BaseObject, Generic[_DocumentType]): instance. - `session` (optional): A :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. - `**kwargs` (optional): additional keyword arguments will be added to the command document before it is sent + .. note:: :meth:`command` does **not** obey this Database's :attr:`read_preference` or :attr:`codec_options`. You must use the `read_preference` and `codec_options` parameters instead. @@ -695,6 +706,9 @@ class Database(common.BaseObject, Generic[_DocumentType]): .. seealso:: The MongoDB documentation on `commands `_. """ + if comment is not None: + kwargs["comment"] = comment + if read_preference is None: read_preference = (session and session._txn_read_preference()) or ReadPreference.PRIMARY with self.__client._socket_for_reads(read_preference, session) as ( @@ -767,6 +781,7 @@ class Database(common.BaseObject, Generic[_DocumentType]): self, session: Optional["ClientSession"] = None, filter: Optional[Mapping[str, Any]] = None, + comment: Optional[Any] = None, **kwargs: Any, ) -> CommandCursor[Dict[str, Any]]: """Get a cursor over the collections of this database. @@ -776,12 +791,15 @@ class Database(common.BaseObject, Generic[_DocumentType]): :class:`~pymongo.client_session.ClientSession`. - `filter` (optional): A query document to filter the list of collections returned from the listCollections command. + - `comment` (optional): A user-provided comment to attach to this + command. - `**kwargs` (optional): Optional parameters of the `listCollections command `_ can be passed as keyword arguments to this method. The supported options differ by server version. + :Returns: An instance of :class:`~pymongo.command_cursor.CommandCursor`. @@ -790,6 +808,8 @@ class Database(common.BaseObject, Generic[_DocumentType]): if filter is not None: kwargs["filter"] = filter read_pref = (session and session._txn_read_preference()) or ReadPreference.PRIMARY + if comment is not None: + kwargs["comment"] = comment def _cmd(session, server, sock_info, read_preference): return self._list_collections( @@ -802,6 +822,7 @@ class Database(common.BaseObject, Generic[_DocumentType]): self, session: Optional["ClientSession"] = None, filter: Optional[Mapping[str, Any]] = None, + comment: Optional[Any] = None, **kwargs: Any, ) -> List[str]: """Get a list of all the collection names in this database. @@ -816,19 +837,25 @@ class Database(common.BaseObject, Generic[_DocumentType]): :class:`~pymongo.client_session.ClientSession`. - `filter` (optional): A query document to filter the list of collections returned from the listCollections command. + - `comment` (optional): A user-provided comment to attach to this + command. - `**kwargs` (optional): Optional parameters of the `listCollections command `_ can be passed as keyword arguments to this method. The supported options differ by server version. + .. versionchanged:: 3.8 Added the ``filter`` and ``**kwargs`` parameters. .. versionadded:: 3.6 """ + if comment is not None: + kwargs["comment"] = comment if filter is None: kwargs["nameOnly"] = True + else: # The enumerate collections spec states that "drivers MUST NOT set # nameOnly if a filter specifies any keys other than name." @@ -840,7 +867,10 @@ class Database(common.BaseObject, Generic[_DocumentType]): return [result["name"] for result in self.list_collections(session=session, **kwargs)] def drop_collection( - self, name_or_collection: Union[str, Collection], session: Optional["ClientSession"] = None + self, + name_or_collection: Union[str, Collection], + session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, ) -> Dict[str, Any]: """Drop a collection. @@ -849,10 +879,16 @@ class Database(common.BaseObject, Generic[_DocumentType]): collection object itself - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. + .. note:: The :attr:`~pymongo.database.Database.write_concern` of this database is automatically applied to this operation. + .. versionchanged:: 4.1 + Added ``comment`` parameter. + .. versionchanged:: 3.6 Added ``session`` parameter. @@ -868,11 +904,14 @@ class Database(common.BaseObject, Generic[_DocumentType]): if not isinstance(name, str): raise TypeError("name_or_collection must be an instance of str") + command = SON([("drop", name)]) + if comment is not None: + command["comment"] = comment + with self.__client._socket_for_writes(session) as sock_info: return self._command( sock_info, - "drop", - value=name, + command, allowable_errors=["ns not found", 26], write_concern=self._write_concern_for(session), parse_write_concern_error=True, @@ -886,6 +925,7 @@ class Database(common.BaseObject, Generic[_DocumentType]): full: bool = False, session: Optional["ClientSession"] = None, background: Optional[bool] = None, + comment: Optional[Any] = None, ) -> Dict[str, Any]: """Validate a collection. @@ -907,6 +947,11 @@ class Database(common.BaseObject, Generic[_DocumentType]): :class:`~pymongo.client_session.ClientSession`. - `background` (optional): A boolean flag that determines whether the command runs in the background. Requires MongoDB 4.4+. + - `comment` (optional): A user-provided comment to attach to this + command. + + .. versionchanged:: 4.1 + Added ``comment`` parameter. .. versionchanged:: 3.11 Added ``background`` parameter. @@ -922,8 +967,10 @@ class Database(common.BaseObject, Generic[_DocumentType]): if not isinstance(name, str): raise TypeError("name_or_collection must be an instance of str or " "Collection") - cmd = SON([("validate", name), ("scandata", scandata), ("full", full)]) + if comment is not None: + cmd["comment"] = comment + if background is not None: cmd["background"] = background @@ -970,7 +1017,11 @@ class Database(common.BaseObject, Generic[_DocumentType]): ) def dereference( - self, dbref: DBRef, session: Optional["ClientSession"] = None, **kwargs: Any + self, + dbref: DBRef, + session: Optional["ClientSession"] = None, + comment: Optional[Any] = None, + **kwargs: Any, ) -> Optional[_DocumentType]: """Dereference a :class:`~bson.dbref.DBRef`, getting the document it points to. @@ -985,10 +1036,15 @@ class Database(common.BaseObject, Generic[_DocumentType]): - `dbref`: the reference - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. - `**kwargs` (optional): any additional keyword arguments are the same as the arguments to :meth:`~pymongo.collection.Collection.find`. + + .. versionchanged:: 4.1 + Added ``comment`` parameter. .. versionchanged:: 3.6 Added ``session`` parameter. """ @@ -999,4 +1055,6 @@ class Database(common.BaseObject, Generic[_DocumentType]): "trying to dereference a DBRef that points to " "another database (%r not %r)" % (dbref.database, self.__name) ) - return self[dbref.collection].find_one({"_id": dbref.id}, session=session, **kwargs) + return self[dbref.collection].find_one( + {"_id": dbref.id}, session=session, comment=comment, **kwargs + ) diff --git a/pymongo/mongo_client.py b/pymongo/mongo_client.py index 3fa2946c7..6b0d55601 100644 --- a/pymongo/mongo_client.py +++ b/pymongo/mongo_client.py @@ -846,6 +846,7 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]): start_at_operation_time: Optional[Timestamp] = None, session: Optional[client_session.ClientSession] = None, start_after: Optional[Mapping[str, Any]] = None, + comment: Optional[Any] = None, ) -> ChangeStream[_DocumentType]: """Watch changes on this cluster. @@ -917,10 +918,15 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]): - `start_after` (optional): The same as `resume_after` except that `start_after` can resume notifications after an invalidate event. This option and `resume_after` are mutually exclusive. + - `comment` (optional): A user-provided comment to attach to this + command. :Returns: A :class:`~pymongo.change_stream.ClusterChangeStream` cursor. + .. versionchanged:: 4.1 + Added ``comment`` parameter. + .. versionchanged:: 3.9 Added the ``start_after`` parameter. @@ -942,6 +948,7 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]): start_at_operation_time, session, start_after, + comment=comment, ) @property @@ -1709,19 +1716,25 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]): ) def list_databases( - self, session: Optional[client_session.ClientSession] = None, **kwargs: Any + self, + session: Optional[client_session.ClientSession] = None, + comment: Optional[Any] = None, + **kwargs: Any, ) -> CommandCursor[Dict[str, Any]]: """Get a cursor over the databases of the connected server. :Parameters: - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. - `**kwargs` (optional): Optional parameters of the `listDatabases command `_ can be passed as keyword arguments to this method. The supported options differ by server version. + :Returns: An instance of :class:`~pymongo.command_cursor.CommandCursor`. @@ -1729,6 +1742,8 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]): """ cmd = SON([("listDatabases", 1)]) cmd.update(kwargs) + if comment is not None: + cmd["comment"] = comment admin = self._database_default_options("admin") res = admin._retryable_read_command(cmd, session=session) # listDatabases doesn't return a cursor (yet). Fake one. @@ -1740,22 +1755,30 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]): return CommandCursor(admin["$cmd"], cursor, None) def list_database_names( - self, session: Optional[client_session.ClientSession] = None + self, + session: Optional[client_session.ClientSession] = None, + comment: Optional[Any] = None, ) -> List[str]: """Get a list of the names of all databases on the connected server. :Parameters: - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. + + .. versionchanged:: 4.1 + Added ``comment`` parameter. .. versionadded:: 3.6 """ - return [doc["name"] for doc in self.list_databases(session, nameOnly=True)] + return [doc["name"] for doc in self.list_databases(session, nameOnly=True, comment=comment)] def drop_database( self, name_or_database: Union[str, database.Database], session: Optional[client_session.ClientSession] = None, + comment: Optional[Any] = None, ) -> None: """Drop a database. @@ -1769,6 +1792,11 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]): database to drop - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + - `comment` (optional): A user-provided comment to attach to this + command. + + .. versionchanged:: 4.1 + Added ``comment`` parameter. .. versionchanged:: 3.6 Added ``session`` parameter. @@ -1791,7 +1819,7 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]): with self._socket_for_writes(session) as sock_info: self[name]._command( sock_info, - "dropDatabase", + {"dropDatabase": 1, "comment": comment}, read_preference=ReadPreference.PRIMARY, write_concern=self._write_concern_for(session), parse_write_concern_error=True, @@ -1837,6 +1865,11 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]): :class:`~pymongo.read_concern.ReadConcern`. If ``None`` (the default) the :attr:`read_concern` of this :class:`MongoClient` is used. + - `comment` (optional): A user-provided comment to attach to this + command. + + .. versionchanged:: 4.1 + Added ``comment`` parameter. .. versionchanged:: 3.8 Undeprecated. Added the ``default``, ``codec_options``, diff --git a/test/change_streams/unified/change-streams.json b/test/change_streams/unified/change-streams.json index adaf00de2..4aea9a4aa 100644 --- a/test/change_streams/unified/change-streams.json +++ b/test/change_streams/unified/change-streams.json @@ -1,10 +1,21 @@ { "description": "change-streams", "schemaVersion": "1.0", + "runOnRequirements": [ + { + "topologies": [ + "replicaset", + "sharded-replicaset" + ] + } + ], "createEntities": [ { "client": { - "id": "client0" + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] } }, { @@ -34,10 +45,7 @@ "description": "Test array truncation", "runOnRequirements": [ { - "minServerVersion": "4.7", - "topologies": [ - "replicaset" - ] + "minServerVersion": "4.7" } ], "operations": [ @@ -111,6 +119,134 @@ } } ] + }, + { + "description": "Test with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "comment": { + "name": "test1" + } + }, + "saveResultAsEntity": "changeStream0" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "pipeline": [ + { + "$changeStream": {} + } + ], + "comment": { + "name": "test1" + } + } + } + } + ] + } + ] + }, + { + "description": "Test with document comment - pre 4.4", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "comment": { + "name": "test1" + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "pipeline": [ + { + "$changeStream": {} + } + ], + "comment": { + "name": "test1" + } + } + } + } + ] + } + ] + }, + { + "description": "Test with string comment", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0" + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "comment": "comment" + }, + "saveResultAsEntity": "changeStream0" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "pipeline": [ + { + "$changeStream": {} + } + ], + "comment": "comment" + } + } + } + ] + } + ] } ] } diff --git a/test/crud/unified/aggregate.json b/test/crud/unified/aggregate.json index dcdad761e..f6da8ff32 100644 --- a/test/crud/unified/aggregate.json +++ b/test/crud/unified/aggregate.json @@ -161,6 +161,286 @@ ] } ] + }, + { + "description": "aggregate with a string comment", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0" + } + ], + "operations": [ + { + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "comment": "comment" + }, + "object": "collection0" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "comment": "comment" + } + } + } + ] + } + ] + }, + { + "description": "aggregate with a document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "comment": { + "content": "test" + } + }, + "object": "collection0" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "comment": { + "content": "test" + } + } + } + } + ] + } + ] + }, + { + "description": "aggregate with a document comment - pre 4.4", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "comment": { + "content": "test" + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "comment": { + "content": "test" + } + }, + "commandName": "aggregate", + "databaseName": "aggregate-tests" + } + } + ] + } + ] + }, + { + "description": "aggregate with comment does not set comment on getMore", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0" + } + ], + "operations": [ + { + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "batchSize": 2, + "comment": "comment" + }, + "object": "collection0", + "expectResult": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + }, + { + "_id": 6, + "x": 66 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "cursor": { + "batchSize": 2 + }, + "comment": "comment" + }, + "commandName": "aggregate", + "databaseName": "aggregate-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "coll0", + "batchSize": 2, + "comment": { + "$$exists": false + } + }, + "commandName": "getMore", + "databaseName": "aggregate-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "coll0", + "batchSize": 2, + "comment": { + "$$exists": false + } + }, + "commandName": "getMore", + "databaseName": "aggregate-tests" + } + } + ] + } + ] } ] } diff --git a/test/crud/unified/bulkWrite-comment.json b/test/crud/unified/bulkWrite-comment.json new file mode 100644 index 000000000..fac964454 --- /dev/null +++ b/test/crud/unified/bulkWrite-comment.json @@ -0,0 +1,494 @@ +{ + "description": "bulkWrite-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "BulkWrite_comment" + } + } + ], + "initialData": [ + { + "collectionName": "BulkWrite_comment", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ], + "tests": [ + { + "description": "BulkWrite with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": 5, + "x": "inserted" + } + } + }, + { + "replaceOne": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "x": "replaced" + } + } + }, + { + "updateOne": { + "filter": { + "_id": 2 + }, + "update": { + "$set": { + "x": "updated" + } + } + } + }, + { + "deleteOne": { + "filter": { + "_id": 3 + } + } + } + ], + "comment": "comment" + }, + "expectResult": { + "deletedCount": 1, + "insertedCount": 1, + "insertedIds": { + "$$unsetOrMatches": { + "0": 5 + } + }, + "matchedCount": 2, + "modifiedCount": 2, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "BulkWrite_comment", + "documents": [ + { + "_id": 5, + "x": "inserted" + } + ], + "ordered": true, + "comment": "comment" + } + } + }, + { + "commandStartedEvent": { + "command": { + "update": "BulkWrite_comment", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "_id": 1, + "x": "replaced" + } + }, + { + "q": { + "_id": 2 + }, + "u": { + "$set": { + "x": "updated" + } + } + } + ], + "ordered": true, + "comment": "comment" + } + } + }, + { + "commandStartedEvent": { + "command": { + "delete": "BulkWrite_comment", + "deletes": [ + { + "q": { + "_id": 3 + }, + "limit": 1 + } + ], + "ordered": true, + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "BulkWrite_comment", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": "replaced" + }, + { + "_id": 2, + "x": "updated" + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": "inserted" + } + ] + } + ] + }, + { + "description": "BulkWrite with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": 5, + "x": "inserted" + } + } + }, + { + "replaceOne": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "x": "replaced" + } + } + }, + { + "updateOne": { + "filter": { + "_id": 2 + }, + "update": { + "$set": { + "x": "updated" + } + } + } + }, + { + "deleteOne": { + "filter": { + "_id": 3 + } + } + } + ], + "comment": { + "key": "value" + } + }, + "expectResult": { + "deletedCount": 1, + "insertedCount": 1, + "insertedIds": { + "$$unsetOrMatches": { + "0": 5 + } + }, + "matchedCount": 2, + "modifiedCount": 2, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "BulkWrite_comment", + "documents": [ + { + "_id": 5, + "x": "inserted" + } + ], + "ordered": true, + "comment": { + "key": "value" + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "update": "BulkWrite_comment", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "_id": 1, + "x": "replaced" + } + }, + { + "q": { + "_id": 2 + }, + "u": { + "$set": { + "x": "updated" + } + } + } + ], + "ordered": true, + "comment": { + "key": "value" + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "delete": "BulkWrite_comment", + "deletes": [ + { + "q": { + "_id": 3 + }, + "limit": 1 + } + ], + "ordered": true, + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "BulkWrite_comment", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": "replaced" + }, + { + "_id": 2, + "x": "updated" + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": "inserted" + } + ] + } + ] + }, + { + "description": "BulkWrite with comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": 5, + "x": "inserted" + } + } + }, + { + "replaceOne": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "x": "replaced" + } + } + }, + { + "updateOne": { + "filter": { + "_id": 2 + }, + "update": { + "$set": { + "x": "updated" + } + } + } + }, + { + "deleteOne": { + "filter": { + "_id": 3 + } + } + } + ], + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "BulkWrite_comment", + "documents": [ + { + "_id": 5, + "x": "inserted" + } + ], + "ordered": true, + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "BulkWrite_comment", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ] + } + ] +} diff --git a/test/crud/unified/deleteMany-comment.json b/test/crud/unified/deleteMany-comment.json new file mode 100644 index 000000000..ea6a8524d --- /dev/null +++ b/test/crud/unified/deleteMany-comment.json @@ -0,0 +1,244 @@ +{ + "description": "deleteMany-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2, + "name": "name2" + }, + { + "_id": 3, + "name": "name3" + } + ] + } + ], + "tests": [ + { + "description": "deleteMany with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "deleteMany", + "object": "collection0", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "comment": "comment" + }, + "expectResult": { + "deletedCount": 2 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "limit": 0 + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "deleteMany with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "deleteMany", + "object": "collection0", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "comment": { + "key": "value" + } + }, + "expectResult": { + "deletedCount": 2 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "limit": 0 + } + ], + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "deleteMany with comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "deleteMany", + "object": "collection0", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "limit": 0 + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2, + "name": "name2" + }, + { + "_id": 3, + "name": "name3" + } + ] + } + ] + } + ] +} diff --git a/test/crud/unified/deleteOne-comment.json b/test/crud/unified/deleteOne-comment.json new file mode 100644 index 000000000..37f356ec6 --- /dev/null +++ b/test/crud/unified/deleteOne-comment.json @@ -0,0 +1,242 @@ +{ + "description": "deleteOne-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2, + "name": "name" + }, + { + "_id": 3, + "name": "name" + } + ] + } + ], + "tests": [ + { + "description": "deleteOne with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "deleteOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": "comment" + }, + "expectResult": { + "deletedCount": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": 1 + }, + "limit": 1 + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 2, + "name": "name" + }, + { + "_id": 3, + "name": "name" + } + ] + } + ] + }, + { + "description": "deleteOne with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "deleteOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": { + "key": "value" + } + }, + "expectResult": { + "deletedCount": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": 1 + }, + "limit": 1 + } + ], + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 2, + "name": "name" + }, + { + "_id": 3, + "name": "name" + } + ] + } + ] + }, + { + "description": "deleteOne with comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "deleteOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": 1 + }, + "limit": 1 + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2, + "name": "name" + }, + { + "_id": 3, + "name": "name" + } + ] + } + ] + } + ] +} diff --git a/test/crud/unified/find-comment.json b/test/crud/unified/find-comment.json new file mode 100644 index 000000000..6000bb017 --- /dev/null +++ b/test/crud/unified/find-comment.json @@ -0,0 +1,298 @@ +{ + "description": "find-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + }, + { + "_id": 6, + "x": 66 + } + ] + } + ], + "tests": [ + { + "description": "find with string comment", + "runOnRequirements": [ + { + "minServerVersion": "3.6" + } + ], + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": "comment" + }, + "expectResult": [ + { + "_id": 1 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": { + "_id": 1 + }, + "comment": "comment" + } + } + } + ] + } + ] + }, + { + "description": "find with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": { + "key": "value" + } + }, + "expectResult": [ + { + "_id": 1 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": { + "_id": 1 + }, + "comment": { + "key": "value" + } + } + } + } + ] + } + ] + }, + { + "description": "find with document comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99", + "minServerVersion": "3.6" + } + ], + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": { + "key": "value" + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": { + "_id": 1 + }, + "comment": { + "key": "value" + } + } + } + } + ] + } + ] + }, + { + "description": "find with comment does not set comment on getMore", + "runOnRequirements": [ + { + "minServerVersion": "3.6" + } + ], + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "batchSize": 2, + "comment": "comment" + }, + "expectResult": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + }, + { + "_id": 6, + "x": 66 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": { + "_id": { + "$gt": 1 + } + }, + "batchSize": 2, + "comment": "comment" + } + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "coll0", + "batchSize": 2, + "comment": { + "$$exists": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "coll0", + "batchSize": 2, + "comment": { + "$$exists": false + } + } + } + } + ] + } + ] + } + ] +} diff --git a/test/crud/unified/findOneAndDelete-comment.json b/test/crud/unified/findOneAndDelete-comment.json new file mode 100644 index 000000000..6853b9cc2 --- /dev/null +++ b/test/crud/unified/findOneAndDelete-comment.json @@ -0,0 +1,211 @@ +{ + "description": "findOneAndDelete-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "findOneAndDelete with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "findOneAndDelete", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": "comment" + }, + "expectResult": { + "_id": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "remove": true, + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "findOneAndDelete with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "findOneAndDelete", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": { + "key": "value" + } + }, + "expectResult": { + "_id": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "remove": true, + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "findOneAndDelete with comment - pre 4.4", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "findOneAndDelete", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "remove": true, + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} diff --git a/test/crud/unified/findOneAndReplace-comment.json b/test/crud/unified/findOneAndReplace-comment.json new file mode 100644 index 000000000..f817bb693 --- /dev/null +++ b/test/crud/unified/findOneAndReplace-comment.json @@ -0,0 +1,234 @@ +{ + "description": "findOneAndReplace-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "findOneAndReplace with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "findOneAndReplace", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 5 + }, + "comment": "comment" + }, + "expectResult": { + "_id": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": { + "x": 5 + }, + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 5 + }, + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "findOneAndReplace with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "findOneAndReplace", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 5 + }, + "comment": { + "key": "value" + } + }, + "expectResult": { + "_id": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": { + "x": 5 + }, + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 5 + }, + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "findOneAndReplace with comment - pre 4.4", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "findOneAndReplace", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 5 + }, + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": { + "x": 5 + }, + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} diff --git a/test/crud/unified/findOneAndUpdate-comment.json b/test/crud/unified/findOneAndUpdate-comment.json new file mode 100644 index 000000000..6dec5b39e --- /dev/null +++ b/test/crud/unified/findOneAndUpdate-comment.json @@ -0,0 +1,228 @@ +{ + "description": "findOneAndUpdate-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "findOneAndUpdate with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "x": 5 + } + } + ], + "comment": "comment" + }, + "expectResult": { + "_id": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": [ + { + "$set": { + "x": 5 + } + } + ], + "comment": "comment" + } + } + } + ] + } + ] + }, + { + "description": "findOneAndUpdate with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "x": 5 + } + } + ], + "comment": { + "key": "value" + } + }, + "expectResult": { + "_id": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": [ + { + "$set": { + "x": 5 + } + } + ], + "comment": { + "key": "value" + } + } + } + } + ] + } + ] + }, + { + "description": "findOneAndUpdate with comment - pre 4.4", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "x": 5 + } + } + ], + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": [ + { + "$set": { + "x": 5 + } + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} diff --git a/test/crud/unified/insertMany-comment.json b/test/crud/unified/insertMany-comment.json new file mode 100644 index 000000000..7e835e801 --- /dev/null +++ b/test/crud/unified/insertMany-comment.json @@ -0,0 +1,225 @@ +{ + "description": "insertMany-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "insertMany with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "insertMany", + "object": "collection0", + "arguments": { + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": "comment" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "insertMany with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "insertMany", + "object": "collection0", + "arguments": { + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": { + "key": "value" + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "insertMany with comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "insertMany", + "object": "collection0", + "arguments": { + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ] + } + ] +} diff --git a/test/crud/unified/insertOne-comment.json b/test/crud/unified/insertOne-comment.json new file mode 100644 index 000000000..a9f735ab6 --- /dev/null +++ b/test/crud/unified/insertOne-comment.json @@ -0,0 +1,219 @@ +{ + "description": "insertOne-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "insertOne with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 2, + "x": 22 + }, + "comment": "comment" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "insertOne with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 2, + "x": 22 + }, + "comment": { + "key": "value" + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "insertOne with comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 2, + "x": 22 + }, + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ] + } + ] +} diff --git a/test/crud/unified/replaceOne-comment.json b/test/crud/unified/replaceOne-comment.json new file mode 100644 index 000000000..02fe90a44 --- /dev/null +++ b/test/crud/unified/replaceOne-comment.json @@ -0,0 +1,229 @@ +{ + "description": "replaceOne-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "ReplaceOne with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "replaceOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 22 + }, + "comment": "comment" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "x": 22 + } + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 22 + } + ] + } + ] + }, + { + "description": "ReplaceOne with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "replaceOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 22 + }, + "comment": { + "key": "value" + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "x": 22 + } + } + ], + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 22 + } + ] + } + ] + }, + { + "description": "ReplaceOne with comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "replaceOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 22 + }, + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "x": 22 + } + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ] + } + ] +} diff --git a/test/crud/unified/updateMany-comment.json b/test/crud/unified/updateMany-comment.json new file mode 100644 index 000000000..26abd92ed --- /dev/null +++ b/test/crud/unified/updateMany-comment.json @@ -0,0 +1,244 @@ +{ + "description": "updateMany-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "UpdateMany with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "updateMany", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 22 + } + }, + "comment": "comment" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "$set": { + "x": 22 + } + }, + "multi": true + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 22 + } + ] + } + ] + }, + { + "description": "UpdateMany with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "updateMany", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 22 + } + }, + "comment": { + "key": "value" + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "$set": { + "x": 22 + } + }, + "multi": true + } + ], + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 22 + } + ] + } + ] + }, + { + "description": "UpdateMany with comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "updateMany", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 22 + } + }, + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "$set": { + "x": 22 + } + }, + "multi": true + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ] + } + ] +} diff --git a/test/crud/unified/updateOne-comment.json b/test/crud/unified/updateOne-comment.json new file mode 100644 index 000000000..9b3b71d39 --- /dev/null +++ b/test/crud/unified/updateOne-comment.json @@ -0,0 +1,241 @@ +{ + "description": "updateOne-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "UpdateOne with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 22 + } + }, + "comment": "comment" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "$set": { + "x": 22 + } + } + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 22 + } + ] + } + ] + }, + { + "description": "UpdateOne with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 22 + } + }, + "comment": { + "key": "value" + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "$set": { + "x": 22 + } + } + } + ], + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 22 + } + ] + } + ] + }, + { + "description": "UpdateOne with comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 22 + } + }, + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "$set": { + "x": 22 + } + } + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ] + } + ] +} diff --git a/test/test_comment.py b/test/test_comment.py new file mode 100644 index 000000000..1c0e74162 --- /dev/null +++ b/test/test_comment.py @@ -0,0 +1,183 @@ +# Copyright 2022-present MongoDB, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Test the keyword argument 'comment' in various helpers.""" + +import inspect +import sys +from collections import defaultdict +from typing import Any, Union + +sys.path[0:0] = [""] + +from test import IntegrationTest, SkipTest, client_context, unittest +from test.utils import EventListener, rs_or_single_client + +from bson.dbref import DBRef +from pymongo.collection import Collection +from pymongo.command_cursor import CommandCursor +from pymongo.database import Database +from pymongo.mongo_client import MongoClient +from pymongo.operations import IndexModel +from pymongo.read_concern import ReadConcern +from pymongo.read_preferences import ReadPreference +from pymongo.write_concern import WriteConcern + + +class Empty(object): + def __getattr__(self, item): + try: + self.__dict__[item] + except KeyError: + return self.empty + + def empty(self, *args, **kwargs): + return Empty() + + +class TestComment(IntegrationTest): + def _test_ops(self, helpers, already_supported, listener, db=Empty(), coll=Empty()): + results = listener.results + for h, args in helpers: + c = "testing comment with " + h.__name__ + with self.subTest("collection-" + h.__name__ + "-comment"): + for cc in [c, {"key": c}, ["any", 1]]: + results.clear() + kwargs = {"comment": cc} + if h == coll.rename: + tmp = db.get_collection("temp_temp_temp").drop() + destruct_coll = db.get_collection("test_temp") + destruct_coll.insert_one({}) + maybe_cursor = destruct_coll.rename(*args, **kwargs) + destruct_coll.drop() + elif h == db.validate_collection: + coll = db.get_collection("test") + coll.insert_one({}) + maybe_cursor = db.validate_collection(*args, **kwargs) + else: + coll.create_index("a") + maybe_cursor = h(*args, **kwargs) + self.assertIn( + "comment", + inspect.signature(h).parameters, + msg="Could not find 'comment' in the " + "signature of function %s" % (h.__name__), + ) + self.assertEqual( + inspect.signature(h).parameters["comment"].annotation, Union[Any, None] + ) + if isinstance(maybe_cursor, CommandCursor): + maybe_cursor.close() + tested = False + # For some reason collection.list_indexes creates two commands and the first + # one doesn't contain 'comment'. + for i in results["started"]: + if cc == i.command.get("comment", ""): + self.assertEqual(cc, i.command["comment"]) + tested = True + self.assertTrue(tested) + if h not in [coll.aggregate_raw_batches]: + self.assertIn( + "`comment` (optional):", + h.__doc__, + ) + if h not in already_supported: + self.assertIn( + "Added ``comment`` parameter", + h.__doc__, + ) + else: + self.assertNotIn( + "Added ``comment`` parameter", + h.__doc__, + ) + + results.clear() + + @client_context.require_version_min(4, 7, -1) + @client_context.require_replica_set + def test_database_helpers(self): + listener = EventListener() + db = rs_or_single_client(event_listeners=[listener]).db + helpers = [ + (db.watch, []), + (db.command, ["hello"]), + (db.list_collections, []), + (db.list_collection_names, []), + (db.drop_collection, ["hello"]), + (db.validate_collection, ["test"]), + (db.dereference, [DBRef("collection", 1)]), + ] + already_supported = [db.command, db.list_collections, db.list_collection_names] + self._test_ops(helpers, already_supported, listener, db=db, coll=db.get_collection("test")) + + @client_context.require_version_min(4, 7, -1) + @client_context.require_replica_set + def test_client_helpers(self): + listener = EventListener() + cli = rs_or_single_client(event_listeners=[listener]) + helpers = [ + (cli.watch, []), + (cli.list_databases, []), + (cli.list_database_names, []), + (cli.drop_database, ["test"]), + ] + already_supported = [ + cli.list_databases, + ] + self._test_ops(helpers, already_supported, listener) + + @client_context.require_version_min(4, 7, -1) + def test_collection_helpers(self): + listener = EventListener() + db = rs_or_single_client(event_listeners=[listener])[self.db.name] + coll = db.get_collection("test") + + helpers = [ + (coll.list_indexes, []), + (coll.drop, []), + (coll.index_information, []), + (coll.options, []), + (coll.aggregate, [[{"$set": {"x": 1}}]]), + (coll.aggregate_raw_batches, [[{"$set": {"x": 1}}]]), + (coll.rename, ["temp_temp_temp"]), + (coll.distinct, ["_id"]), + (coll.find_one_and_delete, [{}]), + (coll.find_one_and_replace, [{}, {}]), + (coll.find_one_and_update, [{}, {"$set": {"a": 1}}]), + (coll.estimated_document_count, []), + (coll.count_documents, [{}]), + (coll.create_indexes, [[IndexModel("a")]]), + (coll.create_index, ["a"]), + (coll.drop_index, [[("a", 1)]]), + (coll.drop_indexes, []), + ] + already_supported = [ + coll.estimated_document_count, + coll.count_documents, + coll.create_indexes, + coll.drop_indexes, + coll.options, + coll.find_one_and_replace, + coll.drop_index, + coll.rename, + coll.distinct, + coll.find_one_and_delete, + coll.find_one_and_update, + ] + self._test_ops(helpers, already_supported, listener, coll=coll, db=db) + + +if __name__ == "__main__": + unittest.main()