1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//! High-performance multi-tenant support for Prax.
//!
//! This module provides comprehensive, performance-optimized multi-tenancy support with
//! multiple isolation strategies:
//!
//! - **Row-Level Security (RLS)**: All tenants share tables, filtered by tenant_id column
//! - **Schema-Based**: Each tenant has their own database schema
//! - **Database-Based**: Each tenant has their own database
//!
//! # Performance Features
//!
//! This implementation includes several performance optimizations:
//!
//! - **Zero-allocation context propagation** via task-local storage
//! - **PostgreSQL RLS integration** for database-level enforcement (no app overhead)
//! - **LRU tenant cache** with TTL and background refresh
//! - **Per-tenant connection pools** with LRU eviction
//! - **Prepared statement caching** that works across tenants (with RLS)
//! - **Sharded caches** for high-concurrency scenarios
//!
//! # Quick Start
//!
//! ```rust,ignore
//! use prax_query::tenant::{TenantContext, TenantConfig, IsolationStrategy};
//! use prax_query::tenant::task_local::with_tenant;
//!
//! // Configure row-level isolation with PostgreSQL RLS
//! let config = TenantConfig::row_level("tenant_id");
//!
//! // Zero-allocation tenant context via task-locals
//! with_tenant("tenant-123", async {
//! // All queries automatically filtered by tenant
//! let users = client.user().find_many().exec().await?;
//! // SQL: SELECT * FROM users WHERE tenant_id = 'tenant-123'
//! Ok(())
//! }).await?;
//! ```
//!
//! # Isolation Strategies
//!
//! ## Row-Level Security (Most Performant)
//!
//! The simplest and most performant approach where all tenants share tables.
//! When combined with PostgreSQL RLS, filtering happens in the database engine
//! with zero application overhead:
//!
//! ```rust,ignore
//! use prax_query::tenant::rls::{RlsManager, RlsConfig};
//!
//! // Setup PostgreSQL RLS
//! let rls = RlsManager::new(
//! RlsConfig::new("tenant_id")
//! .with_session_variable("app.current_tenant")
//! .add_tables(["users", "orders", "products"])
//! );
//!
//! // Generate and execute setup SQL
//! let setup_sql = rls.setup_sql();
//! conn.execute_batch(&setup_sql).await?;
//!
//! // Now all queries are automatically filtered by the database
//! // Just set the tenant context per-request:
//! conn.execute(&rls.set_tenant_local_sql("tenant-123"), &[]).await?;
//! ```
//!
//! ## Schema-Based
//!
//! Each tenant gets their own schema (PostgreSQL/MySQL):
//!
//! ```rust,ignore
//! let config = TenantConfig::schema_based()
//! .with_schema_prefix("tenant_")
//! .with_shared_schema("shared");
//! ```
//!
//! ## Database-Based (Complete Isolation)
//!
//! Each tenant gets their own database:
//!
//! ```rust,ignore
//! use prax_query::tenant::pool::{TenantPoolManager, PoolStrategy};
//!
//! // Use per-tenant connection pools
//! let pool_manager = TenantPoolManager::builder()
//! .per_tenant(100, 5) // max 100 tenants, 5 connections each
//! .build();
//!
//! let config = TenantConfig::database_based()
//! .with_resolver(|tenant_id| async move {
//! DatabaseConfig::from_url(&format!("postgres://localhost/{}", tenant_id))
//! });
//! ```
//!
//! # Caching
//!
//! The module provides high-performance caching for tenant lookups:
//!
//! ```rust,ignore
//! use prax_query::tenant::cache::{TenantCache, ShardedTenantCache, CacheConfig};
//!
//! // Simple cache
//! let cache = TenantCache::new(CacheConfig::new(10_000).with_ttl(Duration::from_secs(300)));
//!
//! // High-concurrency sharded cache
//! let cache = ShardedTenantCache::high_concurrency(10_000);
//!
//! // Get or fetch tenant
//! let ctx = cache.get_or_fetch(&tenant_id, || async {
//! db.query("SELECT * FROM tenants WHERE id = $1", &[&tenant_id]).await
//! }).await?;
//! ```
// Core types
pub use ;
pub use ;
pub use TenantMiddleware;
pub use ;
pub use ;
// High-performance features
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;