extern crate firn;
use anyhow::Result;
use arrow::util::pretty::pretty_format_batches;
use firn::{QueryData, SnowflakeApi, SnowflakeType};
const SQL: &str = "\
SELECT TO_GEOGRAPHY('POINT(-122.0 37.5)') AS geo,
TO_GEOMETRY('POINT(0 0)') AS geom,
[1.0, 2.0, 3.0]::VECTOR(FLOAT, 3) AS v,
{'a': 1, 'b': 2, 'c': 3}::MAP(VARCHAR, INTEGER) AS m,
[10, 20, 30]::ARRAY(INTEGER) AS a";
#[tokio::main]
async fn main() -> Result<()> {
let _ = dotenvy::dotenv();
pretty_env_logger::init();
let api = SnowflakeApi::from_env()?;
let schema = api.query(SQL).describe().await?;
println!("--- describe() ---");
for f in &schema {
println!(
" {:8} type_={:?} ext_type_name={:?} vector_dimension={:?} fields={}",
f.name,
f.type_,
f.ext_type_name,
f.vector_dimension,
f.fields.len()
);
if let Some(t) = &f.ext_type_name {
println!(" -> Snowflake type {t}");
}
if matches!(f.type_, SnowflakeType::Vector) {
if let Some(elem) = f.fields.first() {
println!(
" -> VECTOR<{:?}, {}>",
elem.type_,
f.vector_dimension.unwrap_or(0)
);
}
}
}
println!("\n--- execute() raw ---");
let r = api.query(SQL).execute().await?;
println!("query_id = {}", r.metadata.query_id);
if let QueryData::Arrow(ref batches) = r.data {
if let Some(b) = batches.first() {
println!("Arrow schema (default — Snowflake demotes structured types to Utf8 JSON):");
for f in b.schema().fields() {
println!(" {} : {:?}", f.name(), f.data_type());
}
}
}
println!("\n--- execute() + cast_structured() ---");
let r = r.cast_structured()?;
match r.data {
QueryData::Arrow(batches) => {
if let Some(b) = batches.first() {
println!("Arrow schema (after cast):");
for f in b.schema().fields() {
println!(" {} : {:?}", f.name(), f.data_type());
}
println!("\nfirst batch:");
println!("{}", pretty_format_batches(std::slice::from_ref(b))?);
}
}
QueryData::Json(j) => println!("json: {j}"),
QueryData::Empty => println!("(empty)"),
}
Ok(())
}