5 releases (3 breaking)

0.4.0 Jan 31, 2022
0.3.0 Nov 2, 2021
0.2.0 Oct 28, 2021
0.1.1 Oct 15, 2021
0.1.0 Oct 14, 2021

#1704 in Database interfaces

Apache-2.0

135KB
2K SLoC

Rust gRPC Client Driver for Stargate

This crate provides a high-level async Rust driver for querying Stargate. It exposes the client stubs generated from gRPC proto files together with a set of utilities that make them easier to work with.

Features

  • All of the Stargate gRPC protocol messages exposed as Rust structures and enums
  • Token-based authentication
  • Asynchronous querying
  • Query builder with easy binding of variables by names or positions
  • Optional compile-time type-checking of query bind values
  • Easy conversions between gRPC value types and common Rust types; support for primitive types, lists, maps, tuples and user-defined-types, with arbitrary nesting levels
  • Result set paging

Quick start guide

Add required dependencies. You'll need at least stargate-grpc and an async framework, e.g. tokio or async-std.

[dependencies]
stargate-grpc = "0.3"
tokio = { version = "1", features = ["full"]}

At this point you should be able to build the project with cargo build and it would fetch and compile the dependencies.

For convenience, add the following line to the includes in the source code of your app:

use stargate_grpc::*;

All the code below assumes it is executed in an async context (e.g. inside async main).

Connecting

The main structure that provides the interface to Stargate is StargateClient. The simplest way to obtain an instance is to use the provided builder:

use std::str::FromStr;

let mut client = StargateClient::builder()
    .uri("http://localhost:8090/")?                           // replace with a proper address
    .auth_token(AuthToken::from_str("XXXX-YYYY-ZZZZ...")?)    // replace with a proper token
    .tls(Some(client::default_tls_config()?))                 // optionally enable TLS
    .connect()
    .await?;

Querying

Use Query::builder to create a query, bind query values and pass query parameters:

let query = Query::builder()
    .keyspace("test")                                         // set the keyspace the query applies to
    .consistency(Consistency::LocalQuorum)                    // set consistency level
    .query("SELECT login, emails FROM users WHERE id = :id")  // set the CQL string
    .bind_name("id", 1000)                                    // bind :id to 1000
    .build();                                                 // build the Query

Run the query and wait for its results:

use std::convert::TryInto;

let response = client.execute_query(query).await?;  // send the query and wait for gRPC response
let result_set: ResultSet = response.try_into()?;   // convert the response to a ResultSet

Processing the result set

The result set comes back as a collection of rows. ARow can be easily unpacked into a tuple:

for row in result_set.rows {
    let (login, emails): (String, Vec<String>) = row.try_into()?;
    // ...
}

It is also possible to move each field separately out of the row and to convert it to desired type:

for mut row in result_set.rows {
    let login: String = row.try_take(0)?;         // == row.values[0].take().try_into()?;
    let emails: Vec<String> = row.try_take(1)?;   // == row.values[1].take().try_into()?;
    // ...
}

Building from source

  1. Install Rust toolchain:

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    
  2. Run build in the root directory of the project:

    git clone https://github.com/stargate/stargate-grpc-rust-client stargate-grpc
    cd stargate-grpc
    cargo build
    

Running the examples

For your convenience, this project contains a bunch of examples located in the examples directory, which demonstrate connecting, creating schemas, inserting data and querying. You'll need a working instance of a Stargate cluster to be able to run it. Refer to the official Stargate documentation for more details on how to setup Stargate.

Each example program accepts an URL of the stargate coordinator, the authentication token and the keyspace name:

cargo run --example <example> [-- [--keyspace <keyspace>] [--token <token>] [--tls] [<url>]] 

The authentication token value can be also given in the SG_TOKEN environment variable.

  1. Set up Stargate server in developer mode using Docker:

    docker run --name stargate \
     -p 8081:8081 \
     -p 8090:8090 \
     -d \
     -e CLUSTER_NAME=stargate \
     -e CLUSTER_VERSION=3.11 \
     -e DEVELOPER_MODE=true \
     stargateio/stargate-3_11:v1.0.42
    
  2. Obtain the authentication token:

    curl -L -X POST 'http://127.0.0.1:8081/v1/auth' \
         -H 'Content-Type: application/json' \
         --data-raw '{
            "username": "cassandra",
            "password": "cassandra"
         }'
           
    {"authToken":"2df7e75d-92aa-4cda-9816-f96ccbc91d80"}
    
  3. Set the authentication token variable:

    export SG_TOKEN=2df7e75d-92aa-4cda-9816-f96ccbc91d80
    
  4. Run the keyspace example to test the connection and create the test keyspace (default keyspace name: stargate_examples)

    cargo run --example keyspace 
    Connected to http://127.0.0.1:8090
    Created keyspace stargate_examples
    
  5. Run the other examples:

    cargo run --example query 
    Finished dev [unoptimized + debuginfo] target(s) in 0.04s
    Running `target/debug/examples/basic`
    Connected to http://127.0.0.1:8090
    Created schema
    Inserted data. Now querying.
    All rows:
    2 user_2 ["user_2@example.net", "user_2@mail.example.net"]
    3 user_3 ["user_3@example.net", "user_3@mail.example.net"]
    7 user_7 ["user_7@example.net", "user_7@mail.example.net"]
    9 user_9 ["user_9@example.net", "user_9@mail.example.net"]
    4 user_4 ["user_4@example.net", "user_4@mail.example.net"]
    0 user_0 ["user_0@example.net", "user_0@mail.example.net"]
    8 user_8 ["user_8@example.net", "user_8@mail.example.net"]
    5 user_5 ["user_5@example.net", "user_5@mail.example.net"]
    6 user_6 ["user_6@example.net", "user_6@mail.example.net"]
    1 user_1 ["user_1@example.net", "user_1@mail.example.net"]
    Row with id = 1:
    1 user_1 ["user_1@example.net", "user_1@mail.example.net"]
    

Dependencies

~14–27MB
~469K SLoC