Skip to main content

helios_persistence/
lib.rs

1//! Helios FHIR Server Persistence Layer
2//!
3//! This crate provides a polyglot persistence layer for storing and retrieving FHIR resources.
4//! It supports multiple database backends via feature flags and provides configurable
5//! multitenancy with full FHIR search capabilities.
6//!
7//! # Features
8//!
9//! - **Multiple Backends**: SQLite, PostgreSQL, Cassandra, MongoDB, Neo4j, Elasticsearch, S3
10//! - **Multitenancy**: Three isolation strategies (shared schema, schema-per-tenant, database-per-tenant)
11//! - **Full FHIR Search**: All parameter types, modifiers, chaining, _include/_revinclude
12//! - **Versioning**: Full resource history with optimistic locking
13//! - **Transactions**: ACID transactions with bundle support
14//!
15//! # Backend Features
16//!
17//! Enable backends with feature flags in `Cargo.toml`:
18//!
19//! ```toml
20//! [dependencies]
21//! helios-persistence = { version = "0.1", features = ["postgres", "R4"] }
22//! ```
23//!
24//! Available backend features:
25//! - `sqlite` (default) - SQLite with in-memory and file modes
26//! - `postgres` - PostgreSQL with JSONB storage
27//! - `cassandra` - Apache Cassandra via cdrs-tokio
28//! - `mongodb` - MongoDB document storage
29//! - `neo4j` - Neo4j graph database
30//! - `elasticsearch` - Elasticsearch for full-text search
31//! - `s3` - AWS S3 object storage
32//!
33//! FHIR version features:
34//! - `R4`, `R4B`, `R5`, `R6`
35//!
36//! # Architecture
37//!
38//! The persistence layer is organized into several modules:
39//!
40//! - [`tenant`] - Multi-tenant support with mandatory tenant context
41//! - [`types`] - Core types for stored resources and search
42//! - [`error`] - Error types for all operations
43//! - [`core`] - Storage traits and abstractions
44//! - [`strategy`] - Tenancy isolation strategies (shared schema, schema-per-tenant, database-per-tenant)
45//! - [`backends`] - Backend implementations (SQLite, PostgreSQL, etc.)
46//!
47//! # Quick Start
48//!
49//! ```no_run
50//! use helios_persistence::tenant::{TenantContext, TenantId, TenantPermissions};
51//! use helios_persistence::types::StoredResource;
52//! use helios_fhir::FhirVersion;
53//! use serde_json::json;
54//!
55//! // Create a tenant context (required for all operations)
56//! let tenant = TenantContext::new(
57//!     TenantId::new("my-organization"),
58//!     TenantPermissions::full_access(),
59//! );
60//!
61//! // Create a stored resource
62//! let resource = StoredResource::new(
63//!     "Patient",
64//!     "patient-123",
65//!     tenant.tenant_id().clone(),
66//!     json!({
67//!         "resourceType": "Patient",
68//!         "id": "patient-123",
69//!         "name": [{"family": "Smith", "given": ["John"]}]
70//!     }),
71//!     FhirVersion::default(),
72//! );
73//!
74//! // The resource includes persistence metadata
75//! assert_eq!(resource.version_id(), "1");
76//! assert_eq!(resource.url(), "Patient/patient-123");
77//! ```
78//!
79//! # Multitenancy
80//!
81//! All storage operations require a [`TenantContext`](tenant::TenantContext), ensuring
82//! tenant isolation at the type level. There is no way to bypass this requirement.
83//!
84//! ```
85//! use helios_persistence::tenant::{TenantContext, TenantId, TenantPermissions, Operation};
86//!
87//! // Full access tenant
88//! let admin_ctx = TenantContext::new(
89//!     TenantId::new("acme"),
90//!     TenantPermissions::full_access(),
91//! );
92//!
93//! // Read-only tenant
94//! let reader_ctx = TenantContext::new(
95//!     TenantId::new("acme"),
96//!     TenantPermissions::read_only(),
97//! );
98//!
99//! // Check permissions
100//! assert!(admin_ctx.check_permission(Operation::Create, "Patient").is_ok());
101//! assert!(reader_ctx.check_permission(Operation::Create, "Patient").is_err());
102//! ```
103//!
104//! # Search
105//!
106//! Build search queries with full FHIR search support:
107//!
108//! ```
109//! use helios_persistence::types::{
110//!     SearchQuery, SearchParameter, SearchParamType, SearchValue,
111//!     SearchModifier, SortDirective, IncludeDirective, IncludeType,
112//! };
113//!
114//! // Simple search
115//! let query = SearchQuery::new("Patient")
116//!     .with_parameter(SearchParameter {
117//!         name: "name".to_string(),
118//!         param_type: SearchParamType::String,
119//!         modifier: Some(SearchModifier::Contains),
120//!         values: vec![SearchValue::eq("smith")],
121//!         chain: vec![],
122//!         components: vec![],
123//!     })
124//!     .with_sort(SortDirective::parse("-_lastUpdated"))
125//!     .with_count(20);
126//!
127//! // With _include
128//! let query_with_include = SearchQuery::new("Observation")
129//!     .with_include(IncludeDirective {
130//!         include_type: IncludeType::Include,
131//!         source_type: "Observation".to_string(),
132//!         search_param: "patient".to_string(),
133//!         target_type: Some("Patient".to_string()),
134//!         iterate: false,
135//!     });
136//! ```
137
138#![warn(missing_docs)]
139#![warn(rustdoc::missing_crate_level_docs)]
140
141pub mod advisor;
142pub mod backends;
143pub mod composite;
144pub mod core;
145pub mod error;
146pub mod search;
147pub mod strategy;
148pub mod tenant;
149pub mod types;
150
151// Re-export commonly used types at crate root
152pub use error::{StorageError, StorageResult};
153pub use tenant::{TenantContext, TenantId, TenantPermissions};
154pub use types::{Pagination, SearchQuery, StoredResource};
155
156// Re-export core traits
157pub use core::{
158    Backend, BackendKind, CapabilityProvider, ResourceStorage, SearchProvider, Transaction,
159    TransactionProvider, VersionedStorage,
160};
161
162// Re-export tenancy strategies
163pub use strategy::{
164    DatabasePerTenantConfig, DatabasePerTenantStrategy, IsolationLevel, SchemaPerTenantConfig,
165    SchemaPerTenantStrategy, SharedSchemaConfig, SharedSchemaStrategy, TenancyStrategy,
166    TenantResolution, TenantResolver,
167};
168
169/// Crate version.
170pub const VERSION: &str = env!("CARGO_PKG_VERSION");
171
172/// Crate name.
173pub const NAME: &str = env!("CARGO_PKG_NAME");