# Copyright 2024-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. """Constants, types, and classes shared across Client Bulk Write API implementations.""" from __future__ import annotations from typing import TYPE_CHECKING, Any, Mapping, MutableMapping, NoReturn from pymongo.errors import ClientBulkWriteException, OperationFailure from pymongo.helpers_shared import _get_wce_doc if TYPE_CHECKING: from pymongo.typings import _DocumentOut def _merge_command( ops: list[tuple[str, Mapping[str, Any]]], offset: int, full_result: MutableMapping[str, Any], result: Mapping[str, Any], ) -> None: """Merge result of a single bulk write batch into the full result.""" if result.get("error"): full_result["error"] = result["error"] full_result["nInserted"] += result.get("nInserted", 0) full_result["nDeleted"] += result.get("nDeleted", 0) full_result["nMatched"] += result.get("nMatched", 0) full_result["nModified"] += result.get("nModified", 0) full_result["nUpserted"] += result.get("nUpserted", 0) write_errors = result.get("writeErrors") if write_errors: for doc in write_errors: # Leave the server response intact for APM. replacement = doc.copy() original_index = doc["idx"] + offset replacement["idx"] = original_index # Add the failed operation to the error document. replacement["op"] = ops[original_index][1] full_result["writeErrors"].append(replacement) wce = _get_wce_doc(result) if wce: full_result["writeConcernErrors"].append(wce) def _throw_client_bulk_write_exception( full_result: _DocumentOut, verbose_results: bool ) -> NoReturn: """Raise a ClientBulkWriteException from the full result.""" # retryWrites on MMAPv1 should raise an actionable error. if full_result["writeErrors"]: full_result["writeErrors"].sort(key=lambda error: error["idx"]) err = full_result["writeErrors"][0] code = err["code"] msg = err["errmsg"] if code == 20 and msg.startswith("Transaction numbers"): errmsg = ( "This MongoDB deployment does not support " "retryable writes. Please add retryWrites=false " "to your connection string." ) raise OperationFailure(errmsg, code, full_result) if isinstance(full_result["error"], BaseException): raise ClientBulkWriteException(full_result, verbose_results) from full_result["error"] raise ClientBulkWriteException(full_result, verbose_results)