Skip to main content

Backend

Trait Backend 

Source
pub trait Backend:
    Send
    + Sync
    + 'static {
    // Required methods
    fn names(&self) -> Vec<String>;
    fn summary(&self, name: &str) -> Result<DatasetSummary, AppError>;
    fn schema(&self, name: &str) -> Result<Arc<DatasetSchema>, AppError>;
    fn sample<'life0, 'life1, 'async_trait>(
        &'life0 self,
        name: &'life1 str,
    ) -> Pin<Box<dyn Future<Output = Result<String, AppError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn query<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        name: &'life1 str,
        req: &'life2 QueryRequest,
    ) -> Pin<Box<dyn Future<Output = Result<String, AppError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait;
    fn count<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        name: &'life1 str,
        req: &'life2 CountRequest,
    ) -> Pin<Box<dyn Future<Output = Result<i64, AppError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait;
    fn reload<'life0, 'life1, 'async_trait>(
        &'life0 self,
        name: &'life1 str,
    ) -> Pin<Box<dyn Future<Output = Result<ReloadStats, AppError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;

    // Provided methods
    fn indexed_columns(&self, _name: &str) -> Result<Vec<String>, AppError> { ... }
    fn query_arrow<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        _name: &'life1 str,
        _req: &'life2 QueryRequest,
    ) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, AppError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait { ... }
    fn query_arrow_stream<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        name: &'life1 str,
        req: &'life2 QueryRequest,
    ) -> Pin<Box<dyn Future<Output = Result<ArrowIpcStream, AppError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait { ... }
    fn query_arrow_stream_all<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        name: &'life1 str,
        req: &'life2 QueryRequest,
    ) -> Pin<Box<dyn Future<Output = Result<ArrowIpcStream, AppError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait { ... }
    fn parquet<'life0, 'life1, 'async_trait>(
        &'life0 self,
        _name: &'life1 str,
    ) -> Pin<Box<dyn Future<Output = Result<Bytes, AppError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait { ... }
}
Expand description

Read / reload interface every backend exposes to the HTTP layer.

All methods are async — synchronous backends (DuckDB) wrap their blocking calls in actix_web::web::block inside the impl.

Required Methods§

Source

fn names(&self) -> Vec<String>

Sorted list of dataset names.

Source

fn summary(&self, name: &str) -> Result<DatasetSummary, AppError>

Cheap summary for the dataset listing endpoint. Err(NotFound) on unknown name.

Source

fn schema(&self, name: &str) -> Result<Arc<DatasetSchema>, AppError>

Full schema for name. Err(NotFound) on unknown name.

Source

fn sample<'life0, 'life1, 'async_trait>( &'life0 self, name: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<String, AppError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

JSON for the first row of the dataset, or the literal string "null" if the dataset is empty.

Source

fn query<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, name: &'life1 str, req: &'life2 QueryRequest, ) -> Pin<Box<dyn Future<Output = Result<String, AppError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Execute req against name, returning the JSON-encoded data array (without the {"data": …, "page": …} envelope — that’s added by the handler).

Source

fn count<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, name: &'life1 str, req: &'life2 CountRequest, ) -> Pin<Box<dyn Future<Output = Result<i64, AppError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Count rows in name matching req.predicates.

Source

fn reload<'life0, 'life1, 'async_trait>( &'life0 self, name: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<ReloadStats, AppError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Rebuild name from its configured source and atomically swap it in.

Provided Methods§

Source

fn indexed_columns(&self, _name: &str) -> Result<Vec<String>, AppError>

Names of columns the backend has built an equality index over, for inclusion in the /schema response. Default impl returns an empty vec — backends without per-column indexes (e.g. DuckDB, which relies on the embedded database engine) need not override.

Source

fn query_arrow<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _name: &'life1 str, _req: &'life2 QueryRequest, ) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, AppError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Execute req against name, returning the result as an Arrow IPC stream byte buffer (one schema message + zero or more RecordBatch messages + EOS). The handler ships this verbatim with Content-Type: application/vnd.apache.arrow.stream.

Default impl errors with InvalidValue — backends that don’t produce Arrow natively (e.g. DuckDB today) reject the format and the handler falls through to JSON. Override on backends where batches are already Arrow.

Source

fn query_arrow_stream<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, name: &'life1 str, req: &'life2 QueryRequest, ) -> Pin<Box<dyn Future<Output = Result<ArrowIpcStream, AppError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Execute req and stream the Arrow IPC bytes. The default adapter preserves compatibility for backends that only implement Backend::query_arrow, but high-throughput backends should override this to avoid building one full response buffer.

Source

fn query_arrow_stream_all<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, name: &'life1 str, req: &'life2 QueryRequest, ) -> Pin<Box<dyn Future<Output = Result<ArrowIpcStream, AppError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Execute req and stream all matching Arrow IPC batches in one HTTP response. Unlike Backend::query_arrow_stream, this is not page scoped; limit may still cap the total rows returned.

Source

fn parquet<'life0, 'life1, 'async_trait>( &'life0 self, _name: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Bytes, AppError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Encode the entire dataset as a single self-contained Parquet file, returned as in-memory bytes.

Powers GET /datasets/{name}/parquet, which serves these bytes with HTTP range support so external tools (DuckDB httpfs, pandas, polars, …) can read the dataset straight over HTTP — e.g. SELECT count(*) FROM 'http://host/api/v1/datasets/accidents/parquet'.

The handler caches the result per dataset (and invalidates on reload) so the repeated range requests a Parquet reader makes all see identical, stable bytes. Default impl errors with InvalidValue; every shipped backend overrides it.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§