def list_instances(self, filter_="", page_size=None, page_token=None): """List instances for the client's project. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.InstanceAdmin.ListInstances :type filter_: string :param filter_: (Optional) Filter to select instances listed. See the ``ListInstancesRequest`` docs above for examples. :type page_size: int :param page_size: (Optional) Maximum number of results to return. :type page_token: str :param page_token: (Optional) Token for fetching next page of results. :rtype: :class:`~google.api_core.page_iterator.Iterator` :returns: Iterator of :class:`~google.cloud.spanner_v1.instance.Instance` resources within the client's project. """ metadata = _metadata_with_prefix(self.project_name) path = "projects/%s" % (self.project,) page_iter = self.instance_admin_api.list_instances( path, page_size=page_size, metadata=metadata ) page_iter.item_to_value = self._item_to_instance page_iter.next_page_token = page_token return page_iter
def create(self): """Create this database within its instance Inclues any configured schema assigned to :attr:`ddl_statements`. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.CreateDatabase :rtype: :class:`~google.api_core.operation.Operation` :returns: a future used to poll the status of the create request :raises Conflict: if the database already exists :raises NotFound: if the instance owning the database does not exist """ api = self._instance._client.database_admin_api metadata = _metadata_with_prefix(self.name) db_name = self.database_id if "-" in db_name: db_name = "`%s`" % (db_name,) future = api.create_database( parent=self._instance.name, create_statement="CREATE DATABASE %s" % (db_name,), extra_statements=list(self._ddl_statements), metadata=metadata, ) return future
def begin(self): """Begin a read-only transaction on the database. :rtype: bytes :returns: the ID for the newly-begun transaction. :raises ValueError: if the transaction is already begun, committed, or rolled back. """ if not self._multi_use: raise ValueError("Cannot call 'begin' on single-use snapshots") if self._transaction_id is not None: raise ValueError("Read-only transaction already begun") if self._read_request_count > 0: raise ValueError("Read-only transaction already pending") database = self._session._database api = database.spanner_api metadata = _metadata_with_prefix(database.name) txn_selector = self._make_txn_selector() response = api.begin_transaction( self._session.name, txn_selector.begin, metadata=metadata ) self._transaction_id = response.id return self._transaction_id
def begin(self): """Begin a transaction on the database. :rtype: bytes :returns: the ID for the newly-begun transaction. :raises ValueError: if the transaction is already begun, committed, or rolled back. """ if self._transaction_id is not None: raise ValueError("Transaction already begun") if self.committed is not None: raise ValueError("Transaction already committed") if self._rolled_back: raise ValueError("Transaction is already rolled back") database = self._session._database api = database.spanner_api metadata = _metadata_with_prefix(database.name) txn_options = TransactionOptions(read_write=TransactionOptions.ReadWrite()) response = api.begin_transaction( self._session.name, txn_options, metadata=metadata ) self._transaction_id = response.id return self._transaction_id
def list_instance_configs(self, page_size=None, page_token=None): """List available instance configurations for the client's project. .. _RPC docs: https://cloud.google.com/spanner/docs/reference/rpc/\ google.spanner.admin.instance.v1#google.spanner.admin.\ instance.v1.InstanceAdmin.ListInstanceConfigs See `RPC docs`_. :type page_size: int :param page_size: (Optional) Maximum number of results to return. :type page_token: str :param page_token: (Optional) Token for fetching next page of results. :rtype: :class:`~google.api_core.page_iterator.Iterator` :returns: Iterator of :class:`~google.cloud.spanner_v1.instance.InstanceConfig` resources within the client's project. """ metadata = _metadata_with_prefix(self.project_name) path = "projects/%s" % (self.project,) page_iter = self.instance_admin_api.list_instance_configs( path, page_size=page_size, metadata=metadata ) page_iter.next_page_token = page_token page_iter.item_to_value = _item_to_instance_config return page_iter
def update_ddl(self, ddl_statements, operation_id=""): """Update DDL for this database. Apply any configured schema from :attr:`ddl_statements`. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabase :type ddl_statements: Sequence[str] :param ddl_statements: a list of DDL statements to use on this database :type operation_id: str :param operation_id: (optional) a string ID for the long-running operation :rtype: :class:`google.api_core.operation.Operation` :returns: an operation instance :raises NotFound: if the database does not exist """ client = self._instance._client api = client.database_admin_api metadata = _metadata_with_prefix(self.name) future = api.update_database_ddl( self.name, ddl_statements, operation_id=operation_id, metadata=metadata ) return future
def list_databases(self, page_size=None, page_token=None): """List databases for the instance. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.ListDatabases :type page_size: int :param page_size: Optional. The maximum number of databases in each page of results from this request. Non-positive values are ignored. Defaults to a sensible value set by the API. :type page_token: str :param page_token: Optional. If present, return the next batch of databases, using the value, which must correspond to the ``nextPageToken`` value returned in the previous response. Deprecated: use the ``pages`` property of the returned iterator instead of manually passing the token. :rtype: :class:`~google.api._ore.page_iterator.Iterator` :returns: Iterator of :class:`~google.cloud.spanner_v1.database.Database` resources within the current instance. """ metadata = _metadata_with_prefix(self.name) page_iter = self._client.database_admin_api.list_databases( self.name, page_size=page_size, metadata=metadata ) page_iter.next_page_token = page_token page_iter.item_to_value = self._item_to_database return page_iter
def rollback(self): """Roll back a transaction on the database.""" self._check_state() database = self._session._database api = database.spanner_api metadata = _metadata_with_prefix(database.name) api.rollback(self._session.name, self._transaction_id, metadata=metadata) self._rolled_back = True del self._session._transaction
def execute_partitioned_dml(self, dml, params=None, param_types=None): """Execute a partitionable DML statement. :type dml: str :param dml: DML statement :type params: dict, {str -> column value} :param params: values for parameter replacement. Keys must match the names used in ``dml``. :type param_types: dict[str -> Union[dict, .types.Type]] :param param_types: (Optional) maps explicit types for one or more param values; required if parameters are passed. :rtype: int :returns: Count of rows affected by the DML statement. """ if params is not None: if param_types is None: raise ValueError("Specify 'param_types' when passing 'params'.") params_pb = Struct( fields={key: _make_value_pb(value) for key, value in params.items()} ) else: params_pb = None api = self.spanner_api txn_options = TransactionOptions( partitioned_dml=TransactionOptions.PartitionedDml() ) metadata = _metadata_with_prefix(self.name) with SessionCheckout(self._pool) as session: txn = api.begin_transaction(session.name, txn_options, metadata=metadata) txn_selector = TransactionSelector(id=txn.id) restart = functools.partial( api.execute_streaming_sql, session.name, dml, transaction=txn_selector, params=params_pb, param_types=param_types, metadata=metadata, ) iterator = _restart_on_unavailable(restart) result_set = StreamedResultSet(iterator) list(result_set) # consume all partials return result_set.stats.row_count_lower_bound
def read(self, table, columns, keyset, index='', limit=0, partition=None): """Perform a ``StreamingRead`` API request for rows in a table. :type table: str :param table: name of the table from which to fetch data :type columns: list of str :param columns: names of columns to be retrieved :type keyset: :class:`~google.cloud.spanner_v1.keyset.KeySet` :param keyset: keys / ranges identifying rows to be retrieved :type index: str :param index: (Optional) name of index to use, rather than the table's primary key :type limit: int :param limit: (Optional) maximum number of rows to return. Incompatible with ``partition``. :type partition: bytes :param partition: (Optional) one of the partition tokens returned from :meth:`partition_read`. Incompatible with ``limit``. :rtype: :class:`~google.cloud.spanner_v1.streamed.StreamedResultSet` :returns: a result set instance which can be used to consume rows. :raises ValueError: for reuse of single-use snapshots, or if a transaction ID is already pending for multiple-use snapshots. """ if self._read_request_count > 0: if not self._multi_use: raise ValueError("Cannot re-use single-use snapshot.") if self._transaction_id is None: raise ValueError("Transaction ID pending.") database = self._session._database api = database.spanner_api metadata = _metadata_with_prefix(database.name) transaction = self._make_txn_selector() restart = functools.partial( api.streaming_read, self._session.name, table, columns, keyset._to_pb(), transaction=transaction, index=index, limit=limit, partition_token=partition, metadata=metadata) iterator = _restart_on_unavailable(restart) self._read_request_count += 1 if self._multi_use: return StreamedResultSet(iterator, source=self) else: return StreamedResultSet(iterator)
def drop(self): """Drop this database. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.DropDatabase """ api = self._instance._client.database_admin_api metadata = _metadata_with_prefix(self.name) api.drop_database(self.name, metadata=metadata)
def batch_update(self, statements): """Perform a batch of DML statements via an ``ExecuteBatchDml`` request. :type statements: Sequence[Union[ str, Tuple[str, Dict[str, Any], Dict[str, Union[dict, .types.Type]]]]] :param statements: List of DML statements, with optional params / param types. If passed, 'params' is a dict mapping names to the values for parameter replacement. Keys must match the names used in the corresponding DML statement. If 'params' is passed, 'param_types' must also be passed, as a dict mapping names to the type of value passed in 'params'. :rtype: Tuple(status, Sequence[int]) :returns: Status code, plus counts of rows affected by each completed DML statement. Note that if the staus code is not ``OK``, the statement triggering the error will not have an entry in the list, nor will any statements following that one. """ parsed = [] for statement in statements: if isinstance(statement, str): parsed.append({"sql": statement}) else: dml, params, param_types = statement params_pb = self._make_params_pb(params, param_types) parsed.append( {"sql": dml, "params": params_pb, "param_types": param_types} ) database = self._session._database metadata = _metadata_with_prefix(database.name) transaction = self._make_txn_selector() api = database.spanner_api response = api.execute_batch_dml( session=self._session.name, transaction=transaction, statements=parsed, seqno=self._execute_sql_count, metadata=metadata, ) self._execute_sql_count += 1 row_counts = [ result_set.stats.row_count_exact for result_set in response.result_sets ] return response.status, row_counts
def reload(self): """Reload the metadata for this instance. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.GetInstanceConfig :raises NotFound: if the instance does not exist """ api = self._client.instance_admin_api metadata = _metadata_with_prefix(self.name) instance_pb = api.get_instance(self.name, metadata=metadata) self._update_from_pb(instance_pb)
def create(self): """Create this session, bound to its database. See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.CreateSession :raises: :exc:`ValueError` if :attr:`session_id` is already set. """ if self._session_id is not None: raise ValueError('Session ID already set by back-end') api = self._database.spanner_api metadata = _metadata_with_prefix(self._database.name) session_pb = api.create_session(self._database.name, metadata=metadata) self._session_id = session_pb.name.split('/')[-1]
def read(self, table, columns, keyset, index='', limit=0): """Perform a ``StreamingRead`` API request for rows in a table. :type table: str :param table: name of the table from which to fetch data :type columns: list of str :param columns: names of columns to be retrieved :type keyset: :class:`~google.cloud.spanner_v1.keyset.KeySet` :param keyset: keys / ranges identifying rows to be retrieved :type index: str :param index: (Optional) name of index to use, rather than the table's primary key :type limit: int :param limit: (Optional) maximum number of rows to return :rtype: :class:`~google.cloud.spanner_v1.streamed.StreamedResultSet` :returns: a result set instance which can be used to consume rows. :raises ValueError: for reuse of single-use snapshots, or if a transaction ID is already pending for multiple-use snapshots. """ if self._read_request_count > 0: if not self._multi_use: raise ValueError("Cannot re-use single-use snapshot.") if self._transaction_id is None: raise ValueError("Transaction ID pending.") database = self._session._database api = database.spanner_api metadata = _metadata_with_prefix(database.name) transaction = self._make_txn_selector() restart = functools.partial( api.streaming_read, self._session.name, table, columns, keyset.to_pb(), transaction=transaction, index=index, limit=limit, metadata=metadata) iterator = _restart_on_unavailable(restart) self._read_request_count += 1 if self._multi_use: return StreamedResultSet(iterator, source=self) else: return StreamedResultSet(iterator)
def execute_update(self, dml, params=None, param_types=None, query_mode=None): """Perform an ``ExecuteSql`` API request with DML. :type dml: str :param dml: SQL DML statement :type params: dict, {str -> column value} :param params: values for parameter replacement. Keys must match the names used in ``dml``. :type param_types: dict[str -> Union[dict, .types.Type]] :param param_types: (Optional) maps explicit types for one or more param values; required if parameters are passed. :type query_mode: :class:`google.cloud.spanner_v1.proto.ExecuteSqlRequest.QueryMode` :param query_mode: Mode governing return of results / query plan. See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.ExecuteSqlRequest.QueryMode1 :rtype: int :returns: Count of rows affected by the DML statement. """ if params is not None: if param_types is None: raise ValueError("Specify 'param_types' when passing 'params'.") params_pb = Struct( fields={key: _make_value_pb(value) for key, value in params.items()} ) else: params_pb = None database = self._session._database metadata = _metadata_with_prefix(database.name) transaction = self._make_txn_selector() api = database.spanner_api response = api.execute_sql( self._session.name, dml, transaction=transaction, params=params_pb, param_types=param_types, query_mode=query_mode, seqno=self._execute_sql_count, metadata=metadata, ) self._execute_sql_count += 1 return response.stats.row_count_exact
def reload(self): """Reload this database. Refresh any configured schema into :attr:`ddl_statements`. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.GetDatabaseDDL :raises NotFound: if the database does not exist """ api = self._instance._client.database_admin_api metadata = _metadata_with_prefix(self.name) response = api.get_database_ddl(self.name, metadata=metadata) self._ddl_statements = tuple(response.statements)
def commit(self, return_commit_stats=False, request_options=None): """Commit mutations to the database. :type return_commit_stats: bool :param return_commit_stats: If true, the response will return commit stats which can be accessed though commit_stats. :type request_options: :class:`google.cloud.spanner_v1.types.RequestOptions` :param request_options: (Optional) Common options for this request. If a dict is provided, it must be of the same form as the protobuf message :class:`~google.cloud.spanner_v1.types.RequestOptions`. :rtype: datetime :returns: timestamp of the committed changes. """ self._check_state() database = self._session._database api = database.spanner_api metadata = _metadata_with_prefix(database.name) txn_options = TransactionOptions( read_write=TransactionOptions.ReadWrite()) trace_attributes = {"num_mutations": len(self._mutations)} if request_options is None: request_options = RequestOptions() elif type(request_options) == dict: request_options = RequestOptions(request_options) request_options.transaction_tag = self.transaction_tag # Request tags are not supported for commit requests. request_options.request_tag = None request = CommitRequest( session=self._session.name, mutations=self._mutations, single_use_transaction=txn_options, return_commit_stats=return_commit_stats, request_options=request_options, ) with trace_call("CloudSpanner.Commit", self._session, trace_attributes): response = api.commit( request=request, metadata=metadata, ) self.committed = response.commit_timestamp self.commit_stats = response.commit_stats return self.committed
def reload(self): """Reload this database. Refresh any configured schema into :attr:`ddl_statements`. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.GetDatabaseDDL :raises NotFound: if the database does not exist """ api = self._instance._client.database_admin_api metadata = _metadata_with_prefix(self.name) response = api.get_database_ddl(self.name, metadata=metadata) self._ddl_statements = tuple(response.statements)
def exists(self): """Test whether this backup exists. :rtype: bool :returns: True if the backup exists, else False. """ api = self._instance._client.database_admin_api metadata = _metadata_with_prefix(self.name) try: api.get_backup(name=self.name, metadata=metadata) except NotFound: return False return True
def reload(self): """Reload the metadata for this instance. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.GetInstanceConfig :raises NotFound: if the instance does not exist """ api = self._client.instance_admin_api metadata = _metadata_with_prefix(self.name) instance_pb = api.get_instance(self.name, metadata=metadata) self._update_from_pb(instance_pb)
def rollback(self): """Roll back a transaction on the database.""" self._check_state() database = self._session._database api = database.spanner_api metadata = _metadata_with_prefix(database.name) with trace_call("CloudSpanner.Rollback", self._session): api.rollback( session=self._session.name, transaction_id=self._transaction_id, metadata=metadata, ) self.rolled_back = True del self._session._transaction
def delete(self): """Delete this session. See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.GetSession :raises ValueError: if :attr:`session_id` is not already set. :raises NotFound: if the session does not exist """ if self._session_id is None: raise ValueError('Session ID not set by back-end') api = self._database.spanner_api metadata = _metadata_with_prefix(self._database.name) api.delete_session(self.name, metadata=metadata)
def delete(self): """Delete this session. See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.GetSession :raises ValueError: if :attr:`session_id` is not already set. :raises NotFound: if the session does not exist """ if self._session_id is None: raise ValueError('Session ID not set by back-end') api = self._database.spanner_api metadata = _metadata_with_prefix(self._database.name) api.delete_session(self.name, metadata=metadata)
def update_expire_time(self, new_expire_time): """Update the expire time of this backup. :type new_expire_time: :class:`datetime.datetime` :param new_expire_time: the new expire time timestamp """ api = self._instance._client.database_admin_api metadata = _metadata_with_prefix(self.name) backup_update = { "name": self.name, "expire_time": _datetime_to_pb_timestamp(new_expire_time), } update_mask = {"paths": ["expire_time"]} api.update_backup(backup_update, update_mask, metadata=metadata) self._expire_time = new_expire_time
def reload(self): """Reload this backup. Refresh the stored backup properties. :raises NotFound: if the backup does not exist """ api = self._instance._client.database_admin_api metadata = _metadata_with_prefix(self.name) pb = api.get_backup(self.name, metadata=metadata) self._database = pb.database self._expire_time = _pb_timestamp_to_datetime(pb.expire_time) self._create_time = _pb_timestamp_to_datetime(pb.create_time) self._size_bytes = pb.size_bytes self._state = enums.Backup.State(pb.state) self._referencing_databases = pb.referencing_databases
def execute_update(self, dml, params=None, param_types=None, query_mode=None): """Perform an ``ExecuteSql`` API request with DML. :type dml: str :param dml: SQL DML statement :type params: dict, {str -> column value} :param params: values for parameter replacement. Keys must match the names used in ``dml``. :type param_types: dict[str -> Union[dict, .types.Type]] :param param_types: (Optional) maps explicit types for one or more param values; required if parameters are passed. :type query_mode: :class:`google.cloud.spanner_v1.proto.ExecuteSqlRequest.QueryMode` :param query_mode: Mode governing return of results / query plan. See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.ExecuteSqlRequest.QueryMode1 :rtype: int :returns: Count of rows affected by the DML statement. """ params_pb = self._make_params_pb(params, param_types) database = self._session._database metadata = _metadata_with_prefix(database.name) transaction = self._make_txn_selector() api = database.spanner_api response = api.execute_sql( self._session.name, dml, transaction=transaction, params=params_pb, param_types=param_types, query_mode=query_mode, seqno=self._execute_sql_count, metadata=metadata, ) self._execute_sql_count += 1 return response.stats.row_count_exact
def exists(self): """Test whether this database exists. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.GetDatabaseDDL :rtype: bool :returns: True if the database exists, else false. """ api = self._instance._client.database_admin_api metadata = _metadata_with_prefix(self.name) try: api.get_database_ddl(self.name, metadata=metadata) except NotFound: return False return True
def exists(self): """Test whether this database exists. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.GetDatabaseDDL :rtype: bool :returns: True if the database exists, else false. """ api = self._instance._client.database_admin_api metadata = _metadata_with_prefix(self.name) try: api.get_database_ddl(self.name, metadata=metadata) except NotFound: return False return True
def create(self): """Create this session, bound to its database. See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.CreateSession :raises: :exc:`ValueError` if :attr:`session_id` is already set. """ if self._session_id is not None: raise ValueError("Session ID already set by back-end") api = self._database.spanner_api metadata = _metadata_with_prefix(self._database.name) kw = {} if self._labels: kw = {"session": {"labels": self._labels}} session_pb = api.create_session(self._database.name, metadata=metadata, **kw) self._session_id = session_pb.name.split("/")[-1]
def exists(self): """Test whether this instance exists. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.GetInstanceConfig :rtype: bool :returns: True if the instance exists, else false """ api = self._client.instance_admin_api metadata = _metadata_with_prefix(self.name) try: api.get_instance(self.name, metadata=metadata) except NotFound: return False return True
def exists(self): """Test whether this instance exists. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.GetInstanceConfig :rtype: bool :returns: True if the instance exists, else false """ api = self._client.instance_admin_api metadata = _metadata_with_prefix(self.name) try: api.get_instance(self.name, metadata=metadata) except NotFound: return False return True
def commit(self): """Commit mutations to the database. :rtype: datetime :returns: timestamp of the committed changes. """ self._check_state() database = self._session._database api = database.spanner_api metadata = _metadata_with_prefix(database.name) txn_options = TransactionOptions( read_write=TransactionOptions.ReadWrite()) response = api.commit(self._session.name, self._mutations, single_use_transaction=txn_options, metadata=metadata) self.committed = _pb_timestamp_to_datetime( response.commit_timestamp) return self.committed
def commit(self): """Commit mutations to the database. :rtype: datetime :returns: timestamp of the committed changes. :raises ValueError: if there are no mutations to commit. """ self._check_state() database = self._session._database api = database.spanner_api metadata = _metadata_with_prefix(database.name) response = api.commit(self._session.name, self._mutations, transaction_id=self._transaction_id, metadata=metadata) self.committed = _pb_timestamp_to_datetime(response.commit_timestamp) del self._session._transaction return self.committed
def delete(self): """Mark an instance and all of its databases for permanent deletion. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.DeleteInstance Immediately upon completion of the request: * Billing will cease for all of the instance's reserved resources. Soon afterward: * The instance and all databases within the instance will be deleteed. All data in the databases will be permanently deleted. """ api = self._client.instance_admin_api metadata = _metadata_with_prefix(self.name) api.delete_instance(self.name, metadata=metadata)
def exists(self): """Test for the existence of this session. See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.GetSession :rtype: bool :returns: True if the session exists on the back-end, else False. """ if self._session_id is None: return False api = self._database.spanner_api metadata = _metadata_with_prefix(self._database.name) try: api.get_session(self.name, metadata=metadata) except NotFound: return False return True
def delete(self): """Mark an instance and all of its databases for permanent deletion. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.DeleteInstance Immediately upon completion of the request: * Billing will cease for all of the instance's reserved resources. Soon afterward: * The instance and all databases within the instance will be deleteed. All data in the databases will be permanently deleted. """ api = self._client.instance_admin_api metadata = _metadata_with_prefix(self.name) api.delete_instance(self.name, metadata=metadata)
def bind(self, database): """Associate the pool with a database. :type database: :class:`~google.cloud.spanner_v1.database.Database` :param database: database used by the pool: used to create sessions when needed. """ self._database = database api = database.spanner_api metadata = _metadata_with_prefix(database.name) while not self._sessions.full(): resp = api.batch_create_sessions( database.name, self.size - self._sessions.qsize(), metadata=metadata ) for session_pb in resp.session: session = self._new_session() session._session_id = session_pb.name.split("/")[-1] self._sessions.put(session)
def update(self): """Update this instance. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.UpdateInstance .. note:: Updates the ``display_name``, ``node_count``, ``processing_units`` and ``labels``. To change those values before updating, set them via .. code:: python instance.display_name = 'New display name' instance.node_count = 5 before calling :meth:`update`. :rtype: :class:`google.api_core.operation.Operation` :returns: an operation instance :raises NotFound: if the instance does not exist """ api = self._client.instance_admin_api instance_pb = InstancePB( name=self.name, config=self.configuration_name, display_name=self.display_name, node_count=self._node_count, processing_units=self._processing_units, labels=self.labels, ) # Always update only processing_units, not nodes field_mask = FieldMask( paths=["config", "display_name", "processing_units", "labels"] ) metadata = _metadata_with_prefix(self.name) future = api.update_instance( instance=instance_pb, field_mask=field_mask, metadata=metadata ) return future
def exists(self): """Test for the existence of this session. See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.GetSession :rtype: bool :returns: True if the session exists on the back-end, else False. """ if self._session_id is None: return False api = self._database.spanner_api metadata = _metadata_with_prefix(self._database.name) try: api.get_session(self.name, metadata=metadata) except NotFound: return False return True
def spanner_api(self): """Helper for session-related API calls.""" if self._spanner_api is None: credentials = self._instance._client.credentials if isinstance(credentials, google.auth.credentials.Scoped): credentials = credentials.with_scopes((SPANNER_DATA_SCOPE, )) client_info = self._instance._client._client_info client_options = self._instance._client._client_options if (os.getenv("GOOGLE_CLOUD_SPANNER_ENABLE_RESOURCE_BASED_ROUTING") == "true"): endpoint_cache = self._instance._client._endpoint_cache if self._instance.name in endpoint_cache: client_options = ClientOptions( api_endpoint=endpoint_cache[self._instance.name]) else: try: api = self._instance._client.instance_admin_api resp = api.get_instance( self._instance.name, field_mask={"paths": ["endpoint_uris"]}, metadata=_metadata_with_prefix(self.name), ) endpoints = resp.endpoint_uris if endpoints: endpoint_cache[self._instance.name] = list( endpoints)[0] client_options = ClientOptions( api_endpoint=endpoint_cache[ self._instance.name]) # If there are no endpoints, use default endpoint. except PermissionDenied: warnings.warn( _RESOURCE_ROUTING_PERMISSIONS_WARNING, ResourceRoutingPermissionsWarning, stacklevel=2, ) self._spanner_api = SpannerClient( credentials=credentials, client_info=client_info, client_options=client_options, ) return self._spanner_api
def reload(self): """Reload this database. Refresh any configured schema into :attr:`ddl_statements`. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.GetDatabaseDDL :raises NotFound: if the database does not exist """ api = self._instance._client.database_admin_api metadata = _metadata_with_prefix(self.name) response = api.get_database_ddl(database=self.name, metadata=metadata) self._ddl_statements = tuple(response.statements) response = api.get_database(name=self.name, metadata=metadata) self._state = DatabasePB.State(response.state) self._create_time = response.create_time self._restore_info = response.restore_info self._version_retention_period = response.version_retention_period self._earliest_version_time = response.earliest_version_time
def reload(self): """Reload this backup. Refresh the stored backup properties. :raises NotFound: if the backup does not exist """ api = self._instance._client.database_admin_api metadata = _metadata_with_prefix(self.name) pb = api.get_backup(name=self.name, metadata=metadata) self._database = pb.database self._expire_time = pb.expire_time self._create_time = pb.create_time self._version_time = pb.version_time self._size_bytes = pb.size_bytes self._state = BackupPB.State(pb.state) self._referencing_databases = pb.referencing_databases self._encryption_info = pb.encryption_info self._max_expire_time = pb.max_expire_time self._referencing_backups = pb.referencing_backups
def create(self): """Create this instance. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.CreateInstance .. note:: Uses the ``project`` and ``instance_id`` on the current :class:`Instance` in addition to the ``display_name``. To change them before creating, reset the values via .. code:: python instance.display_name = 'New display name' instance.instance_id = 'i-changed-my-mind' before calling :meth:`create`. :rtype: :class:`~google.api_core.operation.Operation` :returns: an operation instance :raises Conflict: if the instance already exists """ api = self._client.instance_admin_api instance_pb = InstancePB( name=self.name, config=self.configuration_name, display_name=self.display_name, node_count=self.node_count, labels=self.labels, ) metadata = _metadata_with_prefix(self.name) future = api.create_instance( parent=self._client.project_name, instance_id=self.instance_id, instance=instance_pb, metadata=metadata, ) return future
def commit(self): """Commit mutations to the database. :rtype: datetime :returns: timestamp of the committed changes. """ self._check_state() database = self._session._database api = database.spanner_api metadata = _metadata_with_prefix(database.name) txn_options = TransactionOptions(read_write=TransactionOptions.ReadWrite()) trace_attributes = {"num_mutations": len(self._mutations)} with trace_call("CloudSpanner.Commit", self._session, trace_attributes): response = api.commit( session=self._session.name, mutations=self._mutations, single_use_transaction=txn_options, metadata=metadata, ) self.committed = response.commit_timestamp return self.committed
def commit(self): """Commit mutations to the database. :rtype: datetime :returns: timestamp of the committed changes. :raises ValueError: if there are no mutations to commit. """ self._check_state() database = self._session._database api = database.spanner_api metadata = _metadata_with_prefix(database.name) response = api.commit( self._session.name, self._mutations, transaction_id=self._transaction_id, metadata=metadata, ) self.committed = _pb_timestamp_to_datetime(response.commit_timestamp) del self._session._transaction return self.committed
def update_ddl(self, ddl_statements): """Update DDL for this database. Apply any configured schema from :attr:`ddl_statements`. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabase :rtype: :class:`google.api_core.operation.Operation` :returns: an operation instance :raises NotFound: if the database does not exist """ client = self._instance._client api = client.database_admin_api metadata = _metadata_with_prefix(self.name) future = api.update_database_ddl(self.name, ddl_statements, '', metadata=metadata) return future
def create(self): """Create this session, bound to its database. See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.CreateSession :raises ValueError: if :attr:`session_id` is already set. """ if self._session_id is not None: raise ValueError("Session ID already set by back-end") api = self._database.spanner_api metadata = _metadata_with_prefix(self._database.name) request = CreateSessionRequest(database=self._database.name) if self._labels: request.session.labels = self._labels with trace_call("CloudSpanner.CreateSession", self, self._labels): session_pb = api.create_session(request=request, metadata=metadata,) self._session_id = session_pb.name.split("/")[-1]
def create(self): """Create this backup within its instance. :rtype: :class:`~google.api_core.operation.Operation` :returns: a future used to poll the status of the create request :raises Conflict: if the backup already exists :raises NotFound: if the instance owning the backup does not exist :raises BadRequest: if the database or expire_time values are invalid or expire_time is not set """ if not self._expire_time: raise ValueError("expire_time not set") if not self._database: raise ValueError("database not set") if (self.encryption_config and self.encryption_config.kms_key_name and self.encryption_config.encryption_type != CreateBackupEncryptionConfig.EncryptionType. CUSTOMER_MANAGED_ENCRYPTION): raise ValueError( "kms_key_name only used with CUSTOMER_MANAGED_ENCRYPTION") api = self._instance._client.database_admin_api metadata = _metadata_with_prefix(self.name) backup = BackupPB( database=self._database, expire_time=self.expire_time, version_time=self.version_time, ) request = CreateBackupRequest( parent=self._instance.name, backup_id=self.backup_id, backup=backup, encryption_config=self._encryption_config, ) future = api.create_backup( request=request, metadata=metadata, ) return future
def create(self): """Create this instance. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.CreateInstance .. note:: Uses the ``project`` and ``instance_id`` on the current :class:`Instance` in addition to the ``display_name``. To change them before creating, reset the values via .. code:: python instance.display_name = 'New display name' instance.instance_id = 'i-changed-my-mind' before calling :meth:`create`. :rtype: :class:`google.api_core.operation.Operation` :returns: an operation instance :raises Conflict: if the instance already exists """ api = self._client.instance_admin_api instance_pb = admin_v1_pb2.Instance( name=self.name, config=self.configuration_name, display_name=self.display_name, node_count=self.node_count, ) metadata = _metadata_with_prefix(self.name) future = api.create_instance( parent=self._client.project_name, instance_id=self.instance_id, instance=instance_pb, metadata=metadata, ) return future
def list_databases(self, page_size=None): """List databases for the instance. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.ListDatabases :type page_size: int :param page_size: Optional. The maximum number of databases in each page of results from this request. Non-positive values are ignored. Defaults to a sensible value set by the API. :rtype: :class:`~google.api._ore.page_iterator.Iterator` :returns: Iterator of :class:`~google.cloud.spanner_v1.database.Database` resources within the current instance. """ metadata = _metadata_with_prefix(self.name) request = ListDatabasesRequest(parent=self.name, page_size=page_size) page_iter = self._client.database_admin_api.list_databases( request=request, metadata=metadata) return page_iter
def update(self): """Update this instance. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.UpdateInstance .. note:: Updates the ``display_name`` and ``node_count``. To change those values before updating, set them via .. code:: python instance.display_name = 'New display name' instance.node_count = 5 before calling :meth:`update`. :rtype: :class:`google.api_core.operation.Operation` :returns: an operation instance :raises NotFound: if the instance does not exist """ api = self._client.instance_admin_api instance_pb = admin_v1_pb2.Instance( name=self.name, config=self.configuration_name, display_name=self.display_name, node_count=self.node_count, ) field_mask = FieldMask(paths=['config', 'display_name', 'node_count']) metadata = _metadata_with_prefix(self.name) future = api.update_instance( instance=instance_pb, field_mask=field_mask, metadata=metadata, ) return future
def restore(self, source): """Restore from a backup to this database. :type source: :class:`~google.cloud.spanner_v1.backup.Backup` :param source: the path of the source being restored from. :rtype: :class:`~google.api_core.operation.Operation` :returns: a future used to poll the status of the create request :raises Conflict: if the database already exists :raises NotFound: if the instance owning the database does not exist, or if the backup being restored from does not exist :raises ValueError: if backup is not set """ if source is None: raise ValueError("Restore source not specified") if type(self._encryption_config) == dict: self._encryption_config = RestoreDatabaseEncryptionConfig( **self._encryption_config) if (self.encryption_config and self.encryption_config.kms_key_name and self.encryption_config.encryption_type != RestoreDatabaseEncryptionConfig.EncryptionType. CUSTOMER_MANAGED_ENCRYPTION): raise ValueError( "kms_key_name only used with CUSTOMER_MANAGED_ENCRYPTION") api = self._instance._client.database_admin_api metadata = _metadata_with_prefix(self.name) request = RestoreDatabaseRequest( parent=self._instance.name, database_id=self.database_id, backup=source.name, encryption_config=self._encryption_config or None, ) future = api.restore_database( request=request, metadata=metadata, ) return future
def list_instances(self, filter_="", page_size=None, page_token=None): """List instances for the client's project. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.InstanceAdmin.ListInstances :type filter_: string :param filter_: (Optional) Filter to select instances listed. See the ``ListInstancesRequest`` docs above for examples. :type page_size: int :param page_size: Optional. The maximum number of instances in each page of results from this request. Non-positive values are ignored. Defaults to a sensible value set by the API. :type page_token: str :param page_token: Optional. If present, return the next batch of instances, using the value, which must correspond to the ``nextPageToken`` value returned in the previous response. Deprecated: use the ``pages`` property of the returned iterator instead of manually passing the token. :rtype: :class:`~google.api_core.page_iterator.Iterator` :returns: Iterator of :class:`~google.cloud.spanner_v1.instance.Instance` resources within the client's project. """ metadata = _metadata_with_prefix(self.project_name) path = "projects/%s" % (self.project,) page_iter = self.instance_admin_api.list_instances( path, page_size=page_size, metadata=metadata ) page_iter.item_to_value = self._item_to_instance page_iter.next_page_token = page_token return page_iter
def update(self): """Update this instance. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.UpdateInstance .. note:: Updates the ``display_name`` and ``node_count``. To change those values before updating, set them via .. code:: python instance.display_name = 'New display name' instance.node_count = 5 before calling :meth:`update`. :rtype: :class:`google.api_core.operation.Operation` :returns: an operation instance :raises NotFound: if the instance does not exist """ api = self._client.instance_admin_api instance_pb = admin_v1_pb2.Instance( name=self.name, config=self.configuration_name, display_name=self.display_name, node_count=self.node_count, ) field_mask = FieldMask(paths=["config", "display_name", "node_count"]) metadata = _metadata_with_prefix(self.name) future = api.update_instance( instance=instance_pb, field_mask=field_mask, metadata=metadata ) return future
def list_instance_configs(self, page_size=None, page_token=None): """List available instance configurations for the client's project. .. _RPC docs: https://cloud.google.com/spanner/docs/reference/rpc/\ google.spanner.admin.instance.v1#google.spanner.admin.\ instance.v1.InstanceAdmin.ListInstanceConfigs See `RPC docs`_. :type page_size: int :param page_size: Optional. The maximum number of configs in each page of results from this request. Non-positive values are ignored. Defaults to a sensible value set by the API. :type page_token: str :param page_token: Optional. If present, return the next batch of configs, using the value, which must correspond to the ``nextPageToken`` value returned in the previous response. Deprecated: use the ``pages`` property of the returned iterator instead of manually passing the token. :rtype: :class:`~google.api_core.page_iterator.Iterator` :returns: Iterator of :class:`~google.cloud.spanner_v1.instance.InstanceConfig` resources within the client's project. """ metadata = _metadata_with_prefix(self.project_name) path = "projects/%s" % (self.project,) page_iter = self.instance_admin_api.list_instance_configs( path, page_size=page_size, metadata=metadata ) page_iter.next_page_token = page_token page_iter.item_to_value = _item_to_instance_config return page_iter
def list_databases(self, page_size=None, page_token=None): """List databases for the instance. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.ListDatabases :type page_size: int :param page_size: (Optional) Maximum number of results to return. :type page_token: str :param page_token: (Optional) Token for fetching next page of results. :rtype: :class:`~google.api._ore.page_iterator.Iterator` :returns: Iterator of :class:`~google.cloud.spanner_v1.database.Database` resources within the current instance. """ metadata = _metadata_with_prefix(self.name) page_iter = self._client.database_admin_api.list_databases( self.name, page_size=page_size, metadata=metadata ) page_iter.next_page_token = page_token page_iter.item_to_value = self._item_to_database return page_iter
def partition_query( self, sql, params=None, param_types=None, partition_size_bytes=None, max_partitions=None, ): """Perform a ``ParitionQuery`` API request. :type sql: str :param sql: SQL query statement :type params: dict, {str -> column value} :param params: values for parameter replacement. Keys must match the names used in ``sql``. :type param_types: dict[str -> Union[dict, .types.Type]] :param param_types: (Optional) maps explicit types for one or more param values; required if parameters are passed. :type partition_size_bytes: int :param partition_size_bytes: (Optional) desired size for each partition generated. The service uses this as a hint, the actual partition size may differ. :type max_partitions: int :param max_partitions: (Optional) desired maximum number of partitions generated. The service uses this as a hint, the actual number of partitions may differ. :rtype: iterable of bytes :returns: a sequence of partition tokens :raises ValueError: for single-use snapshots, or if a transaction ID is already associtated with the snapshot. """ if not self._multi_use: raise ValueError("Cannot use single-use snapshot.") if self._transaction_id is None: raise ValueError("Transaction not started.") if params is not None: if param_types is None: raise ValueError("Specify 'param_types' when passing 'params'.") params_pb = Struct( fields={key: _make_value_pb(value) for key, value in params.items()} ) else: params_pb = None database = self._session._database api = database.spanner_api metadata = _metadata_with_prefix(database.name) transaction = self._make_txn_selector() partition_options = PartitionOptions( partition_size_bytes=partition_size_bytes, max_partitions=max_partitions ) response = api.partition_query( session=self._session.name, sql=sql, transaction=transaction, params=params_pb, param_types=param_types, partition_options=partition_options, metadata=metadata, ) return [partition.partition_token for partition in response.partitions]
def _call_fut(self, *args, **kw): from google.cloud.spanner_v1._helpers import _metadata_with_prefix return _metadata_with_prefix(*args, **kw)