hamelin_legacy 0.4.0

Legacy AST translation code for Hamelin (to be deprecated)
Documentation
//! Thin wrapper around TrinoClient that implements the sync EnvironmentProvider trait.
//!
//! This module bridges the async `TrinoClient` from `hamelin_trino` to the sync
//! `EnvironmentProvider` trait from `hamelin_lib`.

use std::fmt::Debug;
use std::sync::Arc;
use std::thread;

use tokio::runtime::Handle;

use hamelin_lib::provider::EnvironmentProvider;
use hamelin_lib::sql::expression::identifier::Identifier;
use hamelin_lib::sql::query::TableReference;
use hamelin_lib::types::struct_type::Struct;
use hamelin_trino::TrinoClient;

/// Thin wrapper around `TrinoClient` that implements the sync `EnvironmentProvider` trait.
///
/// Uses the provided tokio Handle to run async operations. When called from within an async
/// context, spawns a separate thread to avoid "cannot block from within a runtime" errors.
pub struct TrinoEnvironmentProvider {
    client: Arc<TrinoClient>,
    handle: Handle,
}

impl TrinoEnvironmentProvider {
    pub fn new(client: Arc<TrinoClient>, handle: Handle) -> Self {
        Self { client, handle }
    }

    /// Run an async future to completion, handling both sync and async calling contexts.
    fn run_blocking<F, T>(&self, future: F) -> T
    where
        F: std::future::Future<Output = T> + Send,
        T: Send,
    {
        // Check if we're already inside a tokio runtime
        if Handle::try_current().is_ok() {
            // We're in an async context - spawn a thread to avoid blocking the runtime
            let handle = self.handle.clone();
            thread::scope(|s| {
                s.spawn(move || handle.block_on(future))
                    .join()
                    .expect("Thread panicked during async operation")
            })
        } else {
            // We're in a sync context - safe to block directly
            self.handle.block_on(future)
        }
    }
}

impl Debug for TrinoEnvironmentProvider {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("TrinoEnvironmentProvider")
            .field("client", &self.client)
            .finish()
    }
}

impl EnvironmentProvider for TrinoEnvironmentProvider {
    fn reflect_columns(&self, table_reference: TableReference) -> anyhow::Result<Struct> {
        self.run_blocking(self.client.reflect_columns(table_reference))
            .map_err(|e| anyhow::anyhow!("{}", e))
    }

    fn reflect_datasets(&self) -> anyhow::Result<Vec<Identifier>> {
        self.run_blocking(self.client.reflect_datasets())
            .map_err(|e| anyhow::anyhow!("{}", e))
    }
}