rhei-flight 1.5.0

Arrow Flight SQL server for Rhei HTAP engine OLAP queries
Documentation
//! Arrow Flight SQL gRPC server for the Rhei HTAP engine.
//!
//! This crate exposes the OLAP backend (DataFusion or DuckDB) over the
//! [Arrow Flight SQL](https://arrow.apache.org/docs/format/FlightSql.html)
//! protocol, letting clients such as `adbc_driver_flightsql` (Python), DBeaver,
//! or any standard Arrow Flight SQL driver run analytical queries via gRPC.
//!
//! # Architecture
//!
//! The crate is built on `arrow-flight 58` and `tonic 0.14`.  The core service
//! is [`RheiFlightSqlService`], which implements `FlightSqlService` and
//! delegates all query execution to [`rhei_olap::OlapBackend`].
//!
//! ## Deferred-execution pattern
//!
//! `get_flight_info_*` encodes the SQL string into an opaque
//! ticket and returns a `FlightInfo` immediately — no query planning occurs
//! yet.  When the client calls `do_get_*` with that ticket, the service
//! decodes the SQL, calls [`rhei_core::OlapEngine::query_stream`], and streams
//! Arrow IPC record batches back over the gRPC connection.
//!
//! Tickets are cheap opaque byte handles; deferring query planning to
//! `do_get` keeps `get_flight_info` latency negligible and avoids holding
//! engine resources while the client is not yet ready to consume data.
//!
//! ## Compression
//!
//! Arrow IPC record batches are compressed before transmission.
//! [`CompressionType::Zstd`] is the default — it offers the best
//! size/CPU tradeoff for typical columnar workloads.
//! [`CompressionType::Lz4`] is available for CPU-constrained clients that
//! need faster decompression.  [`CompressionType::None`] disables compression
//! entirely, which is useful on loopback or high-bandwidth LAN links.
//!
//! ## Read-only constraint
//!
//! All write operations (`do_put_*`) return `tonic::Status::unimplemented`.
//! Rhei's OLAP layer carries no DML semantics — INSERT / UPDATE / DELETE go
//! through the OLTP engine (Rusqlite) on a separate path.
//!
//! # Quick start
//!
//! ```rust,no_run
//! use std::net::SocketAddr;
//! use rhei_flight::serve_flight_sql;
//! # async fn example(olap: rhei_olap::OlapBackend) -> Result<(), Box<dyn std::error::Error>> {
//! let addr: SocketAddr = "0.0.0.0:50051".parse()?;
//! serve_flight_sql(olap, addr).await?;
//! # Ok(()) }
//! ```

mod service;

pub use service::{CompressionType, RheiFlightSqlService};

use std::net::SocketAddr;

use tonic::transport::Server;
use tracing::info;

/// Start the Arrow Flight SQL gRPC server with [`CompressionType::Zstd`] (the default).
///
/// Binds a tonic gRPC server on `addr` and serves Arrow Flight SQL queries
/// against the provided [`rhei_olap::OlapBackend`].  This is a convenience
/// wrapper around [`serve_flight_sql_with_compression`] that pre-selects Zstd.
///
/// The call blocks until the server shuts down or returns an error.
pub async fn serve_flight_sql(
    olap: rhei_olap::OlapBackend,
    addr: SocketAddr,
) -> Result<(), Box<dyn std::error::Error>> {
    serve_flight_sql_with_compression(olap, addr, CompressionType::Zstd).await
}

/// Start the Arrow Flight SQL gRPC server with the specified [`CompressionType`].
///
/// Binds a tonic gRPC server on `addr` and serves Arrow Flight SQL queries
/// against the provided [`rhei_olap::OlapBackend`].  Use this variant when
/// you need to override the default Zstd compression — for example, to select
/// [`CompressionType::Lz4`] on CPU-constrained clients or
/// [`CompressionType::None`] on loopback deployments.
///
/// The call blocks until the server shuts down or returns an error.
pub async fn serve_flight_sql_with_compression(
    olap: rhei_olap::OlapBackend,
    addr: SocketAddr,
    compression: CompressionType,
) -> Result<(), Box<dyn std::error::Error>> {
    let service = RheiFlightSqlService::with_compression(olap, compression);
    let svc = arrow_flight::flight_service_server::FlightServiceServer::new(service);

    info!(%addr, ?compression, "Arrow Flight SQL server listening");

    Server::builder().add_service(svc).serve(addr).await?;

    Ok(())
}

/// Start the Arrow Flight SQL gRPC server with bearer-token authentication.
///
/// Identical to [`serve_flight_sql`] but requires every client RPC to carry
/// `authorization: Bearer {token}` in the gRPC metadata.  Requests that omit
/// or present a wrong token are rejected with `tonic::Status::unauthenticated`.
///
/// Uses [`CompressionType::Zstd`] by default.  To combine custom compression
/// with authentication, construct a [`RheiFlightSqlService`] manually using
/// [`RheiFlightSqlService::with_compression`] and
/// [`RheiFlightSqlService::with_auth_token`].
///
/// The call blocks until the server shuts down or returns an error.
pub async fn serve_flight_sql_with_auth(
    olap: rhei_olap::OlapBackend,
    addr: SocketAddr,
    auth_token: String,
) -> Result<(), Box<dyn std::error::Error>> {
    let service = RheiFlightSqlService::with_compression(olap, CompressionType::Zstd)
        .with_auth_token(auth_token);
    let svc = arrow_flight::flight_service_server::FlightServiceServer::new(service);

    info!(%addr, "Arrow Flight SQL server listening (bearer-token auth enabled)");

    Server::builder().add_service(svc).serve(addr).await?;

    Ok(())
}