Expand description
§firn
Rust client for Snowflake’s internal HTTP API (the same endpoint the
official drivers use). Forked from
snowflake-api at v0.14.0
(andrusha/snowflake-rs).
[dependencies]
firn = "0.15"Default features: cert-auth. Optional: browser-auth, polars.
§Quick start
use firn::{QueryData, SnowflakeApi};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let api = SnowflakeApi::from_env()?;
let r = api.exec("SELECT current_version()").await?;
match r.data {
QueryData::Arrow(batches) => { /* ... */ }
QueryData::Json(v) => { /* ... */ }
QueryData::Empty => {}
}
Ok(())
}§Features
§Auth
- password (
with_password_auth) - key-pair JWT (
with_certificate_auth,cert-authfeature, default) - external-browser SSO (
with_browser_auth,browser-authfeature) - env-driven (
from_env)
§Queries
- single statement (
run_sql.rs) - positional
?bind parameters (run_sql_bound.rs) - multi-statement (
execute_multi,execute_multi_exact) (multi_statement.rs) - per-request session-parameter overrides (
with_session_param) (session_params.rs) - async long-running queries with transparent polling (
run_sql_long_running.rs) - submit + fetch-by-
query_idacross processes (submit_async,query_status,fetch_results) (query_by_id.rs) - describe-only introspection (
describe()) (describe_query.rs)
§Results
- Arrow
RecordBatch, with streaming and raw-IPC variants (streaming.rs) - JSON results when the session is configured for JSON
- per-query
QueryMetadata:query_id,total_rows,total_chunks,statement_type_id, executing warehouse/database/schema/role cast_structured()rewritesMAP/OBJECT/ARRAYcolumns from JSON-in-Utf8 into native ArrowMap<Utf8, V>/List<E>(compound_types.rs)GEOGRAPHY/GEOMETRYcarried viaFieldSchema::ext_type_name;VECTORviavector_dimension+ element typeStatementTypeenum,is_dql()predicate
§Cancellation
- token-based via
CancellationToken(cancel_query.rs) - cross-task by
request_id(cancel_query) (cancel_by_id.rs) - cross-process by
query_id(cancel_query_by_id) (cancel_by_query_id.rs)
§Session
- session-keep-alive heartbeat (
with_keep_alive) (keep_alive.rs) - session-token renewal on
390112mid-flight - parallel queries on a shared
SnowflakeApiwith a lock-free hot path (arc-swap) (parallel_queries.rs)
§Connection
- retry middleware that rotates
request_guidper attempt and writesretryCount/retryReason/clientStartTimeon retriedquery-requestcalls - configurable connect and request timeouts
- credentials and auth tokens wrapped in
SecretString(Debug-redacted, zeroized on drop) - custom reqwest middleware injection (
tracing/)
§PUT
- AWS S3 storage backend
- glob expansion (
PUT 'file:///tmp/*.csv' @stage) - parallel upload of small files
§Integrations
- polars
DataFrameconversion (polarsfeature) (polars/)
§Why
Snowflake exposes two HTTP APIs: the public SQL REST API
and the undocumented endpoint that the official drivers use. This crate
targets the latter, since it supports Arrow output and PUT/GET.
The wire format and retry/cancel semantics follow gosnowflake, the Go driver, since it outputs Arrow by default and is the most legible reference implementation.
§License
Apache-2.0. Original work © Andrew Korzhuev (andrusha/snowflake-rs);
fork modifications © Will Eaton. See LICENSE.
Modules§
Structs§
- Auth
Args - Bind
- A typed bind value. Construct via the inherent constructors
(
Bind::text,Bind::fixed, etc.) or viaIntofrom common primitive types. Pass a slice of these to the query builder. - Certificate
Args - Field
Schema - Based on the [
ExecResponseRowType]. Carries the full type-info surface Snowflake returns for a column —length/byte_length/ extension-type discriminator / VECTOR dimension / nested element sub-schema — so codegen tools that consumedescribe()output don’t have to fall back to the raw response. - Json
Result - Even if Arrow is specified as a return type non-select queries
will return Json array of arrays:
[[42, "answer"], [43, "non-answer"]]. - Password
Args - Query
Builder - Fluent builder returned by
SnowflakeApi::query. Accumulates bind parameters and optional cancellation/request-id, then runs the query viaexecute()(deserialized Arrow) orexecute_raw()(raw bytes). - Query
Handle - Returned by
SnowflakeApi::submit_async/QueryBuilder::submit_async. Both ids are useful:request_idis whatSnowflakeApi::cancel_queryunderstands (same-process abort path),query_idis whatSnowflakeApi::query_status/SnowflakeApi::fetch_resultsexpect (cross-process / cross-worker dispatch). - Query
Metadata - Per-query metadata Snowflake returns alongside the result body. Carried
on
QueryResult,RawQueryResult, and the streaming entry points so callers can correlate a result with itsqueryId(for history / debugging /cancel_query), see which session context actually executed it, and short-circuit on row count without scanning batches. - Query
Result - Container for a successful query response:
QueryMetadata+ rows. Arrow is returned by default for SELECTs unless the session is configured otherwise. - RawQuery
Result - Raw counterpart to
QueryResult: Arrow IPC bytes or JSON, plus metadata. Convertible intoQueryResultviaRawQueryResult::deserialize_arrow. - Record
Batch - A two-dimensional batch of column-oriented data with a defined schema.
- Snowflake
Api - Snowflake API, keeps connection pool and manages session for you
- Snowflake
ApiBuilder
Enums§
- Arrow
Error - Many different operations in the
arrowcrate return this error type. - Auth
Type - Query
Data - Query
Status - Mirrors gosnowflake’s
monitoring.goquery-status constants.Otheris the catch-all so a new server-side status doesn’t immediately break callers; treat unknown values as non-terminal until proven otherwise. - RawQuery
Data - Snowflake
ApiError - Snowflake
Type - Statement
Type - Decoded
statement_type_id, mirroring gosnowflake’s named constants (connection.godefines exactly these four; everything else isOther). gosnowflake’s grouping is intentionally coarse: INSERT / UPDATE / DELETE / MERGE all map toStatementType::Dmlby way of being inside the[0x3000, 0x3500]range. If you need finer granularity, compare against the rawQueryMetadata::statement_type_idinteger directly.
Functions§
- cast_
structured_ batch - Rewrite Utf8 columns whose Arrow field metadata carries
logicalType: "OBJECT"or"ARRAY"into proper ArrowMap<Utf8, V>/List<E>.VandEare inferred per-batch (Boolean/Int64/Float64/Utf8). - cast_
structured_ batch_ with_ schema - Like
cast_structured_batch, butcolumn_schema(the Snowflake rowtype carried oncrate::QueryMetadata::column_schema) suppliesext_type_nameinfo that isn’t in the Arrow field metadata yet. Use this on the streaming path soGEOGRAPHY/GEOMETRYcolumns stay as rawUtf8GeoJSONinstead of being shredded intoMap<Utf8, Utf8>. - cast_
structured_ stream - Wrap a
RecordBatchStreamso each emitted batch is run throughcast_structured_batch_with_schemawith the suppliedcolumn_schema(typicallymeta.column_schemafrom the sameexecute_streamcall).GEOGRAPHY/GEOMETRYcolumns stay raw,MAP/OBJECT/ARRAYcolumns become typed Arrow Map / List.
Type Aliases§
- Arrow
Chunk Stream - Stream of Arrow IPC blobs, one per Snowflake chunk, in original response order. Suitable for forwarding through HTTP/SSE without re-encoding.
- Record
Batch Stream - Stream of decoded Arrow
RecordBatches. A single Snowflake chunk may contain multiple batches; they are flattened into the stream in order. - Secret
String - Secret string type.