Source code for borneo.operations

#
# Copyright (c) 2018, 2023 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
#  https://oss.oracle.com/licenses/upl/
#
from abc import abstractmethod
from datetime import datetime
from decimal import Context, ROUND_HALF_EVEN
from json import loads
from time import sleep, time

from dateutil import tz

from .common import (
    CheckValue, Consistency, Durability, FieldRange, PreparedStatement,
    PutOption, State, SystemState, TableLimits, TimeToLive, Version,
    deprecated)
from .exception import (
    IllegalArgumentException, RequestTimeoutException)
from .http import RateLimiter
from .serde import (
    DeleteRequestSerializer, GetIndexesRequestSerializer,
    GetRequestSerializer, GetTableRequestSerializer, ListTablesRequestSerializer,
    MultiDeleteRequestSerializer,
    PrepareRequestSerializer, PutRequestSerializer, QueryRequestSerializer,
    SystemRequestSerializer, SystemStatusRequestSerializer,
    TableRequestSerializer, TableUsageRequestSerializer,
    WriteMultipleRequestSerializer)
from .serdeutil import SerdeUtil

try:
    from . import config
    from . import serdeutil
except ImportError:
    import config
    import serdeutil

import borneo.nson


[docs]class Request(object): """ A request is a class used as a base for all requests types. Public state and methods are implemented by extending classes. This pattern is used so that fluent construction works properly for the extending classes """ def __init__(self): # Cloud service only. self._compartment = None self._read_rate_limiter = None self._retry_stats = None self._start_time_ms = 0 self._table_name = None self._timeout_ms = 0 self._write_rate_limiter = None self._rate_limit_delayed_ms = 0 self._namespace = None def add_retry_delay_ms(self, millis): """ Internal use only. This adds time to the total time spent processing retries during a single request processing operation. :param millis: millis time to add to retry delay value :type millis: int """ if self._retry_stats is None: self._retry_stats = RetryStats() self._retry_stats.add_delay_ms(millis) def add_retry_exception(self, re): """ Internal use only. This adds (or increments) a class type to the list of exceptions that were processed during retries of a single request operation. :param re: class of exception to add to retry stats. :type re: Exception """ if self._retry_stats is None: self._retry_stats = RetryStats() self._retry_stats.add_exception(re) def does_reads(self): """ Internal use only. :returns: True if the request expects to do reads (incur read units). :rtype: boolean """ return False def does_writes(self): """ Internal use only. :returns: True if the request expects to do writes (incur write units). :rtype: boolean """ return False def get_compartment(self): """ Cloud service only. Get the compartment id or name if set for the request. :returns: compartment id or name if set for the request, otherwise None if not set. :rtype: str """ return self._compartment def get_num_retries(self): """ Internal use only. :returns: number of retries. :rtype: int """ if self._retry_stats is None: return 0 return self._retry_stats.get_retries() def get_read_rate_limiter(self): """ Cloud service only. Returns the read rate limiter instance used during this request. This will be the value supplied via :py:meth:`set_read_rate_limiter`, or if that was not called, it may be an instance of an internal rate limiter that was configured internally during request processing. This is supplied for stats and tracing/debugging only. The returned limiter should be treated as read-only. :returns: the rate limiter instance used for read operations, or None if no limiter was used. :rtype: RateLimiter """ return self._read_rate_limiter def get_retry_delay_ms(self): """ Internal use only. :returns: the time spent in retries, in milliseconds. :rtype: int """ if self._retry_stats is None: return 0 return self._retry_stats.get_delay_ms() def get_retry_stats(self): """ Returns a stats object with information about retries. This may be used during a retry handler or after a request has completed or thrown an exception. :returns: stats object with retry information, or None if no retries were performed. :rtype: RetryStats """ return self._retry_stats def get_start_time_ms(self): """ Internal use only. :returns: the start time of request processing. :returns: int """ return self._start_time_ms def get_table_name(self): """ Returns the table name to use for the operation. :returns: the table name, or None if not set. :returns: str """ return self._table_name def get_timeout(self): return self._timeout_ms def get_write_rate_limiter(self): """ Cloud service only. Returns the write rate limiter instance used during this request. This will be the value supplied via :py:meth:`set_write_rate_limiter`, or if that was not called, it may be an instance of an internal rate limiter that was configured internally during request processing. This is supplied for stats and tracing/debugging only. The returned limiter should be treated as read-only. :returns: the rate limiter instance used for write operations, or None if no limiter was used. :rtype: RateLimiter """ return self._write_rate_limiter def is_query_request(self): return False def increment_retries(self): """ Internal use only. Increments the number of retries during the request operation. """ if self._retry_stats is None: self._retry_stats = RetryStats() self._retry_stats.increment_retries() def set_compartment_internal(self, compartment): """ Internal use only. Sets the compartment id or name to use for the operation. :param compartment: the compartment name or id. :type compartment: str or None. :raises IllegalArgumentException: raises the exception if compartment is not a str or None. """ CheckValue.check_str(compartment, 'compartment', True) self._compartment = compartment def set_defaults(self, cfg): """ Internal use only. Sets default values in a request based on the specified config object. This will typically be overridden by subclasses. :param cfg: the configuration object to use to get default values. :type cfg: NoSQLHandleConfig :returns: self. :raises IllegalArgumentException: raises the exception if cfg is not an instance of NoSQLHandleConfig. """ self._check_config(cfg) if self._timeout_ms == 0: self._timeout_ms = cfg.get_default_timeout() return self def set_read_rate_limiter(self, rate_limiter): """ Cloud service only. Sets a read rate limiter to use for this request. This will override any internal rate limiter that may have otherwise been used during request processing, and it will be used regardless of any rate limiter config. :param rate_limiter: the rate limiter instance to use for read operations. :type rate_limiter: RateLimiter :returns: self. :raises IllegalArgumentException: raises the exception if rate_limiter is not an instance of RateLimiter. """ self._check_rate_limiter(rate_limiter, 'set_read_rate_limiter') self._read_rate_limiter = rate_limiter return self def set_retry_stats(self, retry_stats): """ Internal use only. This is typically set by internal request processing when the first retry is attempted. It is used/updated thereafter on subsequent retry attempts. :param retry_stats: the stats object to use. :type retry_stats: RetryStats :returns: self. :raises IllegalArgumentException: raises the exception if retry_stats is not an instance of RetryStats. """ if retry_stats is not None and not isinstance(retry_stats, RetryStats): raise IllegalArgumentException( 'set_retry_stats requires an instance of RetryStats as ' + 'parameter.') self._retry_stats = retry_stats return self def set_start_time_ms(self, start_time_ms): """ Internal use only. :param start_time_ms: the start time of request processing. :type start_time_ms: int """ self._start_time_ms = start_time_ms def set_write_rate_limiter(self, rate_limiter): """ Cloud service only. Sets a write rate limiter to use for this request. This will override any internal rate limiter that may have otherwise been used during request processing, and it will be used regardless of any rate limiter config. :param rate_limiter: the rate limiter instance to use for write operations. :type rate_limiter: RateLimiter :returns: self. :raises IllegalArgumentException: raises the exception if rate_limiter is not an instance of RateLimiter. """ self._check_rate_limiter(rate_limiter, 'set_write_rate_limiter') self._write_rate_limiter = rate_limiter return self def should_retry(self): # Returns True if this request should be retried. return True def set_table_name(self, table_name): """ Internal use only. Sets the table name to use for the operation. :param table_name: the table name. :type table_name: str or None :raises IllegalArgumentException: raises the exception if table_name is not a string. """ CheckValue.check_str(table_name, 'table_name', True) self._table_name = table_name def set_namespace(self, namespace): """ Internal use only On-premises only Sets the namespace to use for the operation. This will override any configured default value. :param namespace: the namespace :type namespace: str :raises IllegalArgumentException: raises the exception if namespace is not a string. :versionadded: 5.4.0 """ CheckValue.check_str(namespace, 'namespace', True) self._namespace = namespace def get_namespace(self): """ On-premises only Returns the namespace to use for the operation or None if not set. :returns: namespace, or None if not set. :rtype: str :versionadded: 5.4.0 """ return self._namespace def _set_timeout(self, timeout_ms): CheckValue.check_int_gt_zero(timeout_ms, 'timeout_ms') self._timeout_ms = timeout_ms def get_rate_limit_delayed_ms(self): """ Get the time the operation was delayed due to rate limiting. Cloud only. If rate limiting is in place, this value will represent the number of milliseconds that the operation was delayed due to rate limiting. If the value is zero, rate limiting did not apply or the operation did not need to wait for rate limiting. :returns: delay time in milliseconds. """ return self._rate_limit_delayed_ms def set_rate_limit_delayed_ms(self, delay_ms): """ Set the time the operation was delayed due to rate limiting. :param delay_ms: the delay in milliseconds. :type delay_ms: int :returns: self. """ self._rate_limit_delayed_ms = delay_ms return self @staticmethod def _check_config(cfg): if not isinstance(cfg, config.NoSQLHandleConfig): raise IllegalArgumentException( 'set_defaults requires an instance of NoSQLHandleConfig as ' + 'parameter.') @staticmethod def _check_rate_limiter(rate_limiter, name): if (rate_limiter is not None and not isinstance(rate_limiter, RateLimiter)): raise IllegalArgumentException( name + ' requires an instance of RateLimiter as parameter.') @abstractmethod def get_request_name(self): # type () -> str pass
class WriteRequest(Request): """ Represents a base class for the single row modifying operations :py:meth:`NoSQLHandle.put` and :py:meth:`NoSQLHandle.delete`. This class encapsulates the common parameters of table name and the return row boolean, which allows applications to get information about the existing value of the target row on failure. By default no previous information is returned. """ def __init__(self): super(WriteRequest, self).__init__() self._return_row = False self._durability = None def __str__(self): return 'WriteRequest' def does_writes(self): return True def _set_return_row(self, return_row): CheckValue.check_boolean(return_row, 'return_row') self._return_row = return_row def _get_return_row(self): return self._return_row def _set_durability(self, dur): if dur is None: self._durability = None return if not isinstance(dur, Durability): raise IllegalArgumentException('set_durability requires an ' + 'instance of Durability as parameter.') dur.validate() self._durability = dur def _get_durability(self): return self._durability def _validate_write_request(self, request_name): if self.get_table_name() is None: raise IllegalArgumentException( "{} requires table name".format(request_name)) def get_durability(self): pass def get_request_name(self): # type: () -> str return "Write" @staticmethod def get_type_name(): # type: () -> str return "Write" class ReadRequest(Request): """ Represents a base class for read operations such as :py:meth:`NoSQLHandle.get`. This class encapsulates the common parameters of table name and consistency. By default read operations use Consistency.EVENTUAL. Use of Consistency.ABSOLUTE should be used only when required as it incurs additional cost. """ def __init__(self): super(ReadRequest, self).__init__() self._consistency = None def __str__(self): return 'ReadRequest' def does_reads(self): return True def set_defaults(self, cfg): super(ReadRequest, self).set_defaults(cfg) if self._consistency is None: self._set_consistency(cfg.get_default_consistency()) return self def _set_consistency(self, consistency): if (consistency != Consistency.ABSOLUTE and consistency != Consistency.EVENTUAL): raise IllegalArgumentException( 'Consistency must be Consistency.ABSOLUTE or ' + 'Consistency.EVENTUAL') self._consistency = consistency def _get_consistency(self): return self._consistency def _validate_read_request(self, request_name): if self.get_table_name() is None: raise IllegalArgumentException( request_name + ' requires table name.') def get_request_name(self): # type: () -> str return "Read" # noinspection PyUnusedLocal
[docs]class DeleteRequest(WriteRequest): """ Represents the input to a :py:meth:`NoSQLHandle.delete` operation. This request can be used to perform unconditional and conditional deletes: * Delete any existing row. This is the default. * Succeed only if the row exists and and its :py:class:`Version` matches a specific :py:class:`Version`. Use :py:meth:`set_match_version` for this case. Using this option in conjunction with using :py:meth:`set_return_row` allows information about the existing row to be returned if the operation fails because of a version mismatch. On success no information is returned. Using :py:meth:`set_return_row` may incur additional cost and affect operation latency. The table name and key are required parameters. On a successful operation :py:meth:`DeleteResult.get_success` returns True. Additional information, such as previous row information, may be available in :py:class:`DeleteResult`. """ def __init__(self): super(DeleteRequest, self).__init__() self._key = None self._match_version = None def __str__(self): return 'DeleteRequest'
[docs] def set_key(self, key): """ Sets the key to use for the delete operation. This is a required field. :param key: the key value. :type key: dict :returns: self. :raises IllegalArgumentException: raises the exception if key is not a dictionary. """ CheckValue.check_dict(key, 'key') self._key = key return self
[docs] def set_key_from_json(self, json_key): """ Sets the key to use for the delete operation based on a JSON string. The string is parsed for validity and stored internally as a dict. :param json_key: the key as a JSON string. :type json_key: str :returns: self. :raises IllegalArgumentException: raises the exception if json_key is not a string. """ CheckValue.check_str(json_key, 'json_key') self._key = loads(json_key) return self
[docs] def get_key(self): """ Returns the key of the row to be deleted. :returns: the key value, or None if not set. :rtype: dict """ return self._key
[docs] def set_compartment(self, compartment): """ Cloud service only. Sets the name or id of a compartment to be used for this operation. The compartment may be specified as either a name (or path for nested compartments) or as an id (OCID). A name (vs id) can only be used when authenticated using a specific user identity. It is *not* available if authenticated as an Instance Principal which can be done when calling the service from a compute instance in the Oracle Cloud Infrastructure. See :py:meth:`borneo.iam.SignatureProvider.create_with_instance_principal`. :param compartment: the compartment name or id. If using a nested compartment, specify the full compartment path compartmentA.compartmentB, but exclude the name of the root compartment (tenant). :type compartment: str :returns: self. :raises IllegalArgumentException: raises the exception if compartment is not a str. """ self.set_compartment_internal(compartment) return self
[docs] def set_match_version(self, version): """ Sets the :py:class:`Version` to use for a conditional delete operation. The Version is usually obtained from :py:meth:`GetResult.get_version` or other method that returns a Version. When set, the delete operation will succeed only if the row exists and its Version matches the one specified. Using this option will incur additional cost. :param version: the :py:class:`Version` to match. :type version: Version :returns: self. :raises IllegalArgumentException: raises the exception if version is not an instance of Version. """ if not isinstance(version, Version): raise IllegalArgumentException('set_match_version requires an ' + 'instance of Version as parameter.') self._match_version = version return self
[docs] def get_match_version(self): """ Returns the :py:class:`Version` used for a match on a conditional delete. :returns: the Version or None if not set. :rtype: Version """ return self._match_version
[docs] def set_timeout(self, timeout_ms): """ Sets the optional request timeout value, in milliseconds. This overrides any default value set in :py:class:`NoSQLHandleConfig`. The value must be positive. :param timeout_ms: the timeout value, in milliseconds. :type timeout_ms: int :returns: self. :raises IllegalArgumentException: raises the exception if the timeout value is less than or equal to 0. """ self._set_timeout(timeout_ms) return self
[docs] def get_timeout(self): """ Returns the timeout to use for the operation, in milliseconds. A value of 0 indicates that the timeout has not been set. :returns: the timeout value. :rtype: int """ return super(DeleteRequest, self).get_timeout()
[docs] def set_table_name(self, table_name): """ Sets the table name to use for the operation. This is a required parameter. :param table_name: the table name. :type table_name: str :returns: self. :raises IllegalArgumentException: raises the exception if table_name is not a string. """ super(DeleteRequest, self).set_table_name(table_name) return self
[docs] def set_return_row(self, return_row): """ Sets whether information about the existing row should be returned on failure because of a version mismatch. If a match version has not been set via :py:meth:`set_match_version` this parameter is ignored and there will be no return information. This parameter is optional and defaults to False. It's use may incur additional cost. :param return_row: set to True if information should be returned. :type return_row: bool :returns: self. :raises IllegalArgumentException: raises the exception if return_row is not True or False. """ self._set_return_row(return_row) return self
[docs] def get_return_row(self): """ Returns whether information about the existing row should be returned on failure because of a version mismatch. :returns: True if information should be returned. :rtype: bool """ return self._get_return_row()
[docs] def set_durability(self, durability): """ On-premise only. Sets the durability to use for the operation. :param durability: the Durability to use :type durability: Durability :returns: self. :raises IllegalArgumentException: raises the exception if Durability is not valid :versionadded: 5.3.0 """ self._set_durability(durability) return self
[docs] def get_durability(self): """ On-premise only. Gets the durability to use for the operation or None if not set :returns: the Durability :versionadded: 5.3.0 """ return self._get_durability()
def does_reads(self): return self._match_version is not None or self.get_return_row() def validate(self): # Validates the state of the object when complete. self._validate_write_request('DeleteRequest') if self._key is None: raise IllegalArgumentException('DeleteRequest requires a key.') @staticmethod def get_serial_version(serial_version): return serial_version @staticmethod def create_serializer(serial_version): if serial_version >= SerdeUtil.SERIAL_VERSION_4: return borneo.nson.DeleteRequestSerializer() return DeleteRequestSerializer() def get_request_name(self): # type: () -> str return "Delete"
# noinspection PyUnusedLocal
[docs]class GetIndexesRequest(Request): """ Represents the argument of a :py:meth:`NoSQLHandle.get_indexes` operation which returns the information of a specific index or all indexes of the specified table, as returned in :py:class:`GetIndexesResult`. The table name is a required parameter. """ def __init__(self): super(GetIndexesRequest, self).__init__() self._index_name = None def __str__(self): return 'GetIndexesRequest'
[docs] def set_table_name(self, table_name): """ Sets the table name to use for the request. :param table_name: the table name. This is a required parameter. :type table_name: str :returns: self. :raises IllegalArgumentException: raises the exception if table_name is not a string. """ super(GetIndexesRequest, self).set_table_name(table_name) return self
[docs] def set_compartment(self, compartment): """ Cloud service only. Sets the name or id of a compartment to be used for this operation. The compartment may be specified as either a name (or path for nested compartments) or as an id (OCID). A name (vs id) can only be used when authenticated using a specific user identity. It is *not* available if authenticated as an Instance Principal which can be done when calling the service from a compute instance in the Oracle Cloud Infrastructure. See :py:meth:`borneo.iam.SignatureProvider.create_with_instance_principal`. :param compartment: the compartment name or id. If using a nested compartment, specify the full compartment path compartmentA.compartmentB, but exclude the name of the root compartment (tenant). :type compartment: str :returns: self. :raises IllegalArgumentException: raises the exception if compartment is not a str. """ self.set_compartment_internal(compartment) return self
[docs] def set_index_name(self, index_name): """ Sets the index name to use for the request. If not set, this request will return all indexes of the table. :param index_name: the index name. :type index_name: str :returns: self. :raises IllegalArgumentException: raises the exception if index_name is not a string. """ CheckValue.check_str(index_name, 'index_name') self._index_name = index_name return self
[docs] def get_index_name(self): """ Gets the index name to use for the request. :returns: the index name. :rtype: str """ return self._index_name
[docs] def set_timeout(self, timeout_ms): """ Sets the request timeout value, in milliseconds. This overrides any default value set in :py:class:`NoSQLHandleConfig`. The value must be positive. :param timeout_ms: the timeout value, in milliseconds. :type timeout_ms: int :returns: self. :raises IllegalArgumentException: raises the exception if the timeout value is less than or equal to 0. """ self._set_timeout(timeout_ms) return self
[docs] def get_timeout(self): """ Returns the timeout to use for the operation, in milliseconds. A value of 0 indicates that the timeout has not been set. :returns: the timeout value. :rtype: int """ return super(GetIndexesRequest, self).get_timeout()
def should_retry(self): # Returns True if this request should be retried. return False def validate(self): if self.get_table_name() is None: raise IllegalArgumentException( 'GetIndexesRequest requires a table name.') @staticmethod def get_serial_version(serial_version): return serial_version @staticmethod def create_serializer(serial_version): if serial_version >= SerdeUtil.SERIAL_VERSION_4: return borneo.nson.GetIndexesRequestSerializer() return GetIndexesRequestSerializer() def get_request_name(self): # type: () -> str return "GetIndexes"
# noinspection PyUnusedLocal
[docs]class GetRequest(ReadRequest): """ Represents the input to a :py:meth:`NoSQLHandle.get` operation which returns a single row based on the specified key. The table name and key are required parameters. """ def __init__(self): super(GetRequest, self).__init__() self._key = None def __str__(self): return 'GetRequest'
[docs] def set_key(self, key): """ Sets the primary key used for the get operation. This is a required parameter. :param key: the primary key. :type key: dict :returns: self. :raises IllegalArgumentException: raises the exception if key is not a dictionary. """ CheckValue.check_dict(key, 'key') self._key = key return self
[docs] def set_key_from_json(self, json_key): """ Sets the key to use for the get operation based on a JSON string. :param json_key: the key as a JSON string. :type json_key: str :returns: self. :raises IllegalArgumentException: raises the exception if json_key is not a string. """ CheckValue.check_str(json_key, 'json_key') self._key = loads(json_key) return self
[docs] def get_key(self): """ Returns the primary key used for the operation. This is a required parameter. :returns: the key. :rtype: dict """ return self._key
def set_namespace(self, namespace): """ On-premises only Sets the namespace to use for the operation. This will override any configured default value. :param namespace: the namespace :type namespace: str :raises IllegalArgumentException: raises the exception if namespace is not a string. :versionadded: 5.4.0 """ super(GetRequest, self).set_namespace(namespace) return self
[docs] def set_table_name(self, table_name): """ Sets the table name to use for the operation. This is a required parameter. :param table_name: the table name. :type table_name: str :returns: self. :raises IllegalArgumentException: raises the exception if table_name is not a string. """ super(GetRequest, self).set_table_name(table_name) return self
[docs] def set_compartment(self, compartment): """ Cloud service only. Sets the name or id of a compartment to be used for this operation. The compartment may be specified as either a name (or path for nested compartments) or as an id (OCID). A name (vs id) can only be used when authenticated using a specific user identity. It is *not* available if authenticated as an Instance Principal which can be done when calling the service from a compute instance in the Oracle Cloud Infrastructure. See :py:meth:`borneo.iam.SignatureProvider.create_with_instance_principal`. :param compartment: the compartment name or id. If using a nested compartment, specify the full compartment path compartmentA.compartmentB, but exclude the name of the root compartment (tenant). :type compartment: str :returns: self. :raises IllegalArgumentException: raises the exception if compartment is not a str. """ self.set_compartment_internal(compartment) return self
[docs] def set_consistency(self, consistency): """ Sets the consistency to use for the operation. This parameter is optional and if not set the default consistency configured for the :py:class:`NoSQLHandle` is used. :param consistency: the consistency. :type consistency: Consistency :returns: self. :raises IllegalArgumentException: raises the exception if consistency is not Consistency.ABSOLUTE or Consistency.EVENTUAL. """ self._set_consistency(consistency) return self
def get_consistency(self): """ Returns the consistency set for this request, or None if not set. :returns: the consistency :rtype: Consistency """ return self._get_consistency()
[docs] def set_timeout(self, timeout_ms): """ Sets the request timeout value, in milliseconds. This overrides any default value set in :py:class:`NoSQLHandleConfig`. The value must be positive. :param timeout_ms: the timeout value, in milliseconds. :type timeout_ms: int :returns: self. :raises IllegalArgumentException: raises the exception if the timeout value is less than or equal to 0. """ self._set_timeout(timeout_ms) return self
[docs] def get_timeout(self): """ Returns the timeout to use for the operation, in milliseconds. A value of 0 indicates that the timeout has not been set. :returns: the timeout value. :rtype: int """ return super(GetRequest, self).get_timeout()
def validate(self): # Validates the state of the members of this class for use. self._validate_read_request('GetRequest') if self._key is None: raise IllegalArgumentException('GetRequest requires a key.') @staticmethod def get_serial_version(serial_version): return serial_version @staticmethod def create_serializer(serial_version): if serial_version >= SerdeUtil.SERIAL_VERSION_4: return borneo.nson.GetRequestSerializer() return GetRequestSerializer() def get_request_name(self): # type: () -> str return "Get"
# noinspection PyUnusedLocal
[docs]class GetTableRequest(Request): """ Represents the argument of a :py:meth:`NoSQLHandle.get_table` operation which returns static information associated with a table, as returned in :py:class:`TableResult`. This information only changes in response to a change in table schema or a change in provisioned throughput or capacity for the table. The table name is a required parameter. """ def __init__(self): super(GetTableRequest, self).__init__() self._operation_id = None def __str__(self): return 'GetTableRequest' def set_namespace(self, namespace): """ On-premises only Sets the namespace to use for the operation. This will override any configured default value. :param namespace: the namespace :type namespace: str :raises IllegalArgumentException: raises the exception if namespace is not a string. :versionadded: 5.4.0 """ super(GetTableRequest, self).set_namespace(namespace) return self
[docs] def set_table_name(self, table_name): """ Sets the table name to use for the request. :param table_name: the table name. This is a required parameter. :type table_name: str :returns: self. :raises IllegalArgumentException: raises the exception if table_name is not a string. """ super(GetTableRequest, self).set_table_name(table_name) return self
[docs] def set_compartment(self, compartment): """ Cloud service only. Sets the name or id of a compartment to be used for this operation. The compartment may be specified as either a name (or path for nested compartments) or as an id (OCID). A name (vs id) can only be used when authenticated using a specific user identity. It is *not* available if authenticated as an Instance Principal which can be done when calling the service from a compute instance in the Oracle Cloud Infrastructure. See :py:meth:`borneo.iam.SignatureProvider.create_with_instance_principal`. :param compartment: the compartment name or id. If using a nested compartment, specify the full compartment path compartmentA.compartmentB, but exclude the name of the root compartment (tenant). :type compartment: str :returns: self. :raises IllegalArgumentException: raises the exception if compartment is not a str. """ self.set_compartment_internal(compartment) return self
[docs] def set_operation_id(self, operation_id): """ Sets the operation id to use for the request. The operation id can be obtained via :py:meth:`TableResult.get_operation_id`. This parameter is optional. If non-none, it represents an asynchronous table operation that may be in progress. It is used to examine the result of the operation and if the operation has failed an exception will be thrown in response to a :py:meth:`NoSQLHandle.get_table` operation. If the operation is in progress or has completed successfully, the state of the table is returned. :param operation_id: the operation id. This is optional. :type operation_id: str :returns: self. :raises IllegalArgumentException: raises the exception if operation_id is a negative number. """ if operation_id is not None and not CheckValue.is_str(operation_id): raise IllegalArgumentException( 'operation_id must be a string type.') self._operation_id = operation_id return self
[docs] def get_operation_id(self): """ Returns the operation id to use for the request, None if not set. :returns: the operation id. :rtype: str """ return self._operation_id
[docs] def set_timeout(self, timeout_ms): """ Sets the request timeout value, in milliseconds. This overrides any default value set in :py:class:`NoSQLHandleConfig`. The value must be positive. :param timeout_ms: the timeout value, in milliseconds. :type timeout_ms: int :returns: self. :raises IllegalArgumentException: raises the exception if the timeout value is less than or equal to 0. """ self._set_timeout(timeout_ms) return self
[docs] def get_timeout(self): """ Returns the timeout to use for the operation, in milliseconds. A value of 0 indicates that the timeout has not been set. :returns: the timeout value. :rtype: int """ return super(GetTableRequest, self).get_timeout()
def should_retry(self): # Returns True if this request should be retried. return False def validate(self): if self.get_table_name() is None: raise IllegalArgumentException( 'GetTableRequest requires a table name.') @staticmethod def get_serial_version(serial_version): return serial_version @staticmethod def create_serializer(serial_version): if serial_version >= SerdeUtil.SERIAL_VERSION_4: return borneo.nson.GetTableRequestSerializer() return GetTableRequestSerializer() def get_request_name(self): # type: () -> str return "GetTable"
[docs]class ListTablesRequest(Request): """ Represents the argument of a :py:meth:`NoSQLHandle.list_tables` operation which lists all available tables associated with the identity associated with the handle used for the operation. If the list is large it can be paged by using the start_index and limit parameters. The list is returned in a simple array in :py:class:`ListTablesResult`. Names are returned sorted in alphabetical order in order to facilitate paging. """ def __init__(self): super(ListTablesRequest, self).__init__() self._start_index = 0 self._limit = 0 self._namespace = None def __str__(self): return 'ListTablesRequest'
[docs] def set_compartment(self, compartment): """ Cloud service only. Sets the name or id of a compartment to be used for this operation. The compartment may be specified as either a name (or path for nested compartments) or as an id (OCID). A name (vs id) can only be used when authenticated using a specific user identity. It is *not* available if authenticated as an Instance Principal which can be done when calling the service from a compute instance in the Oracle Cloud Infrastructure. See :py:meth:`borneo.iam.SignatureProvider.create_with_instance_principal`. :param compartment: the compartment name or id. If using a nested compartment, specify the full compartment path compartmentA.compartmentB, but exclude the name of the root compartment (tenant). :type compartment: str :returns: self. :raises IllegalArgumentException: raises the exception if compartment is not a str. """ self.set_compartment_internal(compartment) return self
[docs] def set_start_index(self, start_index): """ Sets the index to use to start returning table names. This is related to the :py:meth:`ListTablesResult.get_last_returned_index` from a previous request and can be used to page table names. If not set, the list starts at index 0. :param start_index: the start index. :type start_index: int :returns: self. :raises IllegalArgumentException: raises the exception if start_index is a negative number. """ CheckValue.check_int_ge_zero(start_index, 'start_index') self._start_index = start_index return self
[docs] def get_start_index(self): """ Returns the index to use to start returning table names. This is related to the :py:meth:`ListTablesResult.get_last_returned_index` from a previous request and can be used to page table names. If not set, the list starts at index 0. :returns: the start index. :rtype: int """ return self._start_index
[docs] def set_limit(self, limit): """ Sets the maximum number of table names to return in the operation. If not set (0) there is no limit. :param limit: the maximum number of tables. :type limit: int :returns: self. :raises IllegalArgumentException: raises the exception if limit is a negative number. """ CheckValue.check_int_ge_zero(limit, 'limit') self._limit = limit return self
[docs] def get_limit(self): """ Returns the maximum number of table names to return in the operation. If not set (0) there is no application-imposed limit. :returns: the maximum number of tables to return in a single request. :rtype: int """ return self._limit
[docs] def set_namespace(self, namespace): """ On-premise only. Sets the namespace to use for the list. If not set, all tables accessible to the user will be returned. If set, only tables in the namespace provided are returned. :param namespace: the namespace to use. :type namespace: str :returns: self. :raises IllegalArgumentException: raises the exception if namespace is not a string. """ CheckValue.check_str(namespace, 'namespace') self._namespace = namespace return self
[docs] def get_namespace(self): """ On-premise only. Returns the namespace to use for the list or None if not set. :returns: the namespace. :rtype: str """ return self._namespace
[docs] def set_timeout(self, timeout_ms): """ Sets the request timeout value, in milliseconds. This overrides any default value set in :py:class:`NoSQLHandleConfig`. The value must be positive. :param timeout_ms: the timeout value, in milliseconds. :type timeout_ms: int :returns: self. :raises IllegalArgumentException: raises the exception if the timeout value is less than or equal to 0. """ self._set_timeout(timeout_ms) return self
[docs] def get_timeout(self): """ Returns the timeout to use for the operation, in milliseconds. A value of 0 indicates that the timeout has not been set. :returns: the timeout value. :rtype: int """ return super(ListTablesRequest, self).get_timeout()
def should_retry(self): # Returns True if this request should be retried. return False def validate(self): if self._start_index < 0 or self._limit < 0: raise IllegalArgumentException( 'ListTables: start index and number of tables must be ' + 'non-negative.') @staticmethod def get_serial_version(serial_version): return serial_version @staticmethod def create_serializer(serial_version): if serial_version >= SerdeUtil.SERIAL_VERSION_4: return borneo.nson.ListTablesRequestSerializer() return ListTablesRequestSerializer() def get_request_name(self): # type: () -> str return "ListTables"
[docs]class MultiDeleteRequest(Request): """ Represents the input to a :py:meth:`NoSQLHandle.multi_delete` operation which can be used to delete a range of values that match the primary key and range provided. A range is specified using a partial key plus a range based on the portion of the key that is not provided. For example if a table's primary key is <id, timestamp>; and the its shard key is the id, it is possible to delete a range of timestamp values for a specific id by providing an id but no timestamp in the value used for :py:meth:`set_key` and providing a range of timestamp values in the :py:class:`FieldRange` used in :py:meth:`set_range`. Because this operation can exceed the maximum amount of data modified in a single operation a continuation key can be used to continue the operation. The continuation key is obtained from :py:meth:`MultiDeleteResult.get_continuation_key` and set in a new request using :py:meth:`set_continuation_key`. Operations with a continuation key still require the primary key. The table name and key are required parameters. """ def __init__(self): super(MultiDeleteRequest, self).__init__() self._key = None self._continuation_key = None self._range = None self._max_write_kb = 0 self._durability = None def __str__(self): return 'MultiDeleteRequest' def set_namespace(self, namespace): """ On-premises only Sets the namespace to use for the operation. This will override any configured default value. :param namespace: the namespace :type namespace: str :raises IllegalArgumentException: raises the exception if namespace is not a string. :versionadded: 5.4.0 """ super(MultiDeleteRequest, self).set_namespace(namespace) return self
[docs] def set_table_name(self, table_name): """ Sets the table name to use for the operation. This is a required parameter. :param table_name: the table name. :type table_name: str :returns: self. :raises IllegalArgumentException: raises the exception if table_name is not a string. """ super(MultiDeleteRequest, self).set_table_name(table_name) return self
[docs] def set_key(self, key): """ Sets the key to be used for the operation. This is a required parameter and must completely specify the target table's shard key. :param key: the key. :type key: dict :returns: self. :raises IllegalArgumentException: raises the exception if key is not a dictionary. """ CheckValue.check_dict(key, 'key') self._key = key return self
[docs] def get_key(self): """ Returns the key to be used for the operation. :returns: the key. :rtype: dict """ return self._key
[docs] def set_compartment(self, compartment): """ Cloud service only. Sets the name or id of a compartment to be used for this operation. The compartment may be specified as either a name (or path for nested compartments) or as an id (OCID). A name (vs id) can only be used when authenticated using a specific user identity. It is *not* available if authenticated as an Instance Principal which can be done when calling the service from a compute instance in the Oracle Cloud Infrastructure. See :py:meth:`borneo.iam.SignatureProvider.create_with_instance_principal`. :param compartment: the compartment name or id. If using a nested compartment, specify the full compartment path compartmentA.compartmentB, but exclude the name of the root compartment (tenant). :type compartment: str :returns: self. :raises IllegalArgumentException: raises the exception if compartment is not a str. """ self.set_compartment_internal(compartment) return self
[docs] def set_continuation_key(self, continuation_key): """ Sets the continuation key. :param continuation_key: the key which should have been obtained from :py:meth:`MultiDeleteResult.get_continuation_key`. :type continuation_key: bytearray :returns: self. :raises IllegalArgumentException: raises the exception if continuation_key is not a bytearray. """ if (continuation_key is not None and not isinstance(continuation_key, bytearray)): raise IllegalArgumentException( 'set_continuation_key requires bytearray as parameter.') self._continuation_key = continuation_key return self
[docs] def get_continuation_key(self): """ Returns the continuation key if set. :returns: the continuation key. :rtype: bytearray """ return self._continuation_key
[docs] def set_max_write_kb(self, max_write_kb): """ Sets the limit on the total KB write during this operation, 0 means no application-defined limit. This value can only reduce the system defined limit. :param max_write_kb: the limit in terms of number of KB write during this operation. :type max_write_kb: int :returns: self. :raises IllegalArgumentException: raises the exception if the max_write_kb value is less than 0. """ CheckValue.check_int_ge_zero(max_write_kb, 'max_write_kb') self._max_write_kb = max_write_kb return self
[docs] def get_max_write_kb(self): """ Returns the limit on the total KB write during this operation. If not set by the application this value will be 0 which means the default system limit is used. :returns: the limit, or 0 if not set. :rtype: int """ return self._max_write_kb
[docs] def set_range(self, field_range): """ Sets the :py:class:`FieldRange` to be used for the operation. This parameter is optional, but required to delete a specific range of rows. :param field_range: the field range. :type field_range: FieldRange :returns: self. :raises IllegalArgumentException: raises the exception if field_range is not an instance of FieldRange. """ if field_range is not None and not isinstance(field_range, FieldRange): raise IllegalArgumentException( 'set_range requires an instance of FieldRange or None as ' + 'parameter.') self._range = field_range return self
[docs] def get_range(self): """ Returns the :py:class:`FieldRange` to be used for the operation if set. :returns: the range, None if no range is to be used. :rtype: FieldRange """ return self._range
[docs] def set_timeout(self, timeout_ms): """ Sets the request timeout value, in milliseconds. This overrides any default value set in :py:class:`NoSQLHandleConfig`. The value must be positive. :param timeout_ms: the timeout value, in milliseconds. :type timeout_ms: int :returns: self. :raises IllegalArgumentException: raises the exception if the timeout value is less than or equal to 0. """ self._set_timeout(timeout_ms) return self
[docs] def get_timeout(self): """ Returns the timeout to use for the operation, in milliseconds. A value of 0 indicates that the timeout has not been set. :returns: the timeout value. :rtype: int """ return super(MultiDeleteRequest, self).get_timeout()
[docs] def set_durability(self, durability): """ On-premise only. Sets the durability to use for the operation. :param durability: the Durability to use :type durability: Durability :returns: self. :raises IllegalArgumentException: raises the exception if Durability is not valid :versionadded: 5.3.0 """ if durability is None: self._durability = None return if not isinstance(durability, Durability): raise IllegalArgumentException('set_durability requires an ' + 'instance of Durability as parameter.') durability.validate() self._durability = durability return self
[docs] def get_durability(self): """ On-premise only. Gets the durability to use for the operation or None if not set :returns: the Durability :versionadded: 5.3.0 """ return self._durability
def does_reads(self): return True def does_writes(self): return True def validate(self): if self.get_table_name() is None: raise IllegalArgumentException( 'MultiDeleteRequest requires table name.') if self._key is None: raise IllegalArgumentException( 'MultiDeleteRequest requires a key.') if self._range is not None: self._range.validate() @staticmethod def get_serial_version(serial_version): return serial_version @staticmethod def create_serializer(serial_version): if serial_version >= SerdeUtil.SERIAL_VERSION_4: return borneo.nson.MultiDeleteRequestSerializer() return MultiDeleteRequestSerializer() def get_request_name(self): # type: () -> str return "MultiDelete"
[docs]class PrepareRequest(Request): """ A request that encapsulates a query prepare call. Query preparation allows queries to be compiled (prepared) and reused, saving time and resources. Use of prepared queries vs direct execution of query strings is highly recommended. Prepared queries are implemented as :py:class:`PreparedStatement` which supports bind variables in queries which can be used to more easily reuse a query by parameterization. The statement is required parameter. """ def __init__(self): super(PrepareRequest, self).__init__() self._statement = None self._get_query_plan = False self._get_query_schema = False def __str__(self): return 'PrepareRequest' def set_namespace(self, namespace): """ On-premises only Sets the namespace to use for the operation. This will override any configured default value. :param namespace: the namespace :type namespace: str :raises IllegalArgumentException: raises the exception if namespace is not a string. :versionadded: 5.4.0 """ super(PrepareRequest, self).set_namespace(namespace) return self def set_table_name(self, table_name): """ Sets the table name for a query operation. This is used by rate limiting logic to manage internal rate limiters. :param table_name: the name (or OCID) of the table. :type table_name: str :returns: self. :raises IllegalArgumentException: raises the exception if table_name is not a string. """ super(PrepareRequest, self).set_table_name(table_name) return self
[docs] def set_statement(self, statement): """ Sets the query statement. :param statement: the query statement. :type statement: str :returns: self. :raises IllegalArgumentException: raises the exception if statement is not a string. """ CheckValue.check_str(statement, 'statement') self._statement = statement return self
[docs] def get_statement(self): """ Returns the query statement. :returns: the statement, or None if it has not been set. :rtype: str """ return self._statement
[docs] def set_compartment(self, compartment): """ Cloud service only. Sets the name or id of a compartment to be used for this operation. The compartment may be specified as either a name (or path for nested compartments) or as an id (OCID). A name (vs id) can only be used when authenticated using a specific user identity. It is *not* available if authenticated as an Instance Principal which can be done when calling the service from a compute instance in the Oracle Cloud Infrastructure. See :py:meth:`borneo.iam.SignatureProvider.create_with_instance_principal`. :param compartment: the compartment name or id. If using a nested compartment, specify the full compartment path compartmentA.compartmentB, but exclude the name of the root compartment (tenant). :type compartment: str :returns: self. :raises IllegalArgumentException: raises the exception if compartment is not a str. """ self.set_compartment_internal(compartment) return self
[docs] def set_get_query_plan(self, get_query_plan): """ Sets whether a JSON representation of the query execution plan should be included in the :py:class:`PreparedStatement`. :param get_query_plan: True if a the query execution plan should be included in the :py:class:`PreparedStatement`. False otherwise. :type get_query_plan: bool :returns: self. :raises IllegalArgumentException: raises the exception if get_query_plan is not a boolean. """ CheckValue.check_boolean(get_query_plan, 'get_query_plan') self._get_query_plan = get_query_plan return self
[docs] def get_query_plan(self): """ Returns whether a JSON representation of the query execution plan should be included in the :py:class:`PreparedStatement`. :returns: whether the the query execution plan should be included in the :py:class:`PreparedStatement`. :rtype: bool """ return self._get_query_plan
def set_get_query_schema(self, get_query_schema): """ Sets whether a JSON representation of the schema of the query should be included in the :py:class:`PreparedStatement`. :param: get_query_schema: True if a JSON representation of the schema of the query should be included in the :py:class:`PreparedStatement`. :type get_query_schema: bool :returns: self. :raises IllegalArgumentException: raises the exception if get_query_schema is not a boolean. :versionadded: 5.4.0 """ CheckValue.check_boolean(get_query_schema, 'get_query_schema') self._get_query_schema = get_query_schema return self def get_query_schema(self): """ Returns whether a JSON representation of the schema of the query should be included in the :py:class:`PreparedStatement`. :returns: True if a JSON representation of the schema of the query should be included in the :py:class:`PreparedStatement`. :rtype: bool :versionadded: 5.4.0 """ return self._get_query_schema
[docs] def set_timeout(self, timeout_ms): """ Sets the request timeout value, in milliseconds. This overrides any default value set in :py:class:`NoSQLHandleConfig`. The value must be positive. :param timeout_ms: the timeout value, in milliseconds. :type timeout_ms: int :returns: self. :raises IllegalArgumentException: raises the exception if the timeout value is less than or equal to 0. """ self._set_timeout(timeout_ms) return self
[docs] def get_timeout(self): """ Returns the timeout to use for the operation, in milliseconds. A value of 0 indicates that the timeout has not been set. :returns: the value. :rtype: int """ return super(PrepareRequest, self).get_timeout()
def validate(self): if self._statement is None: raise IllegalArgumentException( 'PrepareRequest requires a statement.') @staticmethod def get_serial_version(serial_version): return serial_version @staticmethod def create_serializer(serial_version): if serial_version >= SerdeUtil.SERIAL_VERSION_4: return borneo.nson.PrepareRequestSerializer() return PrepareRequestSerializer() def get_request_name(self): # type: () -> str return "Prepare"
[docs]class PutRequest(WriteRequest): """ Represents the input to a :py:meth:`NoSQLHandle.put` operation. This request can be used to perform unconditional and conditional puts: Overwrite any existing row. This is the default.\n Succeed only if the row does not exist. Use PutOption.IF_ABSENT for this case.\n Succeed only if the row exists. Use PutOption.IF_PRESENT for this case. \n Succeed only if the row exists and its :py:class:`Version` matches a specific :py:class:`Version`. Use PutOption.IF_VERSION for this case and :py:meth:`set_match_version` to specify the version to match. Information about the existing row can be returned on failure of a put operation using PutOption.IF_VERSION or PutOption.IF_ABSENT by using :py:meth:`set_return_row`. Requesting this information incurs additional cost and may affect operation latency. On a successful operation the :py:class:`Version` returned by :py:meth:`PutResult.get_version` is non-none. Additional information, such as previous row information, may be available in :py:class:`PutResult`. The table name and value are required parameters. """ def __init__(self): super(PutRequest, self).__init__() self._value = None self._option = None self._match_version = None self._ttl = None self._update_ttl = False self._exact_match = False self._identity_cache_size = 0 def __str__(self): return 'PutRequest'
[docs] def set_value(self, value): """ Sets the value to use for the put operation. This is a required parameter and must be set using this method or :py:meth:`set_value_from_json` :param value: the row value. :type value: dict :returns: self. :raises IllegalArgumentException: raises the exception if value is not a dictionary. """ CheckValue.check_dict(value, 'value') self._value = value return self
[docs] def set_value_from_json(self, json_value): """ Sets the value to use for the put operation based on a JSON string. The string is parsed for validity and stored internally as a dict. This is a required parameter and must be set using this method or :py:meth:`set_value` :param json_value: the row value as a JSON string. :type json_value: str :returns: self. :raises IllegalArgumentException: raises the exception if json_value is not a string. """ CheckValue.check_str(json_value, 'json_value') self._value = loads(json_value) return self
[docs] def get_value(self): """ Returns the value of the row to be used. :returns: the value, or None if not set. :rtype: dict """ return self._value
[docs] def set_compartment(self, compartment): """ Cloud service only. Sets the name or id of a compartment to be used for this operation. The compartment may be specified as either a name (or path for nested compartments) or as an id (OCID). A name (vs id) can only be used when authenticated using a specific user identity. It is *not* available if authenticated as an Instance Principal which can be done when calling the service from a compute instance in the Oracle Cloud Infrastructure. See :py:meth:`borneo.iam.SignatureProvider.create_with_instance_principal`. :param compartment: the compartment name or id. If using a nested compartment, specify the full compartment path compartmentA.compartmentB, but exclude the name of the root compartment (tenant). :type compartment: str :returns: self. :raises IllegalArgumentException: raises the exception if compartment is not a str. """ self.set_compartment_internal(compartment) return self
[docs] def set_option(self, option): """ Sets the option for the put. :param option: the option to set. :type option: PutOption :returns: self. """ self._option = option return self
[docs] def get_option(self): """ Returns the option specified for the put. :returns: the option specified. :rtype: PutOption """ return self._option
[docs] def set_match_version(self, version): """ Sets the :py:class:`Version` to use for a conditional put operation. The Version is usually obtained from :py:meth:`GetResult.get_version` or other method that returns a Version. When set, the put operation will succeed only if the row exists and its Version matches the one specified. This condition exists to allow an application to ensure that it is updating a row in an atomic read-modify-write cycle. Using this mechanism incurs additional cost. :param version: the Version to match. :type version: Version :returns: self. :raises IllegalArgumentException: raises the exception if version is not an instance of Version. """ if not isinstance(version, Version): raise IllegalArgumentException('set_match_version requires an ' + 'instance of Version as parameter.') if self._option is None: self._option = PutOption.IF_VERSION self._match_version = version return self
[docs] def get_match_version(self): """ Returns the :py:class:`Version` used for a match on a conditional put. :returns: the Version or None if not set. :rtype: Version """ return self._match_version
[docs] def set_ttl(self, ttl): """ Sets the :py:class:`TimeToLive` value, causing the time to live on the row to be set to the specified value on put. This value overrides any default time to live setting on the table. :param ttl: the time to live. :type ttl: TimeToLive :returns: self. :raises IllegalArgumentException: raises the exception if ttl is not an instance of TimeToLive. """ if ttl is not None and not isinstance(ttl, TimeToLive): raise IllegalArgumentException('set_ttl requires an instance of ' + 'TimeToLive or None as parameter.') self._ttl = ttl return self
[docs] def get_ttl(self): """ Returns the :py:class:`TimeToLive` value, if set. :returns: the :py:class:`TimeToLive` if set, None otherwise. :rtype: TimeToLive """ return self._ttl
[docs] def set_use_table_default_ttl(self, update_ttl): """ If value is True, and there is an existing row, causes the operation to update the time to live (TTL) value of the row based on the Table's default TTL if set. If the table has no default TTL this state has no effect. By default updating an existing row has no effect on its TTL. :param update_ttl: True or False. :type update_ttl: bool :returns: self. :raises IllegalArgumentException: raises the exception if update_ttl is not True or False. """ CheckValue.check_boolean(update_ttl, 'update_ttl') self._update_ttl = update_ttl return self
[docs] def get_use_table_default_ttl(self): """ Returns whether or not to update the row's time to live (TTL) based on a table default value if the row exists. By default updates of existing rows do not affect that row's TTL. :returns: whether or not to update the row's TTL based on a table default value if the row exists. :rtype: bool """ return self._update_ttl
[docs] def get_update_ttl(self): """ Returns True if the operation should update the ttl. :returns: True if the operation should update the ttl. :rtype: bool """ return self._update_ttl or self._ttl is not None
def set_exact_match(self, exact_match): """ If True the value must be an exact match for the table schema or the operation will fail. An exact match means that there are no required fields missing and that there are no extra, unknown fields. The default behavior is to not require an exact match. :param exact_match: True or False. :type exact_match: bool :returns: self. :raises IllegalArgumentException: raises the exception if exact_match is not True or False. """ CheckValue.check_boolean(exact_match, 'exact_match') self._exact_match = exact_match return self def get_exact_match(self): """ Returns whether the value must be an exact match to the table schema or not. :returns: the value. :rtype: bool """ return self._exact_match def set_identity_cache_size(self, identity_cache_size): """ Sets the number of generated identity values that are requested from the server during a put. This takes precedence over the DDL identity CACHE option set during creation of the identity column. Any value equal or less than 0 means that the DDL identity CACHE value is used. :param identity_cache_size: the size. :type identity_cache_size: int :returns: self. :raises IllegalArgumentException: raises the exception if identity_cache_size is not an integer. """ CheckValue.check_int(identity_cache_size, 'identity_cache_size') self._identity_cache_size = identity_cache_size return self def get_identity_cache_size(self): """ Gets the number of generated identity values that are requested from the server during a put if set in this request. :returns: the identity cache size. :rtype: int """ return self._identity_cache_size
[docs] def set_timeout(self, timeout_ms): """ Sets the request timeout value, in milliseconds. This overrides any default value set in :py:class:`NoSQLHandleConfig`. The value must be positive. :param timeout_ms: the timeout value, in milliseconds. :type timeout_ms: int :returns: self. :raises IllegalArgumentException: raises the exception if the timeout value is less than or equal to 0. """ self._set_timeout(timeout_ms) return self
[docs] def get_timeout(self): """ Returns the timeout to use for the operation, in milliseconds. A value of 0 indicates that the timeout has not been set. :returns: the timeout value. :rtype: int """ return super(PutRequest, self).get_timeout()
def set_namespace(self, namespace): """ On-premises only Sets the namespace to use for the operation. This will override any configured default value. :param namespace: the namespace :type namespace: str :raises IllegalArgumentException: raises the exception if namespace is not a string. :versionadded: 5.4.0 """ super(PutRequest, self).set_namespace(namespace) return self
[docs] def set_table_name(self, table_name): """ Sets the table name to use for the operation. :param table_name: the table name. :type table_name: str :returns: self. :raises IllegalArgumentException: raises the exception if table_name is not a string. """ super(PutRequest, self).set_table_name(table_name) return self
[docs] def set_return_row(self, return_row): """ Sets whether information about the exist row should be returned on failure because of a version mismatch or failure of an "if absent" operation. :param return_row: set to True if information should be returned. :type return_row: bool :returns: self. :raises IllegalArgumentException: raises the exception if return_row is not True or False. """ self._set_return_row(return_row) return self
[docs] def get_return_row(self): """ Returns whether information about the exist row should be returned on failure because of a version mismatch or failure of an "if absent" operation. If no option is set via :py:meth:`set_option` or the option is PutOption.IF_PRESENT the value of this parameter is ignored and there will not be any return information. :returns: True if information should be returned. :rtype: bool """ return self._get_return_row()
[docs] def set_durability(self, durability): """ On-premise only. Sets the durability to use for the operation. :param durability: the Durability to use :type durability: Durability :returns: self. :raises IllegalArgumentException: raises the exception if Durability is not valid :versionadded: 5.3.0 """ self._set_durability(durability) return self
[docs] def get_durability(self): """ On-premise only. Gets the durability to use for the operation or None if not set :returns: the Durability :versionadded: 5.3.0 """ return self._get_durability()
def does_reads(self): return self._option is not None or self.get_return_row() def validate(self): # Validates the state of the object when complete. self._validate_write_request('PutRequest') if self._value is None: raise IllegalArgumentException('PutRequest requires a value') self._validate_if_options() def _validate_if_options(self): # Ensures that only one of ifAbsent, ifPresent, or match_version is # set. if (self._option == PutOption.IF_VERSION and self._match_version is None): raise IllegalArgumentException( 'PutRequest: match_version must be specified when ' + 'PutOption.IF_VERSION is used.') if (self._option != PutOption.IF_VERSION and self._match_version is not None): raise IllegalArgumentException( 'PutRequest: match_version is specified, the option is not ' + 'PutOption.IF_VERSION.') if self._update_ttl and self._ttl is not None: raise IllegalArgumentException( 'PutRequest: only one of set_use_table_default_ttl or set_ttl' + ' may be specified') @staticmethod def get_serial_version(serial_version): return serial_version @staticmethod def create_serializer(serial_version): if serial_version >= SerdeUtil.SERIAL_VERSION_4: return borneo.nson.PutRequestSerializer() return PutRequestSerializer() def get_request_name(self): # type: () -> str return "Put"
[docs]class QueryRequest(Request): """ A request that represents a query. A query may be specified as either a textual SQL statement (a String) or a prepared query (an instance of :py:class:`PreparedStatement`), which may include bind variables. For performance reasons prepared queries are preferred for queries that may be reused. This is because prepared queries bypass query compilation. They also allow for parameterized queries using bind variables. To compute and retrieve the full result set of a query, the same QueryRequest instance will, in general, have to be executed multiple times (via :py:meth:`NoSQLHandle.query`). Each execution returns a :py:class:`QueryResult`, which contains a subset of the result set. The following code snippet illustrates a typical query execution: .. code-block:: pycon handle = ... request = QueryRequest().set_statement('SELECT * FROM foo') while True: result = handle.query(request) results = result.get_results() # do something with the results if request.is_done(): break Notice that a batch of results returned by a QueryRequest execution may be empty. This is because during each execution the query is allowed to read or write a maximum number of bytes. If this maximum is reached, execution stops. This can happen before any result was generated (for example, if none of the rows read satisfied the query conditions). If an application wishes to terminate query execution before retrieving all of the query results, it should call :py:meth:`close` in order to release any local resources held by the query. This also allows the application to reuse the QueryRequest instance to run the same query from the beginning or a different query. QueryRequest instances are not thread-safe. That is, if two or more application threads need to run the same query concurrently, they must create and use their own QueryRequest instances. The statement or prepared_statement is required parameter. """ def __init__(self): super(QueryRequest, self).__init__() self._trace_level = 0 self._limit = 0 self._max_read_kb = 0 self._max_write_kb = 0 self._max_memory_consumption = 1024 * 1024 * 1024 self._math_context = Context(prec=7, rounding=ROUND_HALF_EVEN) self._consistency = None self._durability = None self._statement = None self._prepared_statement = None self._continuation_key = None # If shardId is >= 0, the QueryRequest should be executed only at the # shard with this id. This is the case only for advanced queries that do # sorting. self._shard_id = -1 # The QueryDriver, for advanced queries only. self.driver = None # An "internal" request is one created and submitted for execution by # the ReceiveIter. self.is_internal = False def __str__(self): return 'QueryRequest' def copy_internal(self): # Creates an internal QueryRequest out of the application-provided # request. internal_req = QueryRequest() internal_req.set_compartment(self.get_compartment()) internal_req.set_table_name(self.get_table_name()) internal_req.set_timeout(self.get_timeout()) internal_req.set_trace_level(self._trace_level) internal_req.set_limit(self._limit) internal_req.set_max_read_kb(self._max_read_kb) internal_req.set_max_write_kb(self._max_write_kb) internal_req.set_max_memory_consumption(self._max_memory_consumption) internal_req.set_math_context(self._math_context) internal_req.set_consistency(self._consistency) internal_req.set_durability(self._durability) internal_req.set_prepared_statement(self._prepared_statement) internal_req.driver = self.driver internal_req.is_internal = True return internal_req def copy(self): """ Copies the query request to start query results from the beginning. :versionadded: 5.3.6 """ copy = QueryRequest() copy._compartment = self.get_compartment() copy._prepared_statement = self.get_table_name() timeout = self.get_timeout() if timeout > 0: copy.set_timeout(timeout) copy.set_trace_level(self._trace_level) copy.set_limit(self._limit) copy.set_max_read_kb(self._max_read_kb) copy.set_max_write_kb(self._max_write_kb) copy.set_max_memory_consumption(self._max_memory_consumption) copy.set_math_context(self._math_context) if self._consistency is not None: copy.set_consistency(self._consistency) if self._durability is not None: copy.set_durability(self._durability) if self._prepared_statement is not None: copy.set_prepared_statement(self._prepared_statement) copy._statement = self._statement # leave continuationKey null to start from the beginning # copy._continuation_key = self._continuation_key self.is_internal = False self._shard_id = -1 self.driver = None return copy
[docs] def close(self): """ Terminates the query execution and releases any memory consumed by the query at the driver. An application should use this method if it wishes to terminate query execution before retrieving all of the query results. """ self.set_cont_key(None)
[docs] def is_done(self): """ Returns True if the query execution is finished, i.e., there are no more query results to be generated. Otherwise False. :returns: Whether the query execution is finished or not. :rtype: bool """ return self._continuation_key is None
def get_table_name(self): if self._prepared_statement is None: return None return self._prepared_statement.get_table_name()
[docs] def set_compartment(self, compartment): """ Cloud service only. Sets the name or id of a compartment to be used for this operation. The compartment may be specified as either a name (or path for nested compartments) or as an id (OCID). A name (vs id) can only be used when authenticated using a specific user identity. It is *not* available if authenticated as an Instance Principal which can be done when calling the service from a compute instance in the Oracle Cloud Infrastructure. See :py:meth:`borneo.iam.SignatureProvider.create_with_instance_principal`. :param compartment: the compartment name or id. If using a nested compartment, specify the full compartment path compartmentA.compartmentB, but exclude the name of the root compartment (tenant). :type compartment: str :returns: self. :raises IllegalArgumentException: raises the exception if compartment is not a str. """ self.set_compartment_internal(compartment) return self
def set_trace_level(self, trace_level): CheckValue.check_int_ge_zero(trace_level, 'trace_level') if trace_level > 32: raise IllegalArgumentException('trace level must be <= 32') self._trace_level = trace_level return self def get_trace_level(self): return self._trace_level
[docs] def set_limit(self, limit): """ Sets the limit on number of items returned by the operation. This allows an operation to return less than the default amount of data. :param limit: the limit in terms of number of items returned. :type limit: int :returns: self. :raises IllegalArgumentException: raises the exception if the limit is a negative number. """ CheckValue.check_int_ge_zero(limit, 'limit') self._limit = limit return self
[docs] def get_limit(self): """ Returns the limit on number of items returned by the operation. If not set by the application this value will be 0 which means no limit. :returns: the limit, or 0 if not set. :rtype: int """ return self._limit
[docs] def set_max_read_kb(self, max_read_kb): """ Sets the limit on the total data read during this operation, in KB. This value can only reduce the system defined limit. This limit is independent of read units consumed by the operation. It is recommended that for tables with relatively low provisioned read throughput that this limit be reduced to less than or equal to one half of the provisioned throughput in order to avoid or reduce throttling exceptions. :param max_read_kb: the limit in terms of number of KB read during this operation. :type max_read_kb: int :returns: self. :raises IllegalArgumentException: raises the exception if the max_read_kb value is less than 0. """ CheckValue.check_int_ge_zero(max_read_kb, 'max_read_kb') self._max_read_kb = max_read_kb return self
[docs] def get_max_read_kb(self): """ Returns the limit on the total data read during this operation, in KB. If not set by the application this value will be 0 which means no application-defined limit. :returns: the limit, or 0 if not set. :rtype: int """ return self._max_read_kb
[docs] def set_max_write_kb(self, max_write_kb): """ Sets the limit on the total data written during this operation, in KB. This limit is independent of write units consumed by the operation. :param max_write_kb: the limit in terms of number of KB written during this operation. :type max_write_kb: int :returns: self. :raises IllegalArgumentException: raises the exception if the max_write_kb value is less than 0. """ CheckValue.check_int_ge_zero(max_write_kb, 'max_write_kb') self._max_write_kb = max_write_kb return self
[docs] def get_max_write_kb(self): """ Returns the limit on the total data written during this operation, in KB. If not set by the application this value will be 0 which means no application-defined limit. :returns: the limit, or 0 if not set. :rtype: int """ return self._max_write_kb
[docs] def set_max_memory_consumption(self, memory_consumption): """ Sets the maximum number of memory bytes that may be consumed by the statement at the driver for operations such as duplicate elimination (which may be required due to the use of an index on a list or map) and sorting. Such operations may consume a lot of memory as they need to cache the full result set or a large subset of it at the client memory. The default value is 1GB. :param memory_consumption: the maximum number of memory bytes that may be consumed by the statement at the driver for blocking operations. :type memory_consumption: long :returns: self. :raises IllegalArgumentException: raises the exception if memory_consumption is a negative number or 0. """ CheckValue.check_int_ge_zero(memory_consumption, 'memory_consumption') self._max_memory_consumption = memory_consumption return self
[docs] def get_max_memory_consumption(self): """ Returns the maximum number of memory bytes that may be consumed by the statement at the driver for operations such as duplicate elimination (which may be required due to the use of an index on a list or map) and sorting (sorting by distance when a query contains a geo_near() function). Such operations may consume a lot of memory as they need to cache the full result set at the client memory. The default value is 100MB. :returns: the maximum number of memory bytes. :rtype: long """ return self._max_memory_consumption
[docs] def set_math_context(self, math_context): """ Sets the Context used for Decimal operations. :param math_context: the Context used for Decimal operations. :type math_context: Context :returns: self. :raises IllegalArgumentException: raises the exception if math_context is not an instance of Context. """ if not isinstance(math_context, Context): raise IllegalArgumentException( 'set_math_context requires an instance of decimal.Context as ' + 'parameter.') self._math_context = math_context return self
[docs] def get_math_context(self): """ Returns the Context used for Decimal operations. :returns: the Context used for Decimal operations. :rtype: Context """ return self._math_context
[docs] def set_consistency(self, consistency): """ Sets the consistency to use for the operation. :param consistency: the consistency. :type consistency: Consistency :returns: self. :raises IllegalArgumentException: raises the exception if consistency is not Consistency.ABSOLUTE or Consistency.EVENTUAL. """ if (consistency != Consistency.ABSOLUTE and consistency != Consistency.EVENTUAL): raise IllegalArgumentException( 'set_consistency requires Consistency.ABSOLUTE or ' + 'Consistency.EVENTUAL as parameter.') self._consistency = consistency return self
[docs] def get_consistency(self): """ Returns the consistency set for this request, or None if not set. :returns: the consistency :rtype: Consistency """ return self._consistency
def set_durability(self, durability): """ On-premise only. Sets the durability to use for the operation. Only used for queries that do writes or deletes. :param durability: the Durability to use :type durability: Durability :returns: self. :raises IllegalArgumentException: raises the exception if Durability is not valid :versionadded: 5.4.0 """ self._durability = durability return self def get_durability(self): """ On-premise only. Gets the durability to use for the operation or None if not set :returns: the Durability :versionadded: 5.4.0 """ return self._durability @deprecated def set_continuation_key(self, continuation_key): """ Sets the continuation key. This is used to continue an operation that returned this key in its :py:class:`QueryResult`. :param continuation_key: the key which should have been obtained from :py:meth:`QueryResult.get_continuation_key`. :type continuation_key: bytearray or None :returns: self. :raises IllegalArgumentException: raises the exception if continuation_key is not a bytearray. :deprecated: There is no reason to use this method anymore, because setting the continuation key is now done internally. """ if (continuation_key is not None and not isinstance(continuation_key, bytearray)): raise IllegalArgumentException( 'set_continuation_key requires bytearray as parameter.') return self.set_cont_key(continuation_key) @deprecated def get_continuation_key(self): """ Returns the continuation key if set. :returns: the key. :rtype: bytearray :deprecated: There is no reason to use this method anymore, because getting the continuation key is now done internally. """ return self._continuation_key def set_cont_key(self, continuation_key): self._continuation_key = continuation_key if (self.driver is not None and not self.is_internal and self._continuation_key is None): self.driver.close() self.driver = None return self def get_cont_key(self): return self._continuation_key
[docs] def set_statement(self, statement): """ Sets the query statement. :param statement: the query statement. :type statement: str :returns: self. :raises IllegalArgumentException: raises the exception if statement is not a string. """ CheckValue.check_str(statement, 'statement') if (self._prepared_statement is not None and statement != self._prepared_statement.get_sql_text()): raise IllegalArgumentException( 'The query text is not equal to the prepared one.') self._statement = statement return self
[docs] def get_statement(self): """ Returns the query statement. :returns: the statement, or None if it has not been set. :rtype: str """ return self._statement
[docs] def set_prepared_statement(self, value): """ Sets the prepared query statement. :param value: the prepared query statement or the result of a prepare request. :type value: PreparedStatement :returns: self. :raises IllegalArgumentException: raises the exception if value is not an instance of PrepareResult or PreparedStatement. """ if not (isinstance(value, PrepareResult) or isinstance(value, PreparedStatement)): raise IllegalArgumentException( 'set_prepared_statement requires an instance of PrepareResult' + ' or PreparedStatement as parameter.') if (isinstance(value, PreparedStatement) and self._statement is not None and self._statement != value.get_sql_text()): raise IllegalArgumentException( 'The query text is not equal to the prepared one.') self._prepared_statement = (value.get_prepared_statement() if isinstance(value, PrepareResult) else value) return self
[docs] def get_prepared_statement(self): """ Returns the prepared query statement. :returns: the statement, or None if it has not been set. :rtype: PreparedStatement """ return self._prepared_statement
def set_shard_id(self, shard_id): self._shard_id = shard_id def get_shard_id(self): return self._shard_id def set_driver(self, driver): if self.driver is not None: raise IllegalArgumentException( 'QueryRequest is already bound to a QueryDriver') self.driver = driver return self def get_driver(self): return self.driver
[docs] def set_timeout(self, timeout_ms): """ Sets the request timeout value, in milliseconds. This overrides any default value set in :py:class:`NoSQLHandleConfig`. The value must be positive. :param timeout_ms: the timeout value, in milliseconds. :type timeout_ms: int :returns: self. :raises IllegalArgumentException: raises the exception if the timeout value is less than or equal to 0. """ self._set_timeout(timeout_ms) return self
[docs] def get_timeout(self): """ Returns the timeout to use for the operation, in milliseconds. A value of 0 indicates that the timeout has not been set. :returns: the timeout value. :rtype: int """ return super(QueryRequest, self).get_timeout()
def set_defaults(self, cfg): super(QueryRequest, self).set_defaults(cfg) if self._consistency is None: self._consistency = cfg.get_default_consistency() return self def does_reads(self): """ Just about every permutation of query does reads. """ return True def does_writes(self): if self._prepared_statement is None: return False return self._prepared_statement.does_writes() def has_driver(self): return self.driver is not None def is_prepared(self): return self._prepared_statement is not None def is_query_request(self): return not self.is_internal def is_simple_query(self): return self._prepared_statement.is_simple_query() def topology_info(self): return (None if self._prepared_statement is None else self._prepared_statement.topology_info()) def topology_seq_num(self): return (-1 if self._prepared_statement is None else self._prepared_statement.topology_seq_num()) def validate(self): if self._statement is None and self._prepared_statement is None: raise IllegalArgumentException( 'Either statement or prepared statement should be set.') @staticmethod def get_serial_version(serial_version): return serial_version @staticmethod def create_serializer(serial_version): if serial_version >= SerdeUtil.SERIAL_VERSION_4: return borneo.nson.QueryRequestSerializer() return QueryRequestSerializer() def get_request_name(self): # type: () -> str return "Query"
[docs]class SystemRequest(Request): """ On-premise only. SystemRequest is an on-premise-only request used to perform any table-independent administrative operation such as create/drop of namespaces and security-relevant operations (create/drop users and roles). These operations are asynchronous and completion needs to be checked. Examples of statements used in this object include: CREATE NAMESPACE mynamespace\n CREATE USER some_user IDENTIFIED BY password\n CREATE ROLE some_role\n GRANT ROLE some_role TO USER some_user Execution of operations specified by this request is implicitly asynchronous. These are potentially long-running operations. :py:meth:`NoSQLHandle.system_request` returns a :py:class:`SystemResult` instance that can be used to poll until the operation succeeds or fails. """ def __init__(self): super(SystemRequest, self).__init__() self._statement = None def __str__(self): return 'SystemRequest: [statement=' + self._statement + ']'
[docs] def set_statement(self, statement): """ Sets the statement to use for the operation. :param statement: the statement. This is a required parameter. :type statement: str :returns: self. :raises IllegalArgumentException: raises the exception if statement is not a string. """ CheckValue.check_str(statement, 'statement') self._statement = statement return self
[docs] def get_statement(self): """ Returns the statement, or None if not set. :returns: the statement. :rtype: str """ return self._statement
[docs] def set_timeout(self, timeout_ms): """ Sets the request timeout value, in milliseconds. This overrides any default value set in :py:class:`NoSQLHandleConfig`. The value must be positive. :param timeout_ms: the timeout value, in milliseconds. :type timeout_ms: int :returns: self. :raises IllegalArgumentException: raises the exception if the timeout value is less than or equal to 0. """ self._set_timeout(timeout_ms) return self
[docs] def get_timeout(self): """ Returns the timeout to use for the operation, in milliseconds. A value of 0 indicates that the timeout has not been set. :returns: the timeout value. :rtype: int """ return super(SystemRequest, self).get_timeout()
def set_defaults(self, cfg): # Use the default request timeout if not set. self._check_config(cfg) if self.get_timeout() == 0: self._set_timeout(cfg.get_default_table_request_timeout()) return self def should_retry(self): return False def validate(self): if self._statement is None: raise IllegalArgumentException( 'SystemRequest requires a statement.') @staticmethod def get_serial_version(serial_version): return serial_version @staticmethod def create_serializer(serial_version): if serial_version >= SerdeUtil.SERIAL_VERSION_4: return borneo.nson.SystemRequestSerializer() return SystemRequestSerializer() def get_request_name(self): # type: () -> str return "System"
[docs]class SystemStatusRequest(Request): """ On-premise only. SystemStatusRequest is an on-premise-only request used to check the status of an operation started using a :py:class:`SystemRequest`. """ def __init__(self): super(SystemStatusRequest, self).__init__() self._statement = None self._operation_id = None def __str__(self): return ('SystemStatusRequest [statement=' + self._statement + ', operation_id=' + self._operation_id + ']')
[docs] def set_operation_id(self, operation_id): """ Sets the operation id to use for the request. The operation id can be obtained via :py:meth:`SystemResult.get_operation_id`. This parameter is not optional and represents an asynchronous operation that may be in progress. It is used to examine the result of the operation and if the operation has failed an exception will be thrown in response to a :py:meth:`NoSQLHandle.system_status` operation. If the operation is in progress or has completed successfully, the state of the operation is returned. :param operation_id: the operation id. :type operation_id: str :returns: self. :raises IllegalArgumentException: raises the exception if operation_id is a negative number. """ CheckValue.check_str(operation_id, 'operation_id') self._operation_id = operation_id return self
[docs] def get_operation_id(self): """ Returns the operation id to use for the request, None if not set. :returns: the operation id. :rtype: str """ return self._operation_id
[docs] def set_statement(self, statement): """ Sets the statement that was used for the operation. This is optional and is not used in any significant way. It is returned, unmodified, in the :py:class:`SystemResult` for convenience. :param statement: the statement. This is a optional parameter. :type statement: str :returns: self. :raises IllegalArgumentException: raises the exception if statement is not a string. """ CheckValue.check_str(statement, 'statement') self._statement = statement return self
[docs] def get_statement(self): """ Returns the statement set by :py:meth:`set_statement`, or None if not set. :returns: the statement. :rtype: str """ return self._statement
[docs] def set_timeout(self, timeout_ms): """ Sets the request timeout value, in milliseconds. This overrides any default value set in :py:class:`NoSQLHandleConfig`. The value must be positive. :param timeout_ms: the timeout value, in milliseconds. :type timeout_ms: int :returns: self. :raises IllegalArgumentException: raises the exception if the timeout value is less than or equal to 0. """ self._set_timeout(timeout_ms) return self
[docs] def get_timeout(self): """ Returns the timeout to use for the operation, in milliseconds. A value of 0 indicates that the timeout has not been set. :returns: the timeout value. :rtype: int """ return super(SystemStatusRequest, self).get_timeout()
def set_defaults(self, cfg): # Use the default request timeout if not set. self._check_config(cfg) if self.get_timeout() == 0: self._set_timeout(cfg.get_default_table_request_timeout()) return self def should_retry(self): return True def validate(self): if self._operation_id is None: raise IllegalArgumentException( 'SystemStatusRequest requires an operation id.') @staticmethod def get_serial_version(serial_version): return serial_version @staticmethod def create_serializer(serial_version): if serial_version >= SerdeUtil.SERIAL_VERSION_4: return borneo.nson.SystemStatusRequestSerializer() return SystemStatusRequestSerializer() def get_request_name(self): # type: () -> str return "SystemStatus"
[docs]class TableRequest(Request): """ TableRequest is used to create, modify, and drop tables. The operations allowed are those supported by the Data Definition Language (DDL) portion of the query language. The language provides for table creation and removal (drop), index add and drop, as well as schema evolution via alter table. Operations using DDL statements infer the table name from the query statement itself, e.g. "create table mytable(...)". Table creation requires a valid :py:class:`TableLimits` object to define the throughput desired for the table. If TableLimits is provided with any other type of query statement an exception is thrown. This request is also used to modify the limits of throughput and storage for an existing table. This case is handled by specifying a table name and limits without a query statement. If all three are specified it is an error. Execution of operations specified by this request is implicitly asynchronous. These are potentially long-running operations. :py:meth:`NoSQLHandle.table_request` returns a :py:class:`TableResult` instance that can be used to poll until the table reaches the desired state. The statement is required parameter unless modifying limits. """ def __init__(self): super(TableRequest, self).__init__() self._statement = None self._limits = None self._defined_tags = None # a dict, with str values self._match_etag = None self._free_form_tags = None # a dict, wih str values def __str__(self): return ('TableRequest: [name=' + str(self.get_table_name()) + ', statement=' + str(self._statement) + ', limits=' + str(self._limits) + ']')
[docs] def set_statement(self, statement): """ Sets the query statement to use for the operation. This parameter is required unless the operation is intended to change the limits of an existing table. :param statement: the statement. :type statement: str :returns: self. :raises IllegalArgumentException: raises the exception if statement is not a string. """ CheckValue.check_str(statement, 'statement') self._statement = statement return self
[docs] def get_statement(self): """ Returns the statement, or None if not set. :returns: the statement. :rtype: str """ return self._statement
[docs] def set_compartment(self, compartment): """ Cloud service only. Sets the name or id of a compartment to be used for this operation. The compartment may be specified as either a name (or path for nested compartments) or as an id (OCID). A name (vs id) can only be used when authenticated using a specific user identity. It is *not* available if authenticated as an Instance Principal which can be done when calling the service from a compute instance in the Oracle Cloud Infrastructure. See :py:meth:`borneo.iam.SignatureProvider.create_with_instance_principal`. :param compartment: the compartment name or id. If using a nested compartment, specify the full compartment path compartmentA.compartmentB, but exclude the name of the root compartment (tenant). :type compartment: str :returns: self. :raises IllegalArgumentException: raises the exception if compartment is not a str. """ self.set_compartment_internal(compartment) return self
[docs] def set_table_limits(self, table_limits): """ Cloud service only. Sets the table limits to use for the operation. Limits are used in only 2 cases -- table creation statements and limits modification operations. It is not used for other DDL operations. If limits are set for an on-premise service they are silently ignored. :param table_limits: the limits. :type table_limits: TableLimits :returns: self. :raises IllegalArgumentException: raises the exception if table_limits is not an instance TableLimits. """ if not isinstance(table_limits, TableLimits): raise IllegalArgumentException( 'set_table_limits requires an instance of TableLimits as ' + 'parameter.') self._limits = table_limits return self
[docs] def get_table_limits(self): """ Returns the table limits, or None if not set. :returns: the limits. :rtype: TableLimits """ return self._limits
def set_defined_tags(self, tags): """ Cloud service only. Sets defined tags :param tags the tags :type tags: dict(str, dict(str, object)) :versionadded: 5.4.0 """ self._defined_tags = tags def get_defined_tags(self): """ Cloud service only. Returns the defined tags or None if not set :returns: the defined tags. :rtype: dict(str, dict(str, object)) :versionadded: 5.4.0 """ return self._defined_tags def set_free_form_tags(self, tags): """ Cloud service only. Sets free_form tags :param tags the tags :type tags: dict(str, str) :versionadded: 5.4.0 """ self._free_form_tags = tags def get_free_form_tags(self): """ Returns the free_form tags or None if not set :returns: the free_form tags. :rtype: dict(str, str) :versionadded: 5.4.0 """ return self._free_form_tags def set_match_etag(self, etag): """ Cloud service only. Sets a ETag to match for the operation to proceed. The ETag must be non-null and have been previously returned in :py:class:`TableResult`. The ETag is a form of optimistic concurrency control allowing an application to ensure no unexpected modifications have been made to the table. :param etag the tag :type etag: str :versionadded: 5.4.0 """ self._match_etag = etag def get_match_etag(self): """ Cloud service only. :returns: the match etag or None if not set :rtype: str :versionadded: 5.4.0 """ return self._match_etag def set_namespace(self, namespace): """ On-premises only Sets the namespace to use for the operation. This will override any configured default value. :param namespace: the namespace :type namespace: str :raises IllegalArgumentException: raises the exception if namespace is not a string. :versionadded: 5.4.0 """ super(TableRequest, self).set_namespace(namespace) return self
[docs] def set_table_name(self, table_name): """ Sets the table name to use for the operation. The table name is only used to modify the limits of an existing table, and must not be set for any other operation. :param table_name: the name of the table. :type table_name: str :returns: self. :raises IllegalArgumentException: raises the exception if table_name is not a string. """ super(TableRequest, self).set_table_name(table_name) return self
[docs] def set_timeout(self, timeout_ms): """ Sets the request timeout value, in milliseconds. This overrides any default value set in :py:class:`NoSQLHandleConfig`. The value must be positive. :param timeout_ms: the timeout value, in milliseconds. :type timeout_ms: int :returns: self. :raises IllegalArgumentException: raises the exception if the timeout value is less than or equal to 0. """ self._set_timeout(timeout_ms) return self
[docs] def get_timeout(self): """ Returns the timeout to use for the operation, in milliseconds. A value of 0 indicates that the timeout has not been set. :returns: the timeout value. :rtype: int """ return super(TableRequest, self).get_timeout()
def set_defaults(self, cfg): """ Internal use only """ # Use the default request timeout if not set. self._check_config(cfg) if self.get_timeout() == 0: self._set_timeout(cfg.get_default_table_request_timeout()) # Use the default compartment if not set if self.get_compartment() is None: self.set_compartment_internal(cfg.get_default_compartment()) return self def should_retry(self): # Returns True if this request should be retried. return False def validate(self): table_name = self.get_table_name() if self._statement is None and table_name is None: raise IllegalArgumentException( 'TableRequest requires statement or TableLimits and name.') if self._statement is not None and table_name is not None: raise IllegalArgumentException( 'TableRequest cannot have both table name and statement.') if self._limits is not None: self._limits.validate() @staticmethod def get_serial_version(serial_version): return serial_version @staticmethod def create_serializer(serial_version): if serial_version >= SerdeUtil.SERIAL_VERSION_4: return borneo.nson.TableRequestSerializer() return TableRequestSerializer() def get_request_name(self): # type: () -> str return "Table"
[docs]class TableUsageRequest(Request): """ Cloud service only. Represents the argument of a :py:meth:`NoSQLHandle.get_table_usage` operation which returns dynamic information associated with a table, as returned in :py:class:`TableUsageResult`. This information includes a time series of usage snapshots, each indicating data such as read and write throughput, throttling events, etc, as found in :py:meth:`TableUsageResult.table_usage`. It is possible to return a range of usage records or, by default, only the most recent usage record. Usage records are created on a regular basis and maintained for a period of time. Only records for time periods that have completed are returned so that a user never sees changing data for a specific range. The table name is required parameter. """ def __init__(self): super(TableUsageRequest, self).__init__() self._start_time = 0 self._end_time = 0 self._limit = 0 self._start_index = 0 def set_namespace(self, namespace): """ On-premises only Sets the namespace to use for the operation. This will override any configured default value. :param namespace: the namespace :type namespace: str :raises IllegalArgumentException: raises the exception if namespace is not a string. :versionadded: 5.4.0 """ super(TableUsageRequest, self).set_namespace(namespace) return self
[docs] def set_table_name(self, table_name): """ Sets the table name to use for the request. This is a required parameter. :param table_name: the table name. :type table_name: str :returns: self. :raises IllegalArgumentException: raises the exception if table_name is not a string. """ super(TableUsageRequest, self).set_table_name(table_name) return self
[docs] def set_compartment(self, compartment): """ Cloud service only. Sets the name or id of a compartment to be used for this operation. The compartment may be specified as either a name (or path for nested compartments) or as an id (OCID). A name (vs id) can only be used when authenticated using a specific user identity. It is *not* available if authenticated as an Instance Principal which can be done when calling the service from a compute instance in the Oracle Cloud Infrastructure. See :py:meth:`borneo.iam.SignatureProvider.create_with_instance_principal`. :param compartment: the compartment name or id. If using a nested compartment, specify the full compartment path compartmentA.compartmentB, but exclude the name of the root compartment (tenant). :type compartment: str :returns: self. :raises IllegalArgumentException: raises the exception if compartment is not a str. """ self.set_compartment_internal(compartment) return self
[docs] def set_start_time(self, start_time): """ Sets the start time to use for the request in milliseconds since the Epoch in UTC time or an ISO 8601 formatted string accurate to milliseconds. If timezone is not specified it is interpreted as UTC. If no time range is set for this request the most recent complete usage record is returned. :param start_time: the start time. :type start_time: str :returns: self. :raises IllegalArgumentException: raises the exception if start_time is a negative number and is not an ISO 8601 formatted string. """ self._check_time(start_time) if isinstance(start_time, str): start_time = SerdeUtil.iso_time_to_ms(start_time) self._start_time = start_time return self
[docs] def get_start_time(self): """ Returns the start time to use for the request in milliseconds since the Epoch. :returns: the start time. :rtype: int """ return self._start_time
[docs] def get_start_time_string(self): """ Returns the start time as an ISO 8601 formatted string. If the start timestamp is not set, None is returned. :returns: the start time, or None if not set. :rtype: str """ if self._start_time == 0: return None return datetime.fromtimestamp( float(self._start_time) / 1000).replace(tzinfo=tz.UTC).isoformat()
[docs] def set_end_time(self, end_time): """ Sets the end time to use for the request in milliseconds since the Epoch in UTC time or an ISO 8601 formatted string accurate to milliseconds. If timezone is not specified it is interpreted as UTC. If no time range is set for this request the most recent complete usage record is returned. :param end_time: the end time. :type end_time: str :returns: self. :raises IllegalArgumentException: raises the exception if end_time is a negative number and is not an ISO 8601 formatted string. """ self._check_time(end_time) if isinstance(end_time, str): end_time = SerdeUtil.iso_time_to_ms(end_time) self._end_time = end_time return self
[docs] def get_end_time(self): """ Returns the end time to use for the request in milliseconds since the Epoch. :returns: the end time. :rtype: int """ return self._end_time
[docs] def get_end_time_string(self): """ Returns the end time as an ISO 8601 formatted string. If the end timestamp is not set, None is returned. :returns: the end time, or None if not set. :rtype: str """ if self._end_time == 0: return None return datetime.fromtimestamp( float(self._end_time) / 1000).replace(tzinfo=tz.UTC).isoformat()
[docs] def set_limit(self, limit): """ Sets the limit to the number of usage records desired. If this value is 0 there is no limit, but not all usage records may be returned in a single request due to size limitations. :param limit: the numeric limit. :type limit: int :returns: self. :raises IllegalArgumentException: raises the exception if limit is a negative number. """ CheckValue.check_int_ge_zero(limit, 'limit') self._limit = limit return self
[docs] def get_limit(self): """ Returns the limit to the number of usage records desired. :returns: the numeric limit. :rtype: int """ return self._limit
def set_start_index(self, start_index): """ Sets the index to use to start returning usage records within the specified range. This is related to the last_returned_index from a previous request and can be used to page usage records. If not set the list starts a 0 :param start_index: the numeric index. :type start_index: int :returns: self. :raises IllegalArgumentException: raises the exception if start_index is a negative number. :versionadded: 5.4.0 """ CheckValue.check_int_ge_zero(start_index, 'start_index') self._start_index = start_index return self def get_start_index(self): """ Returns the start_index for usage records desired. :returns: the numeric start_index. :rtype: int :versionadded: 5.4.0 """ return self._start_index
[docs] def set_timeout(self, timeout_ms): """ Sets the request timeout value, in milliseconds. This overrides any default value set in :py:class:`NoSQLHandleConfig`. The value must be positive. :param timeout_ms: the timeout value, in milliseconds. :type timeout_ms: int :returns: self. :raises IllegalArgumentException: raises the exception if the timeout value is less than or equal to 0. """ self._set_timeout(timeout_ms) return self
[docs] def get_timeout(self): """ Returns the timeout to use for the operation, in milliseconds. A value of 0 indicates that the timeout has not been set. :returns: the value. :rtype: int """ return super(TableUsageRequest, self).get_timeout()
def should_retry(self): # Returns True if this request should be retried. return False def validate(self): if self.get_table_name() is None: raise IllegalArgumentException( 'TableUsageRequest requires a table name.') if self._start_time > self._end_time > 0: raise IllegalArgumentException( 'TableUsageRequest: end time must be greater than start time.') @staticmethod def get_serial_version(serial_version): return serial_version @staticmethod def create_serializer(serial_version): if serial_version >= SerdeUtil.SERIAL_VERSION_4: return borneo.nson.TableUsageRequestSerializer() return TableUsageRequestSerializer() @staticmethod def _check_time(dt): if (not (isinstance(dt, int) or CheckValue.is_str(dt)) or not CheckValue.is_str(dt) and dt < 0): raise IllegalArgumentException( 'dt must be an integer that is not negative or an ISO ' + '8601 formatted string. Got:' + str(dt)) def get_request_name(self): # type: () -> str return "TableUsage"
[docs]class WriteMultipleRequest(Request): """ Represents the input to a :py:meth:`NoSQLHandle.write_multiple` operation. This request can be used to perform a sequence of :py:class:`PutRequest` or :py:class:`DeleteRequest` operations associated with a table that share the same shard key portion of their primary keys, the WriteMultiple operation as whole is atomic. It is an efficient way to atomically modify multiple related rows. On a successful operation :py:meth:`WriteMultipleResult.get_success` returns True. The execution result of each operations can be retrieved using :py:meth:`WriteMultipleResult.get_results`. If the WriteMultiple operation is aborted because of the failure of an operation with abort_if_unsuccessful set to True, then :py:meth:`WriteMultipleResult.get_success` return False, the index of failed operation can be accessed using :py:meth:`WriteMultipleResult.get_failed_operation_index`, and the execution result of failed operation can be accessed using :py:meth:`WriteMultipleResult.get_failed_operation_result`. """ def __init__(self): # Constructs an empty request. super(WriteMultipleRequest, self).__init__() self._ops = list() self._durability = None
[docs] def add(self, request, abort_if_unsuccessful): """ Adds a Request to the operation list, do validation check before adding it. :param request: the Request to add, either :py:class:`PutRequest` or :py:class:`DeleteRequest`. :type request: Request :param abort_if_unsuccessful: True if this operation should cause the entire WriteMultiple operation to abort when this operation fails. :type abort_if_unsuccessful: bool :returns: self. :raises BatchOperationNumberLimitException: raises the exception if the number of requests exceeds the limit, or IllegalArgumentException if the request is neither a :py:class:`PutRequest` or :py:class:`DeleteRequest`. Or any invalid state of the Request. :raises IllegalArgumentException: raises the exception if parameters are not expected type. """ if not isinstance(request, (PutRequest, DeleteRequest)): raise IllegalArgumentException( 'Invalid request, requires an instance of PutRequest or ' + 'DeleteRequest as parameter. Got: ' + str(request)) CheckValue.check_boolean(abort_if_unsuccessful, 'abort_if_unsuccessful') table_name = self.get_table_name() if table_name is None: self.set_table_name(request.get_table_name()) else: if WriteMultipleRequest.get_top_table_name( request.get_table_name().lower()) \ != table_name.lower(): raise IllegalArgumentException( 'The parent table_name used for the operation is ' 'different from that of others: ' + table_name) request.validate() self._ops.append(self.OperationRequest(request, abort_if_unsuccessful)) return self
@staticmethod def get_top_table_name(table_name): pos = table_name.find('.') if pos == -1: return table_name return table_name[0:pos] def is_single_table(self): if len(self._ops) < 2: return True single_table_name = self.get_table_name() for op in self._ops: if single_table_name.lower() != op.get_request().get_table_name().lower(): return False return True
[docs] def set_compartment(self, compartment): """ Cloud service only. Sets the name or id of a compartment to be used for this operation. The compartment may be specified as either a name (or path for nested compartments) or as an id (OCID). A name (vs id) can only be used when authenticated using a specific user identity. It is *not* available if authenticated as an Instance Principal which can be done when calling the service from a compute instance in the Oracle Cloud Infrastructure. See :py:meth:`borneo.iam.SignatureProvider.create_with_instance_principal`. :param compartment: the compartment name or id. If using a nested compartment, specify the full compartment path compartmentA.compartmentB, but exclude the name of the root compartment (tenant). :type compartment: str :returns: self. :raises IllegalArgumentException: raises the exception if compartment is not a str. """ self.set_compartment_internal(compartment) return self
[docs] def get_request(self, index): """ Returns the Request at the given position, it may be either a :py:class:`PutRequest` or :py:class:`DeleteRequest` object. :param index: the position of Request to get. :type index: int :returns: the Request at the given position. :rtype: Request :raises IndexOutOfBoundsException: raises the exception if the position is negative or greater or equal to the number of Requests. :raises IllegalArgumentException: raises the exception if index is a negative number. """ CheckValue.check_int_ge_zero(index, 'index') return self._ops[index].get_request()
def get_operations(self): # Returns the request lists, internal for now return self._ops
[docs] def get_num_operations(self): """ Returns the number of Requests. :returns: the number of Requests. :rtype: int """ return len(self._ops)
[docs] def set_timeout(self, timeout_ms): """ Sets the request timeout value, in milliseconds. This overrides any default value set in :py:class:`NoSQLHandleConfig`. The value must be positive. :param timeout_ms: the timeout value, in milliseconds. :type timeout_ms: int :returns: self. :raises IllegalArgumentException: raises the exception if the timeout value is less than or equal to 0. """ self._set_timeout(timeout_ms) return self
[docs] def get_timeout(self): """ Returns the timeout to use for the operation, in milliseconds. A value of 0 indicates that the timeout has not been set. :returns: the timeout value. :rtype: int """ return super(WriteMultipleRequest, self).get_timeout()
[docs] def clear(self): """ Removes all of the operations from the WriteMultiple request. """ self.set_table_name(None) self._ops = list()
[docs] def set_durability(self, durability): """ On-premise only. Sets the durability to use for the operation. :param durability: the Durability to use :type durability: Durability :returns: self. :raises IllegalArgumentException: raises the exception if Durability is not valid :versionadded: 5.3.0 """ if durability is None: self._durability = None return if not isinstance(durability, Durability): raise IllegalArgumentException('set_durability requires an ' + 'instance of Durability as parameter.') durability.validate() self._durability = durability return self
[docs] def get_durability(self): """ On-premise only. Gets the durability to use for the operation or None if not set :returns: the Durability :versionadded: 5.3.0 """ return self._durability
def does_reads(self): for op in self._ops: req = op.get_request() if req.does_reads(): return True return False def does_writes(self): return True def validate(self): if not self._ops: raise IllegalArgumentException('The requests list is empty.') @staticmethod def get_serial_version(serial_version): return serial_version @staticmethod def create_serializer(serial_version): if serial_version >= SerdeUtil.SERIAL_VERSION_4: return borneo.nson.WriteMultipleRequestSerializer() return WriteMultipleRequestSerializer() class OperationRequest(object): # A wrapper of WriteRequest that contains an additional flag # abort_if_unsuccessful. Internal for now def __init__(self, request, abort_if_unsuccessful): self._request = request self._abort_if_unsuccessful = abort_if_unsuccessful def get_request(self): return self._request def is_abort_if_unsuccessful(self): return self._abort_if_unsuccessful def get_request_name(self): # type: () -> str return "WriteMultiple"
[docs]class Result(object): """ Result is a base class for result classes for all supported operations. All state and methods are maintained by extending classes. """ def __init__(self): """ read_kb and read_units will be different in the case of Absolute Consistency. write_kb and write_units will always be equal. """ self._rate_limit_delayed_ms = 0 self._read_kb = 0 self._read_units = 0 self._retry_stats = None self._write_kb = 0 self._write_units = 0 def get_rate_limit_delayed_ms(self): """ Get the time the operation was delayed due to rate limiting. Cloud only. If rate limiting is in place, this value will represent the number of milliseconds that the operation was delayed due to rate limiting. If the value is zero, rate limiting did not apply or the operation did not need to wait for rate limiting. :returns: delay time in milliseconds. """ return self._rate_limit_delayed_ms def get_read_units(self): # Internal use only. return self._read_units def get_retry_stats(self): """ Returns a stats object with information about retries. :returns: stats object with retry information, or None if no retries were performed. """ return self._retry_stats def get_write_units(self): # Internal use only. return self._write_kb def set_rate_limit_delayed_ms(self, delay_ms): """ :param delay_ms: the delay in milliseconds. :type delay_ms: int :returns: self. """ self._rate_limit_delayed_ms = delay_ms return self def set_read_kb(self, read_kb): self._read_kb = read_kb return self def set_read_units(self, read_units): self._read_units = read_units return self def set_retry_stats(self, retry_stats): """ Internal use only. :param retry_stats: the stats object to use. :type retry_stats: RetryStats """ self._retry_stats = retry_stats def set_write_kb(self, write_kb): self._write_kb = write_kb return self def set_write_units(self, write_units): # type: (int) -> Result self._write_units = write_units return self def _get_read_kb(self): return self._read_kb def _get_write_kb(self): return self._write_kb
class WriteResult(Result): """ A base class for results of single row modifying operations such as put and delete. """ def __init__(self): super(WriteResult, self).__init__() self._existing_version = None self._existing_value = None self._existing_modification_time = 0 def set_existing_value(self, existing_value): self._existing_value = existing_value return self def set_existing_version(self, existing_version): self._existing_version = existing_version return self def set_existing_modification_time(self, existing_modification_time): self._existing_modification_time = existing_modification_time return self def _get_existing_value(self): return self._existing_value def _get_existing_version(self): return self._existing_version def _get_existing_modification_time(self): return self._existing_modification_time
[docs]class DeleteResult(WriteResult): """ Represents the result of a :py:meth:`NoSQLHandle.delete` operation. If the delete succeeded :py:meth:`get_success` returns True. Information about the existing row on failure may be available using :py:meth:`get_existing_value` and :py:meth:`get_existing_version`, depending on the use of :py:meth:`DeleteRequest.set_return_row`. """ def __init__(self): super(DeleteResult, self).__init__() self._success = False def __str__(self): return str(self._success) def set_success(self, success): self._success = success return self
[docs] def get_success(self): """ Returns True if the delete operation succeeded. :returns: True if the operation succeeded. :rtype: bool """ return self._success
[docs] def get_existing_value(self): """ Returns the existing row value if available. It will be available if the target row exists and the operation failed because of a :py:class:`Version` mismatch and the corresponding :py:class:`DeleteRequest` the method :py:meth:`DeleteRequest.set_return_row` was called with a True value. :returns: the value. :rtype: dict """ return self._get_existing_value()
[docs] def get_existing_version(self): """ Returns the existing row :py:class:`Version` if available. It will be available if the target row exists and the operation failed because of a :py:class:`Version` mismatch and the corresponding :py:class:`DeleteRequest` the method :py:meth:`DeleteRequest.set_return_row` was called with a True value. :returns: the version. :rtype: Version """ return self._get_existing_version()
[docs] def get_existing_modification_time(self): """ Returns the existing row modification time if available. It will be available if the target row exists and the operation failed because of a :py:class:`Version` mismatch and the corresponding :py:class:`DeleteRequest` the method :py:meth:`DeleteRequest.set_return_row` was called with a True value. :returns: the modification time in milliseconds since January 1, 1970 :rtype: int :versionadded: 5.3.0 """ return self._get_existing_modification_time()
[docs] def get_read_kb(self): """ Returns the read throughput consumed by this operation, in KBytes. This is the actual amount of data read by the operation. The number of read units consumed is returned by :py:meth:`get_read_units` which may be a larger number because this was an update operation. :returns: the read KBytes consumed. :rtype: int """ return self._get_read_kb()
[docs] def get_read_units(self): """ Returns the read throughput consumed by this operation, in read units. This number may be larger than that returned by :py:meth:`get_read_kb` because it was an update operation. :returns: the read units consumed. :rtype: int """ return super(DeleteResult, self).get_read_units()
[docs] def get_write_kb(self): """ Returns the write throughput consumed by this operation, in KBytes. :returns: the write KBytes consumed. :rtype: int """ return self._get_write_kb()
[docs] def get_write_units(self): """ Returns the write throughput consumed by this operation, in write units. :returns: the write units consumed. :rtype: int """ return super(DeleteResult, self).get_write_units()
[docs]class GetResult(Result): """ Represents the result of a :py:meth:`NoSQLHandle.get` operation. On a successful operation the value of the row is available using :py:meth:`get_value` and the other state available in this class is valid. On failure that value is None and other state, other than consumed capacity, is undefined. """ def __init__(self): super(GetResult, self).__init__() self._value = None self._version = None self._expiration_time = 0 self._modification_time = 0 def __str__(self): return 'None' if self._value is None else str(self._value) def set_value(self, value): # Sets the value of this object, internal. self._value = value return self
[docs] def get_value(self): """ Returns the value of the returned row, or None if the row does not exist. :returns: the value of the row, or None if it does not exist. :rtype: dict """ return self._value
def set_version(self, version): # Sets the version, internal. self._version = version return self
[docs] def get_version(self): """ Returns the :py:class:`Version` of the row if the operation was successful, or None if the row does not exist. :returns: the version of the row, or None if the row does not exist. :rtype: Version """ return self._version
def set_expiration_time(self, expiration_time): # Sets the expiration time, internal self._expiration_time = expiration_time return self
[docs] def get_expiration_time(self): """ Returns the expiration time of the row. A zero value indicates that the row does not expire. This value is valid only if the operation successfully returned a row (:py:meth:`get_value` returns non-none). :returns: the expiration time in milliseconds since January 1, 1970, or zero if the row never expires or the row does not exist. :rtype: int """ return self._expiration_time
def set_modification_time(self, modification_time): # Sets the modification time, internal self._modification_time = modification_time return self def get_modification_time(self): """ Returns the modification time of the row. This value is valid only if the operation successfully returned a row (:py:meth:`get_value` returns non-none). :returns: the modification time in milliseconds since January 1, 1970 :rtype: int """ return self._modification_time
[docs] def get_read_kb(self): """ Returns the read throughput consumed by this operation, in KBytes. This is the actual amount of data read by the operation. The number of read units consumed is returned by :py:meth:`get_read_units` which may be a larger number if the operation used Consistency.ABSOLUTE. :returns: the read KBytes consumed. :rtype: int """ return self._get_read_kb()
[docs] def get_read_units(self): """ Returns the read throughput consumed by this operation, in read units. This number may be larger than that returned by :py:meth:`get_read_kb` if the operation used Consistency.ABSOLUTE. :returns: the read units consumed. :rtype: int """ return super(GetResult, self).get_read_units()
[docs] def get_write_kb(self): """ Returns the write throughput consumed by this operation, in KBytes. :returns: the write KBytes consumed. :rtype: int """ return self._get_write_kb()
[docs] def get_write_units(self): """ Returns the write throughput consumed by this operation, in write units. :returns: the write units consumed. :rtype: int """ return super(GetResult, self).get_write_units()
[docs]class GetIndexesResult(Result): """ Represents the result of a :py:meth:`NoSQLHandle.get_indexes` operation. On a successful operation the index information is returned in a list of IndexInfo. """ def __init__(self): super(GetIndexesResult, self).__init__() self._indexes = None def __str__(self): idxes = '' for index in range(len(self._indexes)): idxes += str(self._indexes[index]) if index < len(self._indexes) - 1: idxes += ',' return '[' + idxes + ']' def set_indexes(self, indexes): self._indexes = indexes return self
[docs] def get_indexes(self): """ Returns the list of index information returned by the operation. :returns: the indexes information. :rtype: list(IndexInfo) """ return self._indexes
[docs]class ListTablesResult(Result): """ Represents the result of a :py:meth:`NoSQLHandle.list_tables` operation. On a successful operation the table names are available as well as the index of the last returned table. Tables are returned in a list, sorted alphabetically. """ def __init__(self): super(ListTablesResult, self).__init__() self._tables = None self._last_index_returned = 0 def __str__(self): return '[' + ','.join(self._tables) + ']' def set_tables(self, tables): self._tables = tables return self
[docs] def get_tables(self): """ Returns the array of table names returned by the operation. :returns: the table names. :rtype: list(str) """ return self._tables
def set_last_index_returned(self, last_index_returned): self._last_index_returned = last_index_returned return self
[docs] def get_last_returned_index(self): """ Returns the index of the last table name returned. This can be provided to :py:class:`ListTablesRequest` to be used as a starting point for listing tables. :returns: the index. :rtype: int :versionadded: 5.4.0 """ return self._last_index_returned
[docs]class MultiDeleteResult(Result): """ Represents the result of a :py:meth:`NoSQLHandle.multi_delete` operation. On a successful operation the number of rows deleted is available using :py:meth:`get_num_deletions`. There is a limit to the amount of data consumed by a single call. If there are still more rows to delete, the continuation key can be get using :py:meth:`get_continuation_key`. """ def __init__(self): super(MultiDeleteResult, self).__init__() self._continuation_key = None self._num_deleted = 0 def __str__(self): return 'Deleted ' + str(self._num_deleted) + ' rows.' def set_continuation_key(self, continuation_key): self._continuation_key = continuation_key return self
[docs] def get_continuation_key(self): """ Returns the continuation key where the next MultiDelete request resume from. :returns: the continuation key, or None if there are no more rows to delete. :rtype: bytearray """ return self._continuation_key
def set_num_deletions(self, num_deleted): self._num_deleted = num_deleted return self
[docs] def get_num_deletions(self): """ Returns the number of rows deleted from the table. :returns: the number of rows deleted. :rtype: int """ return self._num_deleted
[docs] def get_read_kb(self): """ Returns the read throughput consumed by this operation, in KBytes. This is the actual amount of data read by the operation. The number of read units consumed is returned by :py:meth:`get_read_units` which may be a larger number because this was an update operation. :returns: the read KBytes consumed. :rtype: int """ return self._get_read_kb()
[docs] def get_read_units(self): """ Returns the read throughput consumed by this operation, in read units. This number may be larger than that returned by :py:meth:`get_read_kb` because it was an update operation. :returns: the read units consumed. :rtype: int """ return super(MultiDeleteResult, self).get_read_units()
[docs] def get_write_kb(self): """ Returns the write throughput consumed by this operation, in KBytes. :returns: the write KBytes consumed. :rtype: int """ return self._get_write_kb()
[docs] def get_write_units(self): """ Returns the write throughput consumed by this operation, in write units. :returns: the write units consumed. :rtype: int """ return super(MultiDeleteResult, self).get_write_units()
[docs]class PrepareResult(Result): """ The result of a prepare operation. The returned :py:class:`PreparedStatement` can be re-used for query execution using :py:meth:`QueryRequest.set_prepared_statement` """ def __init__(self): super(PrepareResult, self).__init__() self._prepared_statement = None def set_prepared_statement(self, prepared_statement): # Sets the prepared statement. self._prepared_statement = prepared_statement return self
[docs] def get_prepared_statement(self): """ Returns the value of the prepared statement. :returns: the value of the prepared statement. :rtype: PreparedStatement """ return self._prepared_statement
[docs] def get_read_kb(self): """ Returns the read throughput consumed by this operation, in KBytes. This is the actual amount of data read by the operation. The number of read units consumed is returned by :py:meth:`get_read_units` which may be a larger number if the operation used Consistency.ABSOLUTE. :returns: the read KBytes consumed. :rtype: int """ return self._get_read_kb()
[docs] def get_read_units(self): """ Returns the read throughput consumed by this operation, in read units. This number may be larger than that returned by :py:meth:`get_read_kb` if the operation used Consistency.ABSOLUTE. :returns: the read units consumed. :rtype: int """ return super(PrepareResult, self).get_read_units()
[docs] def get_write_kb(self): """ Returns the write throughput consumed by this operation, in KBytes. :returns: the write KBytes consumed. :rtype: int """ return self._get_write_kb()
[docs] def get_write_units(self): """ Returns the write throughput consumed by this operation, in write units. :returns: the write units consumed. :rtype: int """ return super(PrepareResult, self).get_write_units()
[docs]class PutResult(WriteResult): """ Represents the result of a :py:meth:`NoSQLHandle.put` operation. On a successful operation the value returned by :py:meth:`get_version` is non-none. On failure that value is None. Information about the existing row on failure may be available using :py:meth:`get_existing_value` and :py:meth:`get_existing_version`, depending on the use of :py:meth:`PutRequest.set_return_row` and whether the put had an option set using :py:meth:`PutRequest.set_option`. """ def __init__(self): super(PutResult, self).__init__() self._version = None self._generated_value = None def __str__(self): return 'None Version' if self._version is None else str(self._version) def set_version(self, version): self._version = version return self
[docs] def get_version(self): """ Returns the :py:class:`Version` of the new row if the operation was successful. If the operation failed None is returned. :returns: the :py:class:`Version` on success, None on failure. :rtype: Version """ return self._version
def set_generated_value(self, value): self._generated_value = value return self
[docs] def get_generated_value(self): """ Returns the value generated if the operation created a new value. This can happen if the table contains an identity column or string column declared as a generated UUID. If the table has no such columns this value is None. If a value was generated for the operation, it is non-None. :returns: the generated value. """ return self._generated_value
[docs] def get_existing_version(self): """ Returns the existing row :py:class:`Version` if available. This value will only be available if the conditional put operation failed and the request specified that return information be returned using :py:meth:`PutRequest.set_return_row`. :returns: the :py:class:`Version`. :rtype: Version """ return self._get_existing_version()
[docs] def get_existing_value(self): """ Returns the existing row value if available. This value will only be available if the conditional put operation failed and the request specified that return information be returned using :py:meth:`PutRequest.set_return_row`. :returns: the value. :rtype: dict """ return self._get_existing_value()
[docs] def get_existing_modification_time(self): """ Returns the existing row modification time if available. It will be available if the conditional put operation failed and the request specified that return information be returned using :py:meth:`PutRequest.set_return_row`. A value of -1 indicates this feature is not available at the connected server. :returns: the modification time in milliseconds since January 1, 1970 :rtype: int :versionadded: 5.3.0 """ return self._get_existing_modification_time()
[docs] def get_read_kb(self): """ Returns the read throughput consumed by this operation, in KBytes. This is the actual amount of data read by the operation. The number of read units consumed is returned by :py:meth:`get_read_units` which may be a larger number because this was an update operation. :returns: the read KBytes consumed. :rtype: int """ return self._get_read_kb()
[docs] def get_read_units(self): """ Returns the read throughput consumed by this operation, in read units. This number may be larger than that returned by :py:meth:`get_read_kb` because it was an update operation. :returns: the read units consumed. :rtype: int """ return super(PutResult, self).get_read_units()
[docs] def get_write_kb(self): """ Returns the write throughput consumed by this operation, in KBytes. :returns: the write KBytes consumed. :rtype: int """ return self._get_write_kb()
[docs] def get_write_units(self): """ Returns the write throughput consumed by this operation, in write units. :returns: the write units consumed. :rtype: int """ return super(PutResult, self).get_write_units()
[docs]class QueryResult(Result): """ QueryResult comprises a list of dict instances representing the query results. The shape of the values is based on the schema implied by the query. For example a query such as "SELECT * FROM ..." that returns an intact row will return values that conform to the schema of the table. Projections return instances that conform to the schema implied by the statement. UPDATE queries either return values based on a RETURNING clause or, by default, the number of rows affected by the statement. A single QueryResult does not imply that all results for the query have been returned. If the value returned by :py:meth:`QueryRequest.is_done` is False there are additional results available. This can happen even if there are no values in the returned QueryResult. The best way to use :py:class:`QueryRequest` and :py:class:`QueryResult` is to perform operations in a loop, for example: .. code-block:: pycon handle = ... request = QueryRequest().set_statement('SELECT * FROM foo') while True: result = handle.query(request) results = result.get_results() # do something with the results if request.is_done(): break Modification queries either return values based on a RETURNING clause or, by default, return the number of rows affected by the statement in a dictionary. INSERT queries with no RETURNING clause return a dictionary indicating the number of rows inserted, for example {'NumRowsInserted': 5}. UPDATE queries with no RETURNING clause return a dictionary indicating the number of rows updated, for example {'NumRowsUpdated': 3}. DELETE queries with no RETURNING clause return a dictionary indicating the number of rows deleted, for example {'numRowsDeleted': 2}. """ def __init__(self, request, computed=True): super(QueryResult, self).__init__() self._request = request self._results = None self._continuation_key = None # The following 6 fields are used only for "internal" QueryResults, # i.e., those received and processed by the ReceiveIter. self._reached_limit = False self._is_computed = computed # The following 4 fields are used during phase 1 of a sorting # ALL_PARTITIONS query. In this case, self._results may store results # from multiple partitions. If so, self._results are grouped by # partition and self._pids, self._num_results_per_pid, and # self._continuation_keys fields store the partition id, the number of # results, and the continuation key per partition. Finally, the # self._is_in_phase1 specifies whether phase 1 is done. self._is_in_phase1 = False self._num_results_per_pid = None self._continuation_keys = None self._pids = None def __str__(self): self._compute() if self._results is None: return None res = 'Number of query results: ' + str(len(self._results)) for result in self._results: res += '\n' + str(result) return res + '\n' def set_results(self, results): self._results = results return self
[docs] def get_results(self): """ Returns a list of results for the query. It is possible to have an empty list and a non-none continuation key. :returns: a list of results for the query. :rtype: list(dict) """ self._compute() return self._results
def get_results_internal(self): return self._results def set_continuation_key(self, continuation_key): self._continuation_key = continuation_key return self
[docs] def get_continuation_key(self): """ Returns the continuation key that can be used to obtain more results if non-none. :returns: the continuation key, or None if there are no further values to return. :rtype: bytearray """ self._compute() return self._continuation_key
def set_reached_limit(self, reached_limit): self._reached_limit = reached_limit return self def reached_limit(self): return self._reached_limit def get_request(self): return self._request def set_computed(self, computed): self._is_computed = computed return self def set_is_in_phase1(self, is_in_phase1): self._is_in_phase1 = is_in_phase1 def is_in_phase1(self): return self._is_in_phase1 def set_num_results_per_pid(self, num_results_per_pid): self._num_results_per_pid = num_results_per_pid def get_num_partition_results(self, i): return self._num_results_per_pid[i] def set_partition_cont_keys(self, continuation_keys): self._continuation_keys = continuation_keys def get_partition_cont_key(self, i): return self._continuation_keys[i] def set_pids(self, pids): self._pids = pids def get_num_pids(self): return 0 if self._pids is None else len(self._pids) def get_pid(self, i): return self._pids[i]
[docs] def get_read_kb(self): """ Returns the read throughput consumed by this operation, in KBytes. This is the actual amount of data read by the operation. The number of read units consumed is returned by :py:meth:`get_read_units` which may be a larger number if the operation used Consistency.ABSOLUTE. :returns: the read KBytes consumed. :rtype: int """ self._compute() return self._get_read_kb()
[docs] def get_read_units(self): """ Returns the read throughput consumed by this operation, in read units. This number may be larger than that returned by :py:meth:`get_read_kb` if the operation used Consistency.ABSOLUTE. :returns: the read units consumed. :rtype: int """ self._compute() return super(QueryResult, self).get_read_units()
[docs] def get_write_kb(self): """ Returns the write throughput consumed by this operation, in KBytes. :returns: the write KBytes consumed. :rtype: int """ self._compute() return self._get_write_kb()
[docs] def get_write_units(self): """ Returns the write throughput consumed by this operation, in write units. :returns: the write units consumed. :rtype: int """ self._compute() return super(QueryResult, self).get_write_units()
def _compute(self): if self._is_computed: return driver = self._request.get_driver() driver.compute(self) self._is_computed = True # If the original request specified rate limiting, apply the used # read/write units to the limiter(s) here. if self._request is not None: read_limiter = self._request.get_read_rate_limiter() if read_limiter is not None: print(self.get_read_units()) read_limiter.consume_units_unconditionally( self.get_read_units()) write_limiter = self._request.get_write_rate_limiter() if write_limiter is not None: write_limiter.consume_units_unconditionally( self.get_write_units())
[docs]class QueryIterableResult(Result): """ QueryIterableResult comprises an iterable list of dict instances representing all the query results. The shape of the values is based on the schema implied by the query. For example a query such as "SELECT * FROM ..." that returns an intact row will return values that conform to the schema of the table. Projections return instances that conform to the schema implied by the statement. UPDATE queries either return values based on a RETURNING clause or, by default, the number of rows affected by the statement. Each iterator from QueryIterableResult will iterate over all results of the query. .. code-block:: pycon handle = ... request = QueryRequest().set_statement('SELECT * FROM foo') qiresult = handle.query-iterable(request) for row in qiresult: # do something with the result row print(row) Modification queries either return values based on a RETURNING clause or, by default, return the number of rows affected by the statement in a dictionary. INSERT queries with no RETURNING clause return a dictionary indicating the number of rows inserted, for example {'NumRowsInserted': 5}. UPDATE queries with no RETURNING clause return a dictionary indicating the number of rows updated, for example {'NumRowsUpdated': 3}. DELETE queries with no RETURNING clause return a dictionary indicating the number of rows deleted, for example {'numRowsDeleted': 2}. :versionadded: 5.3.6 """ def __init__(self, request, handle): # NoSQLHandle handle super(QueryIterableResult, self).__init__() self.request = request self.handle = handle self.readKB = 0 self.readUnits = 0 self.writeKB = 0 def __str__(self): # type: () -> str res = 'QueryIterableResult(' + str(self.request) + ')' return res + '\n'
[docs] def get_read_kb(self): # type: () -> int """ Returns the read throughput consumed by this operation, in KBytes. This is the cumulative actual amount of data read by the operation since the beginning of the iterable. The number of read units consumed is returned by :py:meth:`get_read_units` which may be a larger number if the operation used Consistency.ABSOLUTE. :returns: the read KBytes consumed. :rtype: int """ return self.readKB
[docs] def get_read_units(self): # type: () -> int """ Returns the read throughput consumed by this operation, in read units. This is the cumulative amount since the beginning of the iterable. This number may be larger than that returned by :py:meth:`get_read_kb` if the operation used Consistency.ABSOLUTE. :returns: the read units consumed. :rtype: int """ return self.readUnits
[docs] def get_write_kb(self): # type: () -> int """ Returns the write throughput consumed by this operation, in KBytes. :returns: the write KBytes consumed. :rtype: int """ return self.writeKB
def __iter__(self): return QueryIterator(self)
class QueryIterator: """ QueryIterator iterates over all results of a query. :versionadded: 5.3.6 """ def __init__(self, iterable): self._iterable = iterable self._internalRequest = iterable.request.copy() self._internal_result = None self._partialResultList = None self._partialResultIter = None self._next = None self._closed = False def _compute(self): if self._closed: return if self._partialResultList is None: self._internal_result = \ self._iterable.handle.query(self._internalRequest) self._partialResultList = self._internal_result.get_results() self._partialResultIter = self._partialResultList.__iter__() try: self._next = next(self._partialResultIter) return except StopIteration: has_next = False self.set_stats(self._internal_result) else: try: self._next = next(self._partialResultIter) return except StopIteration: has_next = False while not has_next and not self._internalRequest.is_done(): self._internal_result = \ self._iterable.handle.query(self._internalRequest) self._partialResultList = self._internal_result.get_results() self._partialResultIter = self._partialResultList.__iter__() has_next = True try: self._next = next(self._partialResultIter) except StopIteration: has_next = False self.set_stats(self._internal_result) if self._internalRequest.is_done(): self._internalRequest.close() if not has_next: self._closed = True def set_stats(self, internal_result): self._iterable.readKB += internal_result.get_read_kb() self._iterable.readUnits += internal_result.get_read_units() self._iterable.writeKB += internal_result.get_write_kb() self._iterable.set_rate_limit_delayed_ms( self._iterable.get_rate_limit_delayed_ms() + internal_result.get_rate_limit_delayed_ms()) self._iterable.set_read_kb(self._iterable.get_read_kb() + internal_result.get_read_kb()) self._iterable.set_read_units(self._iterable.get_read_units() + internal_result.get_read_units()) self._iterable.set_write_kb(self._iterable.get_write_kb() + internal_result.get_write_kb()) self._iterable.set_write_units(self._iterable.get_write_units() + internal_result.get_write_units()) if internal_result.get_retry_stats() is not None: if self._iterable.get_retry_stats() is None: self._iterable.set_retry_stats(RetryStats()) self._iterable.get_retry_stats().add_delay_ms( internal_result.get_retry_stats().get_delay_ms()) self._iterable.get_retry_stats().increment_retries( internal_result.get_retry_stats().get_retries()) self._iterable.get_retry_stats().add_exceptions( internal_result.get_retry_stats().get_exceptions_map()) def __next__(self): self._compute() if self._closed: raise StopIteration return self._next
[docs]class SystemResult(Result): """ On-premise only. SystemResult is returned from :py:meth:`NoSQLHandle.system_status` and :py:meth:`NoSQLHandle.system_request` operations. It encapsulates the state of the operation requested. Some operations performed by :py:meth:`NoSQLHandle.system_request` are asynchronous. When such an operation has been performed it is necessary to call :py:meth:`NoSQLHandle.system_status` until the status of the operation is known. The method :py:meth:`wait_for_completion` exists to perform this task and should be used whenever possible. Asynchronous operations (e.g. create namespace) can be distinguished from synchronous system operations in this way: Asynchronous operations may return a non-none operation id.\n Asynchronous operations modify state, while synchronous operations are read-only.\n Synchronous operations return a state of STATE.COMPLETE and have a non-none result string. :py:meth:`NoSQLHandle.system_status` is synchronous, returning the known state of the operation. It should only be called if the operation was asynchronous and returned a non-none operation id. """ def __init__(self): super(SystemResult, self).__init__() self._operation_id = None self._result_string = None self._state = 0 self._statement = None def __str__(self): return ('SystemResult [statement=' + self._statement + ', state=' + SerdeUtil.get_operation_state(self._state) + ', operation_id=' + self._operation_id + ', result_string=' + self._result_string + ']') def set_operation_id(self, operation_id): # Sets the operation id for the operation. self._operation_id = operation_id return self
[docs] def get_operation_id(self): """ Returns the operation id for the operation if it was asynchronous. This is None if the request did not generate a new operation and/or the operation state is SystemState.COMPLETE. The value can be used in :py:meth:`SystemStatusRequest.set_operation_id` to get status and find potential errors resulting from the operation. This method is only useful for the result of asynchronous operations. :returns: the operation id. :rtype: str """ return self._operation_id
def set_state(self, state): # Sets the operation state. self._state = state return self
[docs] def get_operation_state(self): """ Returns the operation state. :returns: the state. :rtype: int """ return self._state
def set_result_string(self, result_string): # Sets the result string for the operation. self._result_string = result_string return self
[docs] def get_result_string(self): """ Returns the result string for the operation. This is None if the request was asynchronous or did not return an actual result. For example the "show" operations return a non-none result string, but "create, drop, grant, etc." operations return a none result string. :returns: the result string. :rtype: str """ return self._result_string
def set_statement(self, statement): # Sets the statement to use for the operation. self._statement = statement return self
[docs] def get_statement(self): """ Returns the statement used for the operation. :returns: the statement. :rtype: str """ return self._statement
def get_state(self): return self._state
[docs] def wait_for_completion(self, handle, wait_millis, delay_millis): """ Waits for the operation to be complete. This is a blocking, polling style wait that delays for the specified number of milliseconds between each polling operation. This instance is modified with any changes in state. :param handle: the NoSQLHandle to use. This is required. :type handle: NoSQLHandle :param wait_millis: the total amount of time to wait, in milliseconds. This value must be non-zero and greater than delay_millis. This is required. :type wait_millis: int :param delay_millis: the amount of time to wait between polling attempts, in milliseconds. If 0 it will default to 500. This is required. :type delay_millis: int :raises IllegalArgumentException: raises the exception if the operation times out or the parameters are not valid. """ if self._state == SystemState.COMPLETE: return default_delay = 500 delay_ms = delay_millis if delay_millis != 0 else default_delay if wait_millis < delay_millis: raise IllegalArgumentException( 'Wait milliseconds must be a minimum of ' + str(default_delay) + ' and greater than delay milliseconds.') start_time = int(round(time() * 1000)) delay_s = float(delay_ms) / 1000 system_status = SystemStatusRequest().set_operation_id( self._operation_id) res = None while True: cur_time = int(round(time() * 1000)) if cur_time - start_time > wait_millis: raise RequestTimeoutException( 'Operation not completed within timeout: ' + self._statement, wait_millis) if res is not None: # only delay after the first get_table. sleep(delay_s) res = handle.system_status(system_status) # do partial copy of new state. # statement and operation_id are not changed. self._result_string = res.get_result_string() self._state = res.get_operation_state() if self._state == SystemState.COMPLETE: break
[docs]class TableResult(Result): """ TableResult is returned from :py:meth:`NoSQLHandle.get_table` and :py:meth:`NoSQLHandle.table_request` operations. It encapsulates the state of the table that is the target of the request. Operations available in :py:meth:`NoSQLHandle.table_request` such as table creation, modification, and drop are asynchronous operations. When such an operation has been performed, it is necessary to call :py:meth:`NoSQLHandle.get_table` until the status of the table is State.ACTIVE, State.DROPPED or there is an error condition. The method :py:meth:`wait_for_completion` exists to perform this task and should be used to wait for an operation to complete. :py:meth:`NoSQLHandle.get_table` is synchronous, returning static information about the table as well as its current state. """ def __init__(self): super(TableResult, self).__init__() self._compartment_or_namespace = None self._table_name = None self._state = None self._limits = None self._schema = None self._operation_id = None self._ocid = None self._ddl = None self._defined_tags = None # dict(str, dict(str, object)) self._match_etag = None # str self._free_form_tags = None # dict(str, str) def __str__(self): tres = ('table name=' + str(self._table_name) + ', state=' + self._state) if self._limits is not None: tres += ', limits=' + str(self._limits) # only print one of DDL or schema, preferring DDL if self._ddl is not None: tres += ', ddl=' + str(self._ddl) elif self._schema is not None: tres += ', schema=[' + str(self._schema) + ']' if self._ocid is not None: tres += ', ocid=' + str(self._ocid) return tres def set_compartment_id(self, compartment_id): # Internal use only. self._compartment_or_namespace = compartment_id return self def set_namespace(self, namespace): # Internal use only. self._compartment_or_namespace = namespace return self def get_compartment_id(self): """ Cloud service only. Returns compartment id of the target table. :returns: compartment id. :rtype: str """ return self._compartment_or_namespace def get_namespace(self): """ On-premise service only. Returns the namespace of the table or null if it is not in a namespace. :returns: namespace :rtype: str """ return self._compartment_or_namespace def set_table_name(self, table_name): self._table_name = table_name return self
[docs] def get_table_name(self): """ Returns the table name of the target table. :returns: the table name. :rtype: str """ return self._table_name
def set_state(self, state): self._state = state return self
[docs] def get_state(self): """ Returns the table state. A table in state State.ACTIVE or State.UPDATING is usable for normal operation. :returns: the state. :rtype: State """ return self._state
def set_table_limits(self, limits): self._limits = limits return self
[docs] def get_table_limits(self): """ Returns the throughput and capacity limits for the table. Limits from an on-premise service will always be None. :returns: the limits. :rtype: TableLimits """ return self._limits
def set_schema(self, schema): self._schema = schema return self
[docs] def get_schema(self): """ Returns the schema for the table. :returns: the schema for the table. :rtype: str """ return self._schema
def set_operation_id(self, operation_id): self._operation_id = operation_id return self
[docs] def get_operation_id(self): """ Returns the operation id for an asynchronous operation. This is none if the request did not generate a new operation. The value can be used in :py:meth:`set_operation_id` to find potential errors resulting from the operation. :returns: the operation id for an asynchronous operation. :rtype: str """ return self._operation_id
def get_ddl(self): """ Returns the DDL (create table) statement used to create this table if available. If the table has been altered since initial creation the statement is also altered to reflect the current table schema. This value, when non-null, is functionally equivalent to the schema returned by :py:meth:`set_schema`. table. :returns: the ddl statement used to create the table :rtype: str :versionadded: 5.4.0 """ return self._ddl def get_table_id(self): """ Cloud service only. Returns the OCID of the table. This value will be null if used with the on-premise service. :returns: the table OCID :rtype: str :versionadded: 5.4.0 """ return self._ocid def get_match_etag(self): """ Cloud service only. :returns: the tag :rtype: str :versionadded: 5.4.0 """ return self._match_etag def get_defined_tags(self): """ Cloud service only. :returns: the tags :rtype: dict(str, dict(str, object)) :versionadded: 5.4.0 """ return self._defined_tags def get_free_form_tags(self): """ Cloud service only. :returns: the tags :rtype: dict(str, str) :versionadded: 5.4.0 """ return self._free_form_tags def set_ddl(self, value): self._ddl = value def set_table_id(self, value): self._ocid = value def set_match_etag(self, value): self._match_etag = value def set_defined_tags(self, value): self._defined_tags = value def set_free_form_tags(self, value): self._free_form_tags = value
[docs] def wait_for_completion(self, handle, wait_millis, delay_millis): """ Waits for a table operation to complete. Table operations are asynchronous. This is a blocking, polling style wait that delays for the specified number of milliseconds between each polling operation. This call returns when the table reaches a *terminal* state, which is either State.ACTIVE or State.DROPPED. This instance must be the return value of a previous :py:meth:`NoSQLHandle.table_request` and contain a non-none operation id representing the in-progress operation unless the operation has already completed. This instance is modified with any change in table state or metadata. :param handle: the NoSQLHandle to use. :type handle: NoSQLHandle :param wait_millis: the total amount of time to wait, in milliseconds. This value must be non-zero and greater than delay_millis. :type wait_millis: int :param delay_millis: the amount of time to wait between polling attempts, in milliseconds. If 0 it will default to 500. :type delay_millis: int :raises IllegalArgumentException: raises the exception if the parameters are not valid. :raises RequestTimeoutException: raises the exception if the operation times out. """ terminal = [State.ACTIVE, State.DROPPED] if self._state in terminal: return if self._operation_id is None: raise IllegalArgumentException('Operation id must not be none.') default_delay = 500 delay_ms = delay_millis if delay_millis != 0 else default_delay if wait_millis < delay_millis: raise IllegalArgumentException( 'Wait milliseconds must be a minimum of ' + str(default_delay) + ' and greater than delay milliseconds') start_time = int(round(time() * 1000)) delay_s = float(delay_ms) / 1000 get_table = GetTableRequest().set_table_name( self._table_name).set_operation_id( self._operation_id).set_compartment(self._compartment_or_namespace) res = None while True: cur_time = int(round(time() * 1000)) if cur_time - start_time > wait_millis: raise RequestTimeoutException( 'Operation not completed in expected time', wait_millis) if res is not None: # only delay after the first get_table. sleep(delay_s) res = handle.get_table(get_table) # partial "copy" of possibly modified state. Don't modify # operationId as that is what we are waiting to complete. self._state = res.get_state() self._limits = res.get_table_limits() self._schema = res.get_schema() if self._state in terminal: break
[docs]class TableUsageResult(Result): """ Cloud service only. TableUsageResult is returned from :py:meth:`NoSQLHandle.get_table_usage`. It encapsulates the dynamic state of the requested table. """ def __init__(self): super(TableUsageResult, self).__init__() self._last_index_returned = 0 self._table_name = None self._usage_records = None def __str__(self): if self._usage_records is None: records_str = 'None' else: records_str = '' for index in range(len(self._usage_records)): records_str += str(self._usage_records[index]) if index < len(self._usage_records) - 1: records_str += ', ' return ('TableUsageResult [table=' + str(self._table_name) + '] [table_usage=[' + records_str + ']]') def set_table_name(self, table_name): self._table_name = table_name return self
[docs] def get_table_name(self): """ Returns the table name used by the operation. :returns: the table name. :rtype: str """ return self._table_name
def set_usage_records(self, records): self._usage_records = records return self
[docs] def get_usage_records(self): """ Returns a list of usage records based on the parameters of the :py:class:`TableUsageRequest` used. :returns: an list of usage records. :type: list(TableUsage) """ return self._usage_records
def set_last_index_returned(self, last_index_returned): self._last_index_returned = last_index_returned return self def get_last_index_returned(self): """ Returns the index of the last usage record returned :returns: the index. :rtype: int """ return self._last_index_returned
[docs]class WriteMultipleResult(Result): """ Represents the result of a :py:meth:`NoSQLHandle.write_multiple` operation. If the WriteMultiple succeeds, the execution result of each sub operation can be retrieved using :py:meth:`get_results`. If the WriteMultiple operation is aborted because of the failure of an operation with abort_if_unsuccessful set to True, then the index of failed operation can be accessed using :py:meth:`get_failed_operation_index`, and the execution result of failed operation can be accessed using :py:meth:`get_failed_operation_result`. """ def __init__(self): super(WriteMultipleResult, self).__init__() self._results = list() self._failed_operation_index = -1 def __str__(self): if self.get_success(): return 'WriteMultiple, num results: ' + str(len(self._results)) return ('WriteMultiple aborted, the failed operation index: ' + str(self._failed_operation_index)) def add_result(self, result): self._results.append(result)
[docs] def get_results(self): """ Returns the list of execution results for the operations. :returns: the list of execution results. :rtype: list(OperationResult) """ return self._results
[docs] def get_failed_operation_result(self): """ Returns the result of the operation that results in the entire WriteMultiple operation aborting. :returns: the result of the operation, None if not set. :rtype: OperationResult or None """ if self._failed_operation_index == -1 or not self._results: return None return self._results[0]
def set_failed_operation_index(self, index): self._failed_operation_index = index
[docs] def get_failed_operation_index(self): """ Returns the index of failed operation that results in the entire WriteMultiple operation aborting. :returns: the index of operation, -1 if not set. :rtype: int """ return self._failed_operation_index
[docs] def get_success(self): """ Returns True if the WriteMultiple operation succeeded, or False if the operation is aborted due to the failure of a sub operation. The failed operation index can be accessed using :py:meth:`get_failed_operation_index` and its result can be accessed using :py:meth:`get_failed_operation_result`. :returns: True if the operation succeeded. :rtype: bool """ return self._failed_operation_index == -1
[docs] def size(self): """ Returns the number of results. :returns: the number of results. :rtype: int """ return len(self._results)
[docs] def get_read_kb(self): """ Returns the read throughput consumed by this operation, in KBytes. This is the actual amount of data read by the operation. The number of read units consumed is returned by :py:meth:`get_read_units` which may be a larger number because this was an update operation. :returns: the read KBytes consumed. :rtype: int """ return self._get_read_kb()
[docs] def get_read_units(self): """ Returns the read throughput consumed by this operation, in read units. This number may be larger than that returned by :py:meth:`get_read_kb` because it was an update operation. :returns: the read units consumed. :rtype: int """ return super(WriteMultipleResult, self).get_read_units()
[docs] def get_write_kb(self): """ Returns the write throughput consumed by this operation, in KBytes. :returns: the write KBytes consumed. :rtype: int """ return self._get_write_kb()
[docs] def get_write_units(self): """ Returns the write throughput consumed by this operation, in write units. :returns: the write units consumed. :rtype: int """ return super(WriteMultipleResult, self).get_write_units()
[docs]class OperationResult(WriteResult): """ A single Result associated with the execution of an individual operation in a :py:meth:`NoSQLHandle.write_multiple` request. A list of OperationResult is contained in :py:class:`WriteMultipleResult` and obtained using :py:meth:`WriteMultipleResult.get_results`. """ def __init__(self): super(OperationResult, self).__init__() self._version = None self._success = False self._generated_value = None def __str__(self): return ('Success: ' + str(self._success) + ', version: ' + str(self._version) + ', existing version: ' + str(self.get_existing_version()) + ', existing value: ' + str(self.get_existing_value()) + ', generated value: ' + str(self._generated_value)) def set_version(self, version): self._version = version return self
[docs] def get_version(self): """ Returns the version of the new row for put operation, or None if put operations did not succeed or the operation is delete operation. :returns: the version. :rtype: Version """ return self._version
def set_success(self, success): self._success = success return self
[docs] def get_success(self): """ Returns the flag indicates whether the operation succeeded. A put or delete operation may be unsuccessful if the condition is not matched. :returns: True if the operation succeeded. :rtype: bool """ return self._success
def set_generated_value(self, value): self._generated_value = value return self
[docs] def get_generated_value(self): """ Returns the value generated if the operation created a new value. This can happen if the table contains an identity column or string column declared as a generated UUID. If the table has no such columns this value is None. If a value was generated for the operation, it is non-None. This value is only valid for a put operation on a table with an identity column or string as uuid column. :returns: the generated value. """ return self._generated_value
[docs] def get_existing_version(self): """ Returns the existing row version associated with the key if available. :returns: the existing row version :rtype: Version """ return self._get_existing_version()
[docs] def get_existing_value(self): """ Returns the previous row value associated with the key if available. :returns: the previous row value :rtype: dict """ return self._get_existing_value()
[docs] def get_existing_modification_time(self): """ Returns the existing row modification time if available. :returns: the modification time in milliseconds since January 1, 1970 :rtype: int :versionadded: 5.3.0 """ return self._get_existing_modification_time()
class RetryStats(object): """ A class that maintains stats on retries during a request. This object tracks statistics about retries performed during requests. It can be accessed from within retry handlers (see :py:class:`RetryHandler`) or after a request is finished by calling :py:meth:`Request.get_retry_stats`. """ def __init__(self): self._delay_ms = 0 self._exception_map = dict() self._retries = 0 def __str__(self): return ('retries=' + str(self._retries) + ', delay_ms=' + str(self._delay_ms) + ', exception_map=' + str(self._exception_map)) def add_delay_ms(self, delay_ms): """ Internal use only. Adds time to the overall delay time spent. :param delay_ms: the number of milliseconds to add to the delay total. :type delay_ms: int """ self._delay_ms += delay_ms def add_exception(self, e): """ Internal use only. Adds an exception class to the stats object. This increments the exception count and adds to the count of this type of exception class. :param e: the exception class. :type e: Exception """ num = self.get_num_exceptions(e) + 1 self._exception_map[e] = num def get_exceptions_map(self): """ Internal use only. Returns the map of exceptions. :versionadded: 5.3.6 """ return self._exception_map def add_exceptions(self, ex_map): """ Internal use only. Adds all exceptions to the stats object. This increments the exception count and adds to the count of this type of exception class. :param ex_map: the exceptions map. :type ex_map: dict[Exception, int] :versionadded: 5.3.6 """ for k in ex_map.keys(): num = self.get_num_exceptions(k) + ex_map[k] self._exception_map[k] = num def clear(self): """ Internal use only. Clears the stats object. """ self._delay_ms = 0 self._exception_map.clear() self._retries = 0 def get_delay_ms(self): """ Returns the total time delayed (slept) between retry events. :returns: the time delayed during retries, in milliseconds. This is only the time spent locally in sleep() between retry events. :rtype: int """ return self._delay_ms def get_num_exceptions(self, e): """ Returns the number of exceptions of a particular class. If no exceptions of this class were added to this stats object, the return value is zero. :param e: the class of exception to query. :type e: Exception :returns: the number of exceptions of this class :rtype: int """ num = self._exception_map.get(e) if num is None: return 0 return num def get_retries(self): """ Returns the number of retry events. :returns: number of retry events. :rtype: int """ return self._retries def increment_retries(self, n=1): # type: (int) -> None """ Internal use only. Increments the number of retries. """ self._retries += n