Struct scylla::transport::session::GenericSession

source ·
pub struct GenericSession<DeserializationApi>
where DeserializationApi: DeserializationApiKind,
{ /* private fields */ }
Expand description

Session manages connections to the cluster and allows to perform queries

Implementations§

source§

impl GenericSession<CurrentDeserializationApi>

source

pub async fn query_unpaged( &self, query: impl Into<Query>, values: impl SerializeRow, ) -> Result<QueryResult, QueryError>

Sends a request to the database and receives a response.
Performs an unpaged query, i.e. all results are received in a single response.

This is the easiest way to make a query, but performance is worse than that of prepared queries.

It is discouraged to use this method with non-empty values argument (is_empty() method from SerializeRow trait returns false). In such case, query first needs to be prepared (on a single connection), so driver will perform 2 round trips instead of 1. Please use Session::execute_unpaged() instead.

As all results come in one response (no paging is done!), the memory footprint and latency may be huge for statements returning rows (i.e. SELECTs)! Prefer this method for non-SELECTs, and for SELECTs it is best to use paged queries:

  • to receive multiple pages and transparently iterate through them, use query_iter.
  • to manually receive multiple pages and iterate through them, use query_single_page.

See the book for more information

§Arguments
  • query - statement to be executed, can be just a &str or the Query struct.
  • values - values bound to the query, the easiest way is to use a tuple of bound values.
§Examples
// Insert an int and text into a table.
session
    .query_unpaged(
        "INSERT INTO ks.tab (a, b) VALUES(?, ?)",
        (2_i32, "some text")
    )
    .await?;
use scylla::IntoTypedRows;

// Read rows containing an int and text.
// Keep in mind that all results come in one response (no paging is done!),
// so the memory footprint and latency may be huge!
// To prevent that, use `Session::query_iter` or `Session::query_single_page`.
let query_rows = session
    .query_unpaged("SELECT a, b FROM ks.tab", &[])
    .await?
    .into_rows_result()?;

for row in query_rows.rows()? {
    // Parse row as int and text.
    let (int_val, text_val): (i32, &str) = row?;
}
source

pub async fn query_single_page( &self, query: impl Into<Query>, values: impl SerializeRow, paging_state: PagingState, ) -> Result<(QueryResult, PagingStateResponse), QueryError>

Queries a single page from the database, optionally continuing from a saved point.

It is discouraged to use this method with non-empty values argument (is_empty() method from SerializeRow trait returns false). In such case, query first needs to be prepared (on a single connection), so driver will perform 2 round trips instead of 1. Please use Session::execute_single_page() instead.

§Arguments
  • query - statement to be executed
  • values - values bound to the query
  • paging_state - previously received paging state or PagingState::start()
§Example
use std::ops::ControlFlow;
use scylla::statement::PagingState;

// Manual paging in a loop, unprepared statement.
let mut paging_state = PagingState::start();
loop {
   let (res, paging_state_response) = session
       .query_single_page("SELECT a, b, c FROM ks.tbl", &[], paging_state)
       .await?;

   // Do something with a single page of results.
   for row in res
       .into_rows_result()?
       .rows::<(i32, &str)>()?
   {
       let (a, b) = row?;
   }

   match paging_state_response.into_paging_control_flow() {
       ControlFlow::Break(()) => {
           // No more pages to be fetched.
           break;
       }
       ControlFlow::Continue(new_paging_state) => {
           // Update paging state from the response, so that query
           // will be resumed from where it ended the last time.
           paging_state = new_paging_state;
       }
   }
}
source

pub async fn query_iter( &self, query: impl Into<Query>, values: impl SerializeRow, ) -> Result<QueryPager, QueryError>

Run an unprepared query with paging
This method will query all pages of the result\

Returns an async iterator (stream) over all received rows
Page size can be specified in the Query passed to the function

It is discouraged to use this method with non-empty values argument (is_empty() method from SerializeRow trait returns false). In such case, query first needs to be prepared (on a single connection), so driver will initially perform 2 round trips instead of 1. Please use Session::execute_iter() instead.

See the book for more information.

§Arguments
  • query - statement to be executed, can be just a &str or the Query struct.
  • values - values bound to the query, the easiest way is to use a tuple of bound values.
§Example
use scylla::IntoTypedRows;
use futures::stream::StreamExt;

let mut rows_stream = session
   .query_iter("SELECT a, b FROM ks.t", &[])
   .await?
   .rows_stream::<(i32, i32)>()?;

while let Some(next_row_res) = rows_stream.next().await {
    let (a, b): (i32, i32) = next_row_res?;
    println!("a, b: {}, {}", a, b);
}
source

pub async fn execute_unpaged( &self, prepared: &PreparedStatement, values: impl SerializeRow, ) -> Result<QueryResult, QueryError>

Execute a prepared statement. Requires a PreparedStatement generated using Session::prepare.
Performs an unpaged query, i.e. all results are received in a single response.

As all results come in one response (no paging is done!), the memory footprint and latency may be huge for statements returning rows (i.e. SELECTs)! Prefer this method for non-SELECTs, and for SELECTs it is best to use paged queries:

  • to receive multiple pages and transparently iterate through them, use execute_iter.
  • to manually receive multiple pages and iterate through them, use execute_single_page.

Prepared queries are much faster than simple queries:

  • Database doesn’t need to parse the query
  • They are properly load balanced using token aware routing

Warning
For token/shard aware load balancing to work properly, all partition key values must be sent as bound values (see performance section).

See the book for more information.

§Arguments
  • prepared - the prepared statement to execute, generated using Session::prepare
  • values - values bound to the query, the easiest way is to use a tuple of bound values
§Example
use scylla::prepared_statement::PreparedStatement;

// Prepare the query for later execution
let prepared: PreparedStatement = session
    .prepare("INSERT INTO ks.tab (a) VALUES(?)")
    .await?;

// Run the prepared query with some values, just like a simple query.
let to_insert: i32 = 12345;
session.execute_unpaged(&prepared, (to_insert,)).await?;
source

pub async fn execute_single_page( &self, prepared: &PreparedStatement, values: impl SerializeRow, paging_state: PagingState, ) -> Result<(QueryResult, PagingStateResponse), QueryError>

Executes a prepared statement, restricting results to single page. Optionally continues fetching results from a saved point.

§Arguments
  • prepared - a statement prepared with prepare
  • values - values bound to the query
  • paging_state - continuation based on a paging state received from a previous paged query or None
§Example
use std::ops::ControlFlow;
use scylla::query::Query;
use scylla::statement::{PagingState, PagingStateResponse};

let paged_prepared = session
    .prepare(
        Query::new("SELECT a, b FROM ks.tbl")
            .with_page_size(100.try_into().unwrap()),
    )
    .await?;

// Manual paging in a loop, prepared statement.
let mut paging_state = PagingState::start();
loop {
    let (res, paging_state_response) = session
        .execute_single_page(&paged_prepared, &[], paging_state)
        .await?;

   // Do something with a single page of results.
   for row in res
       .into_rows_result()?
       .rows::<(i32, &str)>()?
   {
       let (a, b) = row?;
   }

    match paging_state_response.into_paging_control_flow() {
        ControlFlow::Break(()) => {
            // No more pages to be fetched.
            break;
        }
        ControlFlow::Continue(new_paging_state) => {
            // Update paging continuation from the paging state, so that query
            // will be resumed from where it ended the last time.
            paging_state = new_paging_state;
        }
    }
}
source

pub async fn execute_iter( &self, prepared: impl Into<PreparedStatement>, values: impl SerializeRow, ) -> Result<QueryPager, QueryError>

Run a prepared query with paging.
This method will query all pages of the result.\

Returns an async iterator (stream) over all received rows.
Page size can be specified in the PreparedStatement passed to the function.

See the book for more information.

§Arguments
  • prepared - the prepared statement to execute, generated using Session::prepare
  • values - values bound to the query, the easiest way is to use a tuple of bound values
§Example
use scylla::prepared_statement::PreparedStatement;
use scylla::IntoTypedRows;

// Prepare the query for later execution
let prepared: PreparedStatement = session
    .prepare("SELECT a, b FROM ks.t")
    .await?;

// Execute the query and receive all pages
let mut rows_stream = session
   .execute_iter(prepared, &[])
   .await?
   .rows_stream::<(i32, i32)>()?;

while let Some(next_row_res) = rows_stream.next().await {
    let (a, b): (i32, i32) = next_row_res?;
    println!("a, b: {}, {}", a, b);
}
source

pub async fn batch( &self, batch: &Batch, values: impl BatchValues, ) -> Result<QueryResult, QueryError>

Perform a batch query
Batch contains many simple or prepared queries which are executed at once
Batch doesn’t return any rows

Batch values must contain values for each of the queries

Avoid using non-empty values (SerializeRow::is_empty() return false) for simple queries inside the batch. Such queries will first need to be prepared, so the driver will need to send (numer_of_unprepared_queries_with_values + 1) requests instead of 1 request, severly affecting performance.

See the book for more information

§Arguments
  • batch - Batch to be performed
  • values - List of values for each query, it’s the easiest to use a tuple of tuples
§Example
use scylla::batch::Batch;

let mut batch: Batch = Default::default();

// A query with two bound values
batch.append_statement("INSERT INTO ks.tab(a, b) VALUES(?, ?)");

// A query with one bound value
batch.append_statement("INSERT INTO ks.tab(a, b) VALUES(3, ?)");

// A query with no bound values
batch.append_statement("INSERT INTO ks.tab(a, b) VALUES(5, 6)");

// Batch values is a tuple of 3 tuples containing values for each query
let batch_values = ((1_i32, 2_i32), // Tuple with two values for the first query
                    (4_i32,),       // Tuple with one value for the second query
                    ());            // Empty tuple/unit for the third query

// Run the batch
session.batch(&batch, batch_values).await?;
source

pub fn make_shared_session_with_legacy_api(&self) -> LegacySession

👎Deprecated since 0.15.0: Legacy deserialization API is inefficient and is going to be removed soon

Creates a new Session instance that shared resources with the current Session but supports the legacy API.

This method is provided in order to make migration to the new deserialization API easier. For example, if your program in general uses the new API but you still have some modules left that use the old one, you can use this method to create an instance that supports the old API and pass it to the module that you intend to migrate later.

source§

impl GenericSession<LegacyDeserializationApi>

source

pub async fn query_unpaged( &self, query: impl Into<Query>, values: impl SerializeRow, ) -> Result<LegacyQueryResult, QueryError>

👎Deprecated since 0.15.0: Legacy deserialization API is inefficient and is going to be removed soon
source

pub async fn query_single_page( &self, query: impl Into<Query>, values: impl SerializeRow, paging_state: PagingState, ) -> Result<(LegacyQueryResult, PagingStateResponse), QueryError>

👎Deprecated since 0.15.0: Legacy deserialization API is inefficient and is going to be removed soon
source

pub async fn query_iter( &self, query: impl Into<Query>, values: impl SerializeRow, ) -> Result<LegacyRowIterator, QueryError>

👎Deprecated since 0.15.0: Legacy deserialization API is inefficient and is going to be removed soon
source

pub async fn execute_unpaged( &self, prepared: &PreparedStatement, values: impl SerializeRow, ) -> Result<LegacyQueryResult, QueryError>

👎Deprecated since 0.15.0: Legacy deserialization API is inefficient and is going to be removed soon
source

pub async fn execute_single_page( &self, prepared: &PreparedStatement, values: impl SerializeRow, paging_state: PagingState, ) -> Result<(LegacyQueryResult, PagingStateResponse), QueryError>

👎Deprecated since 0.15.0: Legacy deserialization API is inefficient and is going to be removed soon
source

pub async fn execute_iter( &self, prepared: impl Into<PreparedStatement>, values: impl SerializeRow, ) -> Result<LegacyRowIterator, QueryError>

👎Deprecated since 0.15.0: Legacy deserialization API is inefficient and is going to be removed soon
source

pub async fn batch( &self, batch: &Batch, values: impl BatchValues, ) -> Result<LegacyQueryResult, QueryError>

👎Deprecated since 0.15.0: Legacy deserialization API is inefficient and is going to be removed soon
source

pub fn make_shared_session_with_new_api(&self) -> Session

👎Deprecated since 0.15.0: Legacy deserialization API is inefficient and is going to be removed soon

Creates a new Session instance that shares resources with the current Session but supports the new API.

This method is provided in order to make migration to the new deserialization API easier. For example, if your program in general uses the old API but you want to migrate some modules to the new one, you can use this method to create an instance that supports the new API and pass it to the module that you intend to migrate.

The new session object will use the same connections and cluster metadata.

source§

impl<DeserApi> GenericSession<DeserApi>
where DeserApi: DeserializationApiKind,

Represents a CQL session, which can be used to communicate with the database

source

pub async fn connect(config: SessionConfig) -> Result<Self, NewSessionError>

Estabilishes a CQL session with the database

Usually it’s easier to use SessionBuilder instead of calling Session::connect directly, because it’s more convenient.

§Arguments
  • config - Connection configuration - known nodes, Compression, etc. Must contain at least one known node.
§Example
use scylla::{Session, SessionConfig};
use scylla::transport::KnownNode;

let mut config = SessionConfig::new();
config.known_nodes.push(KnownNode::Hostname("127.0.0.1:9042".to_string()));

let session: Session = Session::connect(config).await?;
source

pub async fn prepare( &self, query: impl Into<Query>, ) -> Result<PreparedStatement, QueryError>

Prepares a statement on the server side and returns a prepared statement, which can later be used to perform more efficient queries

Prepared queries are much faster than simple queries:

  • Database doesn’t need to parse the query
  • They are properly load balanced using token aware routing

Warning
For token/shard aware load balancing to work properly, all partition key values must be sent as bound values (see performance section)

See the book for more information. See the documentation of PreparedStatement.

§Arguments
  • query - query to prepare, can be just a &str or the Query struct.
§Example
use scylla::prepared_statement::PreparedStatement;

// Prepare the query for later execution
let prepared: PreparedStatement = session
    .prepare("INSERT INTO ks.tab (a) VALUES(?)")
    .await?;

// Run the prepared query with some values, just like a simple query
let to_insert: i32 = 12345;
session.execute_unpaged(&prepared, (to_insert,)).await?;
source

pub async fn prepare_batch(&self, batch: &Batch) -> Result<Batch, QueryError>

Prepares all statements within the batch and returns a new batch where every statement is prepared. /// # Example

use scylla::batch::Batch;

// Create a batch statement with unprepared statements
let mut batch: Batch = Default::default();
batch.append_statement("INSERT INTO ks.simple_unprepared1 VALUES(?, ?)");
batch.append_statement("INSERT INTO ks.simple_unprepared2 VALUES(?, ?)");

// Prepare all statements in the batch at once
let prepared_batch: Batch = session.prepare_batch(&batch).await?;

// Specify bound values to use with each query
let batch_values = ((1_i32, 2_i32),
                    (3_i32, 4_i32));

// Run the prepared batch
session.batch(&prepared_batch, batch_values).await?;
source

pub async fn use_keyspace( &self, keyspace_name: impl Into<String>, case_sensitive: bool, ) -> Result<(), QueryError>

Sends USE <keyspace_name> request on all connections
This allows to write SELECT * FROM table instead of SELECT * FROM keyspace.table\

Note that even failed use_keyspace can change currently used keyspace - the request is sent on all connections and can overwrite previously used keyspace.

Call only one use_keyspace at a time.
Trying to do two use_keyspace requests simultaneously with different names can end with some connections using one keyspace and the rest using the other.

See the book for more information

§Arguments
  • keyspace_name - keyspace name to use, keyspace names can have up to 48 alphanumeric characters and contain underscores
  • case_sensitive - if set to true the generated query will put keyspace name in quotes
§Example
session
    .query_unpaged("INSERT INTO my_keyspace.tab (a) VALUES ('test1')", &[])
    .await?;

session.use_keyspace("my_keyspace", false).await?;

// Now we can omit keyspace name in the query
session
    .query_unpaged("INSERT INTO tab (a) VALUES ('test2')", &[])
    .await?;
source

pub async fn refresh_metadata(&self) -> Result<(), QueryError>

Manually trigger a metadata refresh
The driver will fetch current nodes in the cluster and update its metadata

Normally this is not needed, the driver should automatically detect all metadata changes in the cluster

source

pub fn get_metrics(&self) -> Arc<Metrics>

Access metrics collected by the driver
Driver collects various metrics like number of queries or query latencies. They can be read using this method

source

pub fn get_cluster_data(&self) -> Arc<ClusterData>

Access cluster data collected by the driver
Driver collects various information about network topology or schema. They can be read using this method

source

pub async fn get_tracing_info( &self, tracing_id: &Uuid, ) -> Result<TracingInfo, QueryError>

Get TracingInfo of a traced query performed earlier

See the book for more information about query tracing

source

pub fn get_keyspace(&self) -> Option<Arc<String>>

Gets the name of the keyspace that is currently set, or None if no keyspace was set.

It will initially return the name of the keyspace that was set in the session configuration, but calling use_keyspace will update it.

Note: the return value might be wrong if use_keyspace was called concurrently or it previously failed. It is also unspecified if get_keyspace is called concurrently with use_keyspace.

source

pub async fn await_schema_agreement(&self) -> Result<Uuid, QueryError>

source

pub async fn check_schema_agreement(&self) -> Result<Option<Uuid>, QueryError>

source

pub fn get_default_execution_profile_handle(&self) -> &ExecutionProfileHandle

Retrieves the handle to execution profile that is used by this session by default, i.e. when an executed statement does not define its own handle.

Trait Implementations§

source§

impl<DeserApi> Debug for GenericSession<DeserApi>
where DeserApi: DeserializationApiKind,

This implementation deliberately omits some details from Cluster in order to avoid cluttering the print with much information of little usability.

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<DeserializationApi> Freeze for GenericSession<DeserializationApi>

§

impl<DeserializationApi> !RefUnwindSafe for GenericSession<DeserializationApi>

§

impl<DeserializationApi> Send for GenericSession<DeserializationApi>
where DeserializationApi: Send,

§

impl<DeserializationApi> Sync for GenericSession<DeserializationApi>
where DeserializationApi: Sync,

§

impl<DeserializationApi> Unpin for GenericSession<DeserializationApi>
where DeserializationApi: Unpin,

§

impl<DeserializationApi> !UnwindSafe for GenericSession<DeserializationApi>

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> 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> IntoEither for T

source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

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

§

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>,

§

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<V, T> VZip<V> for T
where V: MultiLane<T>,

source§

fn vzip(self) -> V

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,