helios-sof 0.2.2

This crate provides a complete implementation of the SQL-on-FHIR specification for Rust, enabling the transformation of FHIR resources into tabular data using declarative ViewDefinitions. It supports all major FHIR versions (R4, R4B, R5, R6) through a version-agnostic abstraction layer.
Documentation
//! SQL-on-FHIR v2 `$sqlquery-run` engine.
//!
//! Pure execution logic: parse a SQLQuery Library, materialize its `depends-on`
//! ViewDefinitions into an in-memory SQLite database, bind `Library.parameter`
//! values to the SQL, run the user query, and format the rows.
//!
//! The REST handler in `helios-rest` wires this to storage (resolving Library
//! / ViewDefinition resources and supplying `RowStream`s from the wired
//! `SofRunner`); this module contains no storage or HTTP concerns.

pub mod bind;
pub mod engine;
pub mod library;
pub mod output;
pub mod params;
pub mod scan;

pub use bind::{BINDABLE_PARAMETER_TYPES, BoundParam, bind_supplied_params};
pub use engine::{ColumnFhirType, InMemorySqlEngine, QueryResult, TableSchema};
pub use library::{DependsOnView, LibraryParameter, SqlQueryLibrary, parse_sqlquery_library};
pub use output::format_fhir_parameters;
pub use params::{SqlQueryRunParams, extract_sqlquery_params_from_json};
pub use scan::{
    Placeholder, ScanError, ScanResult, SourcePosition, TableRef, scan_sql, undeclared_tables,
};

use thiserror::Error;

/// Errors produced by the `$sqlquery-run` pipeline.
#[derive(Debug, Error)]
pub enum SqlQueryError {
    #[error("malformed Library: {0}")]
    MalformedLibrary(String),

    #[error("SQLQuery Library has no SQL content")]
    MissingSql,

    #[error("depends-on entry missing label")]
    MissingDependsOnLabel,

    #[error("could not resolve canonical URL: {0}")]
    UnknownCanonical(String),

    #[error("too many depends-on ViewDefinitions: {count} (max {max})")]
    TooManyDependsOn { count: usize, max: usize },

    #[error("row limit exceeded ({max} rows)")]
    RowCapExceeded { max: usize },

    #[error("query exceeded {secs}s timeout")]
    Timeout { secs: u64 },

    #[error("SQL parse error: {0}")]
    NotSelect(String),

    #[error("invalid parameter binding: {0}")]
    BindParameter(String),

    #[error("invalid identifier '{0}': must not contain a double-quote")]
    InvalidIdentifier(String),

    #[error("SQLite error: {0}")]
    Sqlite(#[from] rusqlite::Error),

    #[error("composite SQL value for column '{0}' cannot be represented as a FHIR scalar")]
    UnsupportedFhirValue(String),

    /// The `SofRunner` stream feeding a `depends-on` dependency table
    /// yielded an error — a storage failure, a backend statement timeout,
    /// or a lost connection. The dependency was not materialized. This is
    /// never the client's fault (the Library and its ViewDefinitions may be
    /// perfectly well-formed) and must be surfaced as a server error, not
    /// folded into [`SqlQueryError::MalformedLibrary`].
    #[error("dependency source failed: {0}")]
    SourceStream(String),

    /// A failure in the server's own execution machinery rather than in the
    /// client's request — e.g. the blocking worker that materializes a
    /// depends-on ViewDefinition's row stream panicked. This is never
    /// caused by malformed client input and should be surfaced as a 500,
    /// not as a validation error.
    #[error("internal error: {0}")]
    Internal(String),
}