use std::collections::HashMap;
use arrow_flight::error::Result;
use arrow_flight::sql::client::FlightSqlServiceClient;
use async_trait::async_trait;
use tonic::transport::Channel;
use crate::flight::{FlightDriver, FlightMetadata, FlightProperties};
pub const QUERY: &str = "flight.sql.query";
pub const USERNAME: &str = "flight.sql.username";
pub const PASSWORD: &str = "flight.sql.password";
pub const HEADER_PREFIX: &str = "flight.sql.header.";
#[derive(Clone, Debug, Default)]
pub struct FlightSqlDriver {
properties_template: FlightProperties,
persistent_headers: bool,
}
impl FlightSqlDriver {
pub fn new() -> Self {
Default::default()
}
pub fn with_properties_template(mut self, properties_template: FlightProperties) -> Self {
self.properties_template = properties_template;
self
}
pub fn with_persistent_headers(mut self, persistent_headers: bool) -> Self {
self.persistent_headers = persistent_headers;
self
}
}
#[async_trait]
impl FlightDriver for FlightSqlDriver {
async fn metadata(
&self,
channel: Channel,
options: &HashMap<String, String>,
) -> Result<FlightMetadata> {
let mut client = FlightSqlServiceClient::new(channel);
let mut handshake_headers = self.properties_template.grpc_headers.clone();
let headers_overlay = options.iter().filter_map(|(key, value)| {
key.strip_prefix(HEADER_PREFIX)
.map(|header_name| (header_name.to_owned(), value.to_owned()))
});
handshake_headers.extend(headers_overlay);
for (name, value) in &handshake_headers {
client.set_header(name, value)
}
if let Some(username) = options.get(USERNAME) {
let default_password = "".to_string();
let password = options.get(PASSWORD).unwrap_or(&default_password);
client.handshake(username, password).await.ok();
}
let info = client.execute(options[QUERY].clone(), None).await?;
let mut partition_headers = if self.persistent_headers {
handshake_headers
} else {
HashMap::default()
};
if let Some(token) = client.token() {
partition_headers.insert("authorization".into(), format!("Bearer {token}"));
}
let props = self
.properties_template
.clone()
.with_grpc_headers(partition_headers);
FlightMetadata::try_new(info, props)
}
}