Crate snowflake_api

Source
Expand description

§snowflake-rs

Snowflake library for undocumented public API. If you want to query documented public SQL REST API use snowflake-jwt together with your favourite request library, see ./jwt/examples for how it’s done.

§Features

Since it does a lot of I/O the library is async-only, and currently has hard dependency on tokio as a runtime due to use of reqwest.

  • Single statements example
  • Multiple statements
  • Async requests (is it needed if whole library is async?)
  • Query results in Arrow
  • Chunked query results
  • Password, certificate, env auth
  • Browser-auth
  • Closing session
  • Token renewal
  • PUT support example
  • GET support
  • AWS integration
  • GCloud integration
  • Azure integration
  • Parallel uploading of small files
  • Glob support for PUT (eg *.csv)
  • Polars support example
  • Tracing / custom reqwest middlware example

§Why

Snowflake has 2 public APIs, one is SQL REST API, which is limited in its support of PUT and GET statements and another undocumented API, which is used by official Drivers with the support for both.

This implementation emulates gosnowflake library, as each official driver comes with a different set of internal flags and defaults (which are selected by CLIENT_APP_ID) the Go implementation is the only one currently outputting Arrow by-default.

We’ve chosen not to generate bindings for C/C++ libsnowflakeclient library (which backs ODBC driver) as it is in active development and building it under macOS M1 is bigger effort than writing our own API wrapper.

§Usage

In your Cargo.toml:

[dependencies]
snowflake-api = "0.7.0"

Check examples for working programs using the library.

use anyhow::Result;
use snowflake_api::{QueryResult, SnowflakeApi};

async fn run_query(sql: &str) -> Result<QueryResult> {
    let mut api = SnowflakeApi::with_password_auth(
        "ACCOUNT_IDENTIFIER",
        Some("WAREHOUSE"),
        Some("DATABASE"),
        Some("SCHEMA"),
        "USERNAME",
        Some("ROLE"),
        "PASSWORD",
    )?;
    let res = api.exec(sql).await?;

    Ok(res)
}

Or using environment variables:

 use anyhow::Result;
use snowflake_api::{QueryResult, SnowflakeApi};

async fn run_query(sql: &str) -> Result<QueryResult> {
    let mut api = SnowflakeApi::from_env()?;
    let res = api.exec(sql).await?;

    Ok(res)
}

§PUT / GET

PUT/GET statements allow you to access Snowflake-owned storage instead of provisioning your own when doing COPY INTO. Storage provider depends on which cloud your Snowflake account was provisioned in, hence the need to support multiple cloud backends.

Modules§

connection

Structs§

AuthArgs
CertificateArgs
FieldSchema
Based on the [ExecResponseRowType]
JsonResult
Even if Arrow is specified as a return type non-select queries will return Json array of arrays: [[42, "answer"], [43, "non-answer"]].
PasswordArgs
SnowflakeApi
Snowflake API, keeps connection pool and manages session for you
SnowflakeApiBuilder

Enums§

AuthType
QueryResult
Container for query result. Arrow is returned by-default for all SELECT statements, unless there is session configuration issue or it’s a different statement type.
RawQueryResult
Raw query result Can be transformed into QueryResult
SnowflakeApiError