4 releases

0.2.0 Dec 15, 2022
0.1.2 Nov 27, 2022
0.1.1 Nov 24, 2022
0.1.0 Nov 24, 2022

#1762 in Database interfaces

MIT/Apache

26KB
490 lines

Snowflake Connector

Under heavy development. Might be wise to point to git instead of crates.io for now.

Usage

Add following line to Cargo.toml:

snowflake-connector = { version = "0.2", features = ["derive"] }

Right now, only key pair authentication is supported.

You must have the text files environment_variables/snowflake_private_key_path.txt and environment_variables/snowflake_public_key_path.txt, where your application is executed, and these files must store the path to the keys.

Dev Setup

Add your public and private key under environment_variables/local folder (you will have to create the local folder). Make sure your private key is named rsa_key.p8 and your public key is rsa_key.pub.

Point environment_variables/snowflake_private_key_path.txt to your private key by changing its contents to: ./environment_variables/local/rsa_key.p8

Point environment_variables/snowflake_public_key_path.txt to your public key: ./environment_variables/local/rsa_key.pub

Make sure to ignore the environment_variables directory. You do not want to commit your keys to a repository.

How it Works

Below example is not tested, but you get the gist:

use snowflake_connector::{*, errors::SnowflakeError};

fn get_from_snowflake() -> Result<SnowflakeSQLResult<Test>, SnowflakeError> {
    let connector = SnowflakeConnector::try_new("COMPANY.ACCOUNT", "ACCOUNT", "USER@EXAMPLE.COM")?;
    connector
        .execute("DB", "WH")
        .sql("SELECT * FROM TEST_TABLE WHERE id = ? LIMIT 69")?
        .add_binding(420)
        .select::<Test>().await
}

fn main() {
    if let Ok(data) = get_from_snowflake() {
        println!("{:#?}", data)
    } else {
        panic!("Failed to retrieve data from snowflake!");
    }
}

// Fields must be in order of columns!
#[derive(SnowflakeDeserialize, Debug)]
pub struct Test {
    pub id: u32,
    pub value1: bool,
    pub value2: String,
    pub value3: SomeEnumValue,
}

// Enum must implement DeserializeFromStr!
#[derive(Debug)]
pub enum SomeEnumValue {
    Value1,
    Value2,
}

// Snowflake sends each cell as a string,
// convert the string to the appropriate type!
impl DeserializeFromStr for SomeEnumValue {
    type Err = anyhow::Error;
    fn deserialize_from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "VALUE1" => Ok(SomeEnumValue::Value1),
            "VALUE2" => Ok(SomeEnumValue::Value2),
            _ => Err(anyhow::anyhow!("Failed to convert string to SomeEnumValue")),
        }
    }
}

Snowflake returns every value as a string. Implement DeserializeFromStr for types that can be parsed from a string. Add the SnowflakeDeserialize derive attribute to a struct to allow SnowflakeConnector to convert the data to that type. As of now, the order of the fields must correspond to the order of the columns. Let's assume the fields go top-to-bottom, so the top-most field must be the first column, the bottom-most field must be the last column, otherwise deserializing will fail.

Dependencies

~12–25MB
~381K SLoC