Source code for aerospike_sdk.record_result

# Copyright 2025-2026 Aerospike, Inc.
#
# Portions may be licensed to Aerospike, Inc. under one or more contributor
# license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0.
#
# 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.

"""RecordResult — per-record outcome for batch and query operations."""

from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING, Any

from aerospike_async import Key, Record
from aerospike_async.exceptions import ResultCode

from aerospike_sdk.exceptions import _result_code_to_exception

if TYPE_CHECKING:  # Not unused — needed for forward-reference type annotations and Sphinx autodoc.
    from aerospike_async import BatchRecord
    from aerospike_sdk.exceptions import AerospikeError


[docs] @dataclass(frozen=True, slots=True) class RecordResult: """One row from a batch, query stream, or single-key SDK call. Inspect :attr:`is_ok` and :attr:`result_code` for outcome; use :meth:`or_raise` or :meth:`record_or_raise` when failures should throw. Foreground UDF success values appear in :attr:`udf_result` when returned by the server. Attributes: key: Target :class:`~aerospike_async.Key` for this row. record: :class:`~aerospike_async.Record` payload, or ``None`` if not returned (errors, not found, or UDF error rows). result_code: Server :class:`~aerospike_async.exceptions.ResultCode`. in_doubt: ``True`` when a write may have completed despite an error. index: Batch position, or ``0`` / ``-1`` depending on origin. exception: Embedded :class:`~aerospike_sdk.exceptions.AerospikeError` when the client placed an error in-stream instead of raising. udf_result: Lua return value for successful foreground UDF calls. Example: Inspect a row from a stream:: row = await stream.first() if row and row.is_ok: bins = row.record.bins if row.record else {} elif row: row.or_raise() See Also: :class:`~aerospike_sdk.record_stream.RecordStream`: Async iteration of results. """ key: Key record: Record | None result_code: ResultCode in_doubt: bool = False index: int = -1 exception: AerospikeError | None = None udf_result: Any | None = None @property def is_ok(self) -> bool: """Whether :attr:`result_code` is ``ResultCode.OK``. Returns: ``True`` on success; ``False`` for any other result code. Example:: row = await stream.first() if row is not None and row.is_ok and row.record: bins = row.record.bins """ return self.result_code == ResultCode.OK
[docs] def or_raise(self) -> RecordResult: """Return ``self`` if successful, else raise from :attr:`exception` or result code. Returns: This instance when :attr:`is_ok` is true. Raises: AerospikeError: If :attr:`exception` is set (embedded client error). AerospikeError: Otherwise, from :attr:`result_code` via :func:`~aerospike_sdk.exceptions._result_code_to_exception` (usually a specific subclass; unmapped codes use the base type). Example:: row = await stream.first() if row is not None: row.or_raise() """ if not self.is_ok: if self.exception is not None: raise self.exception raise _result_code_to_exception( self.result_code, str(self.result_code), self.in_doubt ) return self
[docs] def record_or_raise(self) -> Record: """Return :attr:`record`, raising if the result is not OK. Returns: The non-``None`` :class:`~aerospike_async.Record`. Raises: Same as :meth:`or_raise`, plus ``ValueError`` if the result is OK but :attr:`record` is ``None`` (unexpected empty payload). Example: rec = (await stream.first_or_raise()).record_or_raise() """ self.or_raise() if self.record is None: raise ValueError("Record is None despite ResultCode.OK") return self.record
[docs] def as_bool(self) -> bool: """Interpret the row as an existence check (for example after :meth:`Session.exists`). Returns: ``True`` if the key exists (OK result). ``False`` if the result is key-not-found. Raises: AerospikeError: For any other non-OK code (via :meth:`or_raise`). Example: found = (await exists_stream.first_or_raise()).as_bool() """ if self.is_ok: return True if self.result_code == ResultCode.KEY_NOT_FOUND_ERROR: return False self.or_raise() return False # unreachable
def batch_records_to_results( batch_records: list[BatchRecord] | tuple[BatchRecord, ...], ) -> list[RecordResult]: """Convert ``BatchRecord`` entries to :class:`RecordResult` (library internal). Args: batch_records: Sequence of :class:`~aerospike_async.BatchRecord` from the async client. Returns: Parallel list with :attr:`~RecordResult.index` set to each row's position in ``batch_records``. """ return [ RecordResult( key=br.key, record=br.record, result_code=br.result_code if br.result_code is not None else ResultCode.OK, in_doubt=br.in_doubt, index=i, ) for i, br in enumerate(batch_records) ]