80 lines
3.1 KiB
Python
80 lines
3.1 KiB
Python
# 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)
|