Struct Client

Source
pub struct Client { /* private fields */ }
Expand description

Client is a client for reading and writing data to a Cloud Spanner database. A client is safe to use concurrently, except for its Close method.

Implementations§

Source§

impl Client

Source

pub async fn new( database: impl Into<String>, config: ClientConfig, ) -> Result<Self, Error>

new creates a client to a database. A valid database name has the form projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID.

Source

pub async fn close(self)

Close closes all the sessions gracefully. This method can be called only once.

Source

pub async fn single(&self) -> Result<ReadOnlyTransaction, Error>

single provides a read-only snapshot transaction optimized for the case where only a single read or query is needed. This is more efficient than using read_only_transaction for a single read or query.

use google_cloud_spanner::key::Key;
use google_cloud_spanner::statement::ToKind;
use google_cloud_spanner::client::Client;

#[tokio::main]
async fn run(client: Client) {
    let mut tx = client.single().await.unwrap();
    let iter1 = tx.read("Guild",&["GuildID", "OwnerUserID"], vec![
        Key::new(&"pk1"),
        Key::new(&"pk2")
    ]).await.unwrap();
}
Source

pub async fn single_with_timestamp_bound( &self, tb: TimestampBound, ) -> Result<ReadOnlyTransaction, Error>

single provides a read-only snapshot transaction optimized for the case where only a single read or query is needed. This is more efficient than using read_only_transaction for a single read or query.

Source

pub async fn read_only_transaction(&self) -> Result<ReadOnlyTransaction, Error>

read_only_transaction returns a ReadOnlyTransaction that can be used for multiple reads from the database.

use google_cloud_spanner::client::{Client, Error};
use google_cloud_spanner::statement::Statement;
use google_cloud_spanner::key::Key;

async fn run(client: Client) -> Result<(), Error>{
    let mut tx = client.read_only_transaction().await?;

    let mut stmt = Statement::new("SELECT * , \
            ARRAY (SELECT AS STRUCT * FROM UserItem WHERE UserId = @Param1 ) AS UserItem, \
            ARRAY (SELECT AS STRUCT * FROM UserCharacter WHERE UserId = @Param1 ) AS UserCharacter  \
            FROM User \
            WHERE UserId = @Param1");

    stmt.add_param("Param1", user_id);
    let mut reader = tx.query(stmt).await?;
    let mut data = vec![];
    while let Some(row) = reader.next().await? {
        let user_id= row.column_by_name::<String>("UserId")?;
        let user_items= row.column_by_name::<Vec<model::UserItem>>("UserItem")?;
        let user_characters = row.column_by_name::<Vec<model::UserCharacter>>("UserCharacter")?;
        data.push(user_id);
    }

    let mut reader2 = tx.read("User", &["UserId"], vec![
        Key::new(&"user-1"),
        Key::new(&"user-2")
    ]).await?;

    Ok(())
}
Source

pub async fn read_only_transaction_with_option( &self, options: ReadOnlyTransactionOption, ) -> Result<ReadOnlyTransaction, Error>

read_only_transaction returns a ReadOnlyTransaction that can be used for multiple reads from the database.

Source

pub async fn batch_read_only_transaction( &self, ) -> Result<BatchReadOnlyTransaction, Error>

batch_read_only_transaction returns a BatchReadOnlyTransaction that can be used for partitioned reads or queries from a snapshot of the database. This is useful in batch processing pipelines where one wants to divide the work of reading from the database across multiple machines.

Source

pub async fn batch_read_only_transaction_with_option( &self, options: ReadOnlyTransactionOption, ) -> Result<BatchReadOnlyTransaction, Error>

batch_read_only_transaction returns a BatchReadOnlyTransaction that can be used for partitioned reads or queries from a snapshot of the database. This is useful in batch processing pipelines where one wants to divide the work of reading from the database across multiple machines.

Source

pub async fn partitioned_update(&self, stmt: Statement) -> Result<i64, Error>

partitioned_update executes a DML statement in parallel across the database, using separate, internal transactions that commit independently. The DML statement must be fully partitionable: it must be expressible as the union of many statements each of which accesses only a single row of the table. The statement should also be idempotent, because it may be applied more than once.

PartitionedUpdate returns an estimated count of the number of rows affected. The actual number of affected rows may be greater than the estimate.

Source

pub async fn partitioned_update_with_option( &self, stmt: Statement, options: PartitionedUpdateOption, ) -> Result<i64, Error>

partitioned_update executes a DML statement in parallel across the database, using separate, internal transactions that commit independently. The DML statement must be fully partitionable: it must be expressible as the union of many statements each of which accesses only a single row of the table. The statement should also be idempotent, because it may be applied more than once.

PartitionedUpdate returns an estimated count of the number of rows affected. The actual number of affected rows may be greater than the estimate.

Source

pub async fn apply_at_least_once( &self, ms: Vec<Mutation>, ) -> Result<Option<CommitResult>, Error>

apply_at_least_once may attempt to apply mutations more than once; if the mutations are not idempotent, this may lead to a failure being reported when the mutation was applied more than once. For example, an insert may fail with ALREADY_EXISTS even though the row did not exist before Apply was called. For this reason, most users of the library will prefer not to use this option. However, apply_at_least_once requires only a single RPC, whereas apply’s default replay protection may require an additional RPC. So this method may be appropriate for latency sensitive and/or high throughput blind writing.

Source

pub async fn apply_at_least_once_with_option( &self, ms: Vec<Mutation>, options: CommitOptions, ) -> Result<Option<CommitResult>, Error>

apply_at_least_once may attempt to apply mutations more than once; if the mutations are not idempotent, this may lead to a failure being reported when the mutation was applied more than once. For example, an insert may fail with ALREADY_EXISTS even though the row did not exist before Apply was called. For this reason, most users of the library will prefer not to use this option. However, apply_at_least_once requires only a single RPC, whereas apply’s default replay protection may require an additional RPC. So this method may be appropriate for latency sensitive and/or high throughput blind writing.

Source

pub async fn apply(&self, ms: Vec<Mutation>) -> Result<CommitResult, Error>

Apply applies a list of mutations atomically to the database.

use google_cloud_spanner::mutation::insert;
use google_cloud_spanner::mutation::delete;
use google_cloud_spanner::key::all_keys;
use google_cloud_spanner::statement::ToKind;
use google_cloud_spanner::client::{Client, Error};
use google_cloud_spanner::value::CommitTimestamp;

async fn run(client: Client) -> Result<(), Error>{
    let m1 = delete("Guild", all_keys());
    let m2 = insert("Guild", &["GuildID", "OwnerUserID", "UpdatedAt"], &[&"1", &"2", &CommitTimestamp::new()]);
    let commit_timestamp = client.apply(vec![m1,m2]).await?;
    Ok(())
}
Source

pub async fn apply_with_option( &self, ms: Vec<Mutation>, options: ReadWriteTransactionOption, ) -> Result<CommitResult, Error>

Apply applies a list of mutations atomically to the database.

Source

pub async fn read_write_transaction<'a, T, E, F>( &self, f: F, ) -> Result<(CommitResult, T), E>
where E: TryAs<Status> + From<SessionError> + From<Status>, F: for<'tx> Fn(&'tx mut ReadWriteTransaction) -> Pin<Box<dyn Future<Output = Result<T, E>> + Send + 'tx>>,

ReadWriteTransaction executes a read-write transaction, with retries as necessary.

The function f will be called one or more times. It must not maintain any state between calls.

If the transaction cannot be committed or if f returns an ABORTED error, ReadWriteTransaction will call f again. It will continue to call f until the transaction can be committed or the Context times out or is cancelled. If f returns an error other than ABORTED, ReadWriteTransaction will abort the transaction and return the error.

To limit the number of retries, set a deadline on the Context rather than using a fixed limit on the number of attempts. ReadWriteTransaction will retry as needed until that deadline is met.

See https://godoc.org/cloud.google.com/go/spanner#ReadWriteTransaction for more details.

use google_cloud_spanner::mutation::update;
use google_cloud_spanner::key::{Key, all_keys};
use google_cloud_spanner::value::Timestamp;
use google_cloud_spanner::client::Error;
use google_cloud_spanner::client::Client;

#[tokio::main]
async fn run(client: Client) ->  Result<(Option<Timestamp>,()), Error>{
    client.read_write_transaction(|tx| {
        Box::pin(async move {
            // The transaction function will be called again if the error code
            // of this error is Aborted. The backend may automatically abort
            // any read/write transaction if it detects a deadlock or other problems.
            let key = all_keys();
            let mut reader = tx.read("UserItem", &["UserId", "ItemId", "Quantity"], key).await?;
            let mut ms = vec![];
            while let Some(row) = reader.next().await? {
                let user_id = row.column_by_name::<String>("UserId")?;
                let item_id = row.column_by_name::<i64>("ItemId")?;
                let quantity = row.column_by_name::<i64>("Quantity")? + 1;
                let m = update("UserItem", &["Quantity"], &[&user_id, &item_id, &quantity]);
                ms.push(m);
            }
            // The buffered mutation will be committed.  If the commit
            // fails with an Aborted error, this function will be called again
            tx.buffer_write(ms);
            Ok(())
        })
    }).await
}
Source

pub async fn read_write_transaction_with_option<'a, T, E, F>( &'a self, f: F, options: ReadWriteTransactionOption, ) -> Result<(CommitResult, T), E>
where E: TryAs<Status> + From<SessionError> + From<Status>, F: for<'tx> Fn(&'tx mut ReadWriteTransaction) -> Pin<Box<dyn Future<Output = Result<T, E>> + Send + 'tx>>,

ReadWriteTransaction executes a read-write transaction, with retries as necessary.

The function f will be called one or more times. It must not maintain any state between calls.

If the transaction cannot be committed or if f returns an ABORTED error, ReadWriteTransaction will call f again. It will continue to call f until the transaction can be committed or the Context times out or is cancelled. If f returns an error other than ABORTED, ReadWriteTransaction will abort the transaction and return the error.

To limit the number of retries, set a deadline on the Context rather than using a fixed limit on the number of attempts. ReadWriteTransaction will retry as needed until that deadline is met.

See https://godoc.org/cloud.google.com/go/spanner#ReadWriteTransaction for more details.

Source

pub async fn begin_read_write_transaction( &self, ) -> Result<ReadWriteTransaction, Error>

begin_read_write_transaction creates new ReadWriteTransaction.

use google_cloud_spanner::mutation::update;
use google_cloud_spanner::key::{Key, all_keys};
use google_cloud_spanner::value::Timestamp;
use google_cloud_spanner::client::Error;
use google_cloud_spanner::client::Client;
use google_cloud_spanner::transaction_rw::ReadWriteTransaction;
use google_cloud_googleapis::spanner::v1::execute_batch_dml_request::Statement;
use google_cloud_spanner::retry::TransactionRetry;

async fn run(client: Client) -> Result<(), Error>{
    let retry = &mut TransactionRetry::new();
    loop {
        let tx = &mut client.begin_read_write_transaction().await?;

        let result = run_in_transaction(tx).await;

        // try to commit or rollback transaction.
        match tx.end(result, None).await {
            Ok((_commit_timestamp, success)) => return Ok(success),
            Err(err) => retry.next(err).await? // check retry
        }
    }
}

async fn run_in_transaction(tx: &mut ReadWriteTransaction) -> Result<(), Error> {
    let key = all_keys();
    let mut reader = tx.read("UserItem", &["UserId", "ItemId", "Quantity"], key).await?;
    let mut ms = vec![];
    while let Some(row) = reader.next().await? {
        let user_id = row.column_by_name::<String>("UserId")?;
        let item_id = row.column_by_name::<i64>("ItemId")?;
        let quantity = row.column_by_name::<i64>("Quantity")? + 1;
        let m = update("UserItem", &["UserId", "ItemId", "Quantity"], &[&user_id, &item_id, &quantity]);
        ms.push(m);
    }
    tx.buffer_write(ms);
    Ok(())
}
Source

pub fn session_count(&self) -> usize

Get open session count.

Trait Implementations§

Source§

impl Clone for Client

Source§

fn clone(&self) -> Client

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

§

impl Freeze for Client

§

impl !RefUnwindSafe for Client

§

impl Send for Client

§

impl Sync for Client

§

impl Unpin for Client

§

impl !UnwindSafe for Client

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,