Send a query or getmore operation and handles the response. If operation is ``None`` this is an exhaust cursor, which reads the next result batch off the exhaust socket instead of sending getMore messages to the server. Can raise ConnectionFailure.
(self, operation: Union[_Query, _GetMore])
| 970 | return await self._collection.distinct(key, session=self._session, **options) |
| 971 | |
| 972 | async def _send_message(self, operation: Union[_Query, _GetMore]) -> None: |
| 973 | """Send a query or getmore operation and handles the response. |
| 974 | |
| 975 | If operation is ``None`` this is an exhaust cursor, which reads |
| 976 | the next result batch off the exhaust socket instead of |
| 977 | sending getMore messages to the server. |
| 978 | |
| 979 | Can raise ConnectionFailure. |
| 980 | """ |
| 981 | client = self._collection.database.client |
| 982 | # OP_MSG is required to support exhaust cursors with encryption. |
| 983 | if client._encrypter and self._exhaust: |
| 984 | raise InvalidOperation("exhaust cursors do not support auto encryption") |
| 985 | |
| 986 | try: |
| 987 | response = await client._run_operation( |
| 988 | operation, self._unpack_response, address=self._address |
| 989 | ) |
| 990 | except OperationFailure as exc: |
| 991 | if exc.code in _CURSOR_CLOSED_ERRORS or self._exhaust: |
| 992 | # Don't send killCursors because the cursor is already closed. |
| 993 | self._killed = True |
| 994 | if exc.timeout: |
| 995 | self._die_no_lock() |
| 996 | else: |
| 997 | await self.close() |
| 998 | # If this is a tailable cursor the error is likely |
| 999 | # due to capped collection roll over. Setting |
| 1000 | # self._killed to True ensures AsyncCursor.alive will be |
| 1001 | # False. No need to re-raise. |
| 1002 | if ( |
| 1003 | exc.code in _CURSOR_CLOSED_ERRORS |
| 1004 | and self._query_flags & _QUERY_OPTIONS["tailable_cursor"] |
| 1005 | ): |
| 1006 | return |
| 1007 | raise |
| 1008 | except ConnectionFailure: |
| 1009 | self._killed = True |
| 1010 | await self.close() |
| 1011 | raise |
| 1012 | # Catch KeyboardInterrupt, CancelledError, etc. and cleanup. |
| 1013 | except BaseException: |
| 1014 | await self.close() |
| 1015 | raise |
| 1016 | self._address = response.address |
| 1017 | if isinstance(response, PinnedResponse): |
| 1018 | if not self._sock_mgr: |
| 1019 | self._sock_mgr = _ConnectionManager(response.conn, response.more_to_come) # type: ignore[arg-type] |
| 1020 | |
| 1021 | cmd_name = operation.name |
| 1022 | docs = response.docs |
| 1023 | if response.from_command: |
| 1024 | if cmd_name != "explain": |
| 1025 | cursor = docs[0]["cursor"] |
| 1026 | self._id = cursor["id"] |
| 1027 | if cmd_name == "find": |
| 1028 | documents = cursor["firstBatch"] |
| 1029 | # Update the namespace used for future getMore commands. |
no test coverage detected