Skip to main content

sz_orm_core/
lib.rs

1//! # SZ-ORM — Xianshida ORM
2//!
3//! Rust asynchronous ORM workspace (production-ready), ThinkORM-style compatible.
4//!
5//! **Production evidence**: 67 packages published to crates.io · 321 references in sz-pay production · 5159+ tests pass.
6//!
7//! ## Architecture Overview
8//!
9//! The SZ-ORM workspace consists of **71 members** (69 sz-orm-* libs + cli + examples):
10//!
11//! ### Core Engine (sz-orm-core)
12//! | Module | Function |
13//! |------|------|
14//! | `model` | `Model` trait — defines table name, primary key, timestamps, soft delete, relations |
15//! | `query` | `QueryBuilder<M>` — chainable API, supports SELECT/INSERT/UPDATE/DELETE/aggregation/pagination/JOIN |
16//! | `dialect` | Multi-database dialects — MySQL (backtick), PostgreSQL (double quote), SQLite, Oracle 23ai |
17//! | `pool` | Asynchronous connection pool — configurable size, timeout, idle reaping, health checks, max lifetime |
18//! | `transaction` | ACID transactions — isolation levels, savepoints, `TransactionManager` for multi-transaction management |
19//! | `migration` | File-based migration system — up/down/rollback/reset/refresh, with `SchemaBuilder` |
20//! | `cache` | Multi-level cache — `MemoryCache`, `MultiLevelCache`, with TTL support |
21//! | `value` | Unified value type — 20 variants (integer/float/string/bytes/UUID/date/JSON/array) |
22//! | `db_type` | Database type enum — MySQL, PostgreSQL, SQLite, Oracle, Redis, MongoDB and 11 total |
23//! | `error` | Error type system — `DbError` (20 variants), `PoolError`, `CacheError`, `TxError` |
24//!
25//! ### Database Adapters
26//! - **sz-orm-sqlx** — sqlx adapter, connects to real MySQL/PostgreSQL/SQLite/Oracle
27//! - **sz-orm-sql-validator** — SQL validation and injection detection
28//!
29//! ### Extension Ecosystem Packages (18)
30//! | Package | Function |
31//! |------|------|
32//! | sz-orm-crypto | Crypto primitives (AES-256-GCM, PBKDF2, HMAC-SHA256) |
33//! | sz-orm-auth | JWT authentication (HS256) |
34//! | sz-orm-scheduler | Cron scheduled task dispatch |
35//! | sz-orm-mqtt | MQTT client (rumqttc) |
36//! | sz-orm-websocket | WebSocket server (tokio-tungstenite) |
37//! | sz-orm-queue | Message queue (RabbitMQ/lapin, Kafka, NATS, ActiveMQ, RocketMQ, Pulsar) |
38//! | sz-orm-storage | Object storage (S3/Alibaba Cloud/Tencent Cloud/Huawei Cloud/Qiniu/Upyun/Local) |
39//! | sz-orm-ai | AI integration (Embedding, RAG, Vector) |
40//! | sz-orm-grpc | gRPC server/client |
41//! | sz-orm-graphql | GraphQL query support |
42//! | sz-orm-es | Elasticsearch integration |
43//! | sz-orm-tracing | Distributed tracing |
44//! | sz-orm-logger | Logging system |
45//! | sz-orm-swagger | API documentation generation |
46//! | sz-orm-masking | Data masking |
47//! | sz-orm-health | Health checks |
48//! | sz-orm-audit | Audit log |
49//! | sz-orm-batch | Batch operations |
50//!
51//! ### Advanced Feature Packages (6)
52//! | Package | Function |
53//! |------|------|
54//! | sz-orm-dtx | Distributed transactions |
55//! | sz-orm-rw | Read-write splitting |
56//! | sz-orm-sharding | Sharding |
57//! | sz-orm-limit | Rate limiting |
58//! | sz-orm-config | Configuration management |
59//! | sz-orm-mig | Enhanced migration management |
60//!
61//! ### Platform Support
62//! - **sz-orm-wasm** — WebAssembly compile target
63//! - **sz-orm-lc** — Local/edge computing
64//! - **sz-orm-back** — Backup and restore
65//!
66//! ## Quick Start
67//!
68//! ```rust,ignore
69//! use sz_orm_core::*;
70//!
71//! // 1. Define the model
72//! #[derive(Clone)]
73//! struct User {
74//!     id: i64,
75//!     name: String,
76//!     email: String,
77//! }
78//!
79//! impl Model for User {
80//!     type PrimaryKey = i64;
81//!     fn table_name() -> &'static str { "users" }
82//!     fn pk(&self) -> Self::PrimaryKey { self.id }
83//!     fn set_pk(&mut self, pk: Self::PrimaryKey) { self.id = pk; }
84//! }
85//!
86//! // 2. Build a query
87//! let dialect = get_dialect(DbType::MySQL).unwrap();
88//! let sql = QueryBuilder::<User>::new(dialect)
89//!     .table("users")
90//!     .select(vec!["id", "name", "email"])
91//!     .where_eq("status", Value::String("active".to_string()))
92//!     .order_by("created_at")
93//!     .order_desc("id")
94//!     .limit(10)
95//!     .build_select();
96//!
97//! // 3. Validate before execution
98//! QueryBuilder::<User>::new(get_dialect(DbType::MySQL).unwrap())
99//!     .table("users")
100//!     .select(vec!["id", "name"])
101//!     .validate()?; // Validate SQL syntax, injection, parenthesis balance
102//!
103//! // 4. Other operations
104//! let mut data = std::collections::HashMap::new();
105//! data.insert("name".to_string(), Value::String("Alice".to_string()));
106//! data.insert("age".to_string(), Value::I64(25));
107//!
108//! let insert_sql = QueryBuilder::<User>::new(dialect)
109//!     .table("users")
110//!     .build_insert(&data);
111//!
112//! let update_sql = QueryBuilder::<User>::new(get_dialect(DbType::MySQL).unwrap())
113//!     .table("users")
114//!     .where_eq("id", Value::I64(1))
115//!     .build_update(&data);
116//!
117//! let delete_sql = QueryBuilder::<User>::new(get_dialect(DbType::MySQL).unwrap())
118//!     .table("users")
119//!     .where_eq("id", Value::I64(1))
120//!     .build_delete();
121//! ```
122//!
123//! ## Supported Databases
124//!
125//! | Database | Dialect Implementation | Real Connection | Quoting |
126//! |--------|---------|---------|---------|
127//! | MySQL | `MySqlDialect` (`` ` `` backtick) | sz-orm-sqlx | ✅ |
128//! | PostgreSQL | `PostgreSqlDialect` (`"` double quote) | sz-orm-sqlx | ✅ |
129//! | SQLite 3.35+ | `SqliteDialect` (`"` double quote) | sz-orm-sqlx | ✅ |
130//! | Oracle 23ai | `OracleDialect` (automatic type mapping) | sz-orm-sqlx | ✅ |
131//!
132//! Obtain a dialect instance via `get_dialect(DbType::MySQL)`. Each dialect handles:
133//! - Identifier quoting style
134//! - String escaping rules
135//! - Pagination syntax (LIMIT/OFFSET vs OFFSET/FETCH)
136//! - JSON extraction functions (JSON_EXTRACT vs #>> vs json_extract vs JSON_VALUE)
137//! - Full-text search (MATCH AGAINST vs to_tsvector vs CONTAINS)
138//! - Boolean-to-integer conversion (IF/CASE)
139//! - Auto-increment keyword (AUTO_INCREMENT/GENERATED BY DEFAULT AS IDENTITY)
140//!
141//! ## Core Features in Detail
142//!
143//! ### QueryBuilder API
144//!
145//! Most query methods return `Self`, enabling chainable calls; validation methods like `select`/`having`
146//! return `Result<Self>` (after audit M-5/M-6, column names/aggregate expressions go through identifier validation):
147//!
148//! ```rust,ignore
149//! // Basic query
150//! QueryBuilder::<M>::new(dialect)
151//!     .table("users")
152//!     .select(vec!["id", "name"])?                 // Column validation + quote
153//!     .where_eq("status", Value::String("active".to_string()))    // AND
154//!     .or_where_eq("role", Value::String("admin".to_string()))     // OR
155//!     .where_in("id", vec![Value::I64(1), Value::I64(2)])
156//!     .where_between("age", Value::I64(18), Value::I64(30))
157//!     .where_null("deleted_at")
158//!     .order_by("created_at")
159//!     .order_desc("id")
160//!     .group_by("status")
161//!     .having(AggExpr::CountStar, HavingOp::Gt, Value::I64(5))?   // Parameterized HAVING
162//!     .limit(20)
163//!     .offset(40)
164//!     .page(3, 20)                       // page=3, page_size=20
165//!     .join_inner("posts", "users.id", "posts.user_id")
166//!     .join_left("profiles", "users.id", "profiles.user_id")
167//!     .build_select();
168//!
169//! // Aggregate functions
170//! builder.build_count();    // SELECT COUNT(*)
171//! builder.build_exists();   // SELECT EXISTS(...)
172//! builder.build_max("score");
173//! builder.build_min("price");
174//! builder.build_sum("amount");
175//! builder.build_avg("value");
176//! ```
177//!
178//! ### SQL Validation
179//!
180//! ```rust,ignore
181//! // Compile-time + runtime dual validation
182//! builder.validate()?;              // Validate SELECT
183//! builder.validate_insert(&data)?;  // Validate INSERT (including empty data check)
184//! builder.validate_update(&data)?;  // Validate UPDATE (including empty data check)
185//! builder.validate_delete()?;       // Validate DELETE
186//!
187//! // Validation covers: SQL syntax, injection detection, parenthesis balance,
188//! // table/column name legitimacy, JOIN column validation
189//! ```
190//!
191//! ### Model Trait
192//!
193//! ```rust,ignore
194//! pub trait Model: Send + Sync + Sized + 'static {
195//!     type PrimaryKey: Send + Sync + Debug + Display + Clone + Default;
196//!
197//!     fn table_name() -> &'static str;          // Table name (required)
198//!     fn pk_name() -> &'static str { "id" }     // Primary key column name
199//!     fn pk(&self) -> Self::PrimaryKey;         // Get primary key value
200//!     fn set_pk(&mut self, pk: Self::PrimaryKey); // Set primary key value
201//!     fn foreign_key(relation: &str) -> String; // Foreign key naming "user_id"
202//!     fn timestamp_fields() -> Option<TimestampFields>; // Automatic timestamps
203//!     fn soft_delete_field() -> Option<&'static str>;   // Soft delete field
204//! }
205//!
206//! // ModelExt extension
207//! pub trait ModelExt: Model {
208//!     fn columns() -> Vec<&'static str>;     // All columns
209//!     fn fillable() -> Vec<&'static str>;    // Fillable columns
210//!     fn guarded() -> Vec<&'static str>;     // Guarded columns (includes primary key by default)
211//!     fn hidden() -> Vec<&'static str>;      // Hidden columns (not serialized)
212//!     fn relations() -> HashMap<&str, Relation>; // Relations
213//!     fn fill(&mut self, data: HashMap<String, Value>); // Mass assignment
214//!     fn to_json(&self) -> serde_json::Value; // Serialize
215//! }
216//!
217//! // Four relation types
218//! // BelongsTo   — many-to-one (Order → User)
219//! // HasMany     — one-to-many (User → Orders)
220//! // HasOne      — one-to-one (User → Profile)
221//! // BelongsToMany — many-to-many (User ↔ Role, through junction table)
222//! ```
223//!
224//! ### Connection Pool
225//!
226//! ```rust,ignore
227//! // Configure via Builder
228//! let config = PoolConfigBuilder::new()
229//!     .max_size(100)       // Maximum connections
230//!     .min_idle(10)        // Minimum idle connections
231//!     .acquire_timeout(30) // Acquire timeout (seconds)
232//!     .idle_timeout(600)   // Idle timeout (seconds)
233//!     .max_lifetime(1800)  // Max lifetime (seconds)
234//!     .build()?;
235//!
236//! let pool = Pool::new(config, factory)?;
237//! let conn = pool.acquire().await?;  // Acquire connection (with timeout)
238//! pool.release(conn).await;         // Release connection
239//! pool.status().await;               // PoolStatus { idle, active, max, min }
240//! pool.reap_idle().await;           // Reap idle connections
241//! pool.close_all().await;           // Close all connections
242//! ```
243//!
244//! ### Transactions
245//!
246//! ```rust,ignore
247//! // Transaction options
248//! let opts = TransactOptions::default()
249//!     .with_isolation(IsolationLevel::Serializable)
250//!     .read_only()
251//!     .with_timeout(Duration::from_secs(30));
252//!
253//! let mut tx = Transaction::new(conn, opts);
254//! tx.execute("INSERT INTO users VALUES (1)").await?;
255//! tx.query("SELECT * FROM users").await?;
256//!
257//! // Savepoints (nested transactions)
258//! let sp = tx.savepoint().await?;         // SAVEPOINT sp_N
259//! tx.rollback_to_savepoint(&sp).await?;   // ROLLBACK TO SAVEPOINT sp_N
260//! tx.release_savepoint(&sp).await?;       // RELEASE SAVEPOINT sp_N
261//!
262//! tx.commit().await?;
263//! // tx.rollback().await?;
264//!
265//! // TransactionManager: manages multiple named transactions
266//! let mgr = TransactionManager::new();
267//! mgr.begin("tx1", conn, opts).await?;
268//! mgr.commit("tx1").await?;
269//! mgr.list().await;        // ["tx1"]
270//! mgr.state("tx1").await;  // Some(TransactionState::Committed)
271//! ```
272//!
273//! ### Migration System
274//!
275//! ```rust,ignore
276//! // File naming: <version>_<name>_up.sql / <version>_<name>_down.sql
277//! // Example: 001_create_users_up.sql, 001_create_users_down.sql
278//!
279//! let resolver = FileMigrationResolver::new(PathBuf::from("./migrations"));
280//! let migrations = resolver.resolve(DbType::MySQL)?;
281//!
282//! let mut migrator = Migrator::new(MigrationContext::default())
283//!     .add_migrations(migrations);
284//!
285//! migrator.migrate().await?;                     // Execute all pending migrations
286//! migrator.up(Some("003")).await?;               // Migrate up to specified version
287//! migrator.down(Some("001")).await?;             // Rollback to specified version
288//! migrator.rollback("002").await?;               // Rollback a single migration
289//! migrator.reset().await?;                       // Rollback all + re-execute
290//! migrator.refresh().await?;                     // Same as reset
291//! migrator.progress();                            // MigrationProgress { total, applied, pending }
292//!
293//! // SchemaBuilder: programmatic table creation
294//! let sql = SchemaBuilder::new("users")
295//!     .add_column(ColumnDef::new("id", "INT").not_null().auto_increment())
296//!     .add_column(ColumnDef::new("name", "VARCHAR").length(255).not_null())
297//!     .add_index(IndexDef::new("idx_name", vec!["name"]).unique())
298//!     .add_foreign_key(
299//!         ForeignKeyDef::new("fk_role", "role_id", "roles", "id")
300//!             .on_delete("CASCADE")
301//!     )
302//!     .build(DbType::MySQL);
303//! ```
304//!
305//! ### Value Type
306//!
307//! ```rust,ignore
308//! // 20 variants, covering all database types
309//! Value::Null | Bool(bool) | I8..I64 | U8..U64 | F32 | F64
310//! | String(String) | Bytes(Vec<u8>) | Uuid(String) | Date(String)
311//! | DateTime(String) | Time(String) | Json(String) | Array(Vec<Value>)
312//!
313//! // Type conversions
314//! value.as_str()    // Option<&str>
315//! value.as_i64()    // Option<i64> (supports F32/F64/Bool/String→i64 conversion)
316//! value.as_f64()    // Option<f64>
317//! value.as_bool()   // Option<bool> (supports "true"/"1"/"yes"/"on" etc.)
318//! value.as_bytes()  // Option<&[u8]>
319//! value.to_param()  // Cow<str> — SQL parameter format
320//!
321//! // From implementations
322//! let v: Value = 42i64.into();
323//! let v: Value = "hello".into();
324//! let v: Value = vec![1u8, 2u8].into();
325//! ```
326//!
327//! ## Error Handling
328//!
329//! Unified error type system, each error carries a unique error code:
330//!
331//! ```rust,ignore
332//! // DbError — 20 variants, error codes DB001-DB020
333//! DbError::QueryError("...")
334//! DbError::ConnectionRefused("...")
335//! DbError::ConnectionTimeout("...")
336//! DbError::NotFound("...")
337//! DbError::ConstraintViolation("...")
338//! // ... etc.
339//!
340//! // PoolError — 6 variants, error codes PL001-PL006
341//! PoolError::Exhausted | Timeout | AlreadyAcquired | InvalidConfig | ...
342//!
343//! // CacheError — 6 variants, error codes CH001-CH006
344//! // TxError — 6 variants (NotStarted, CommitFailed, SavepointError, etc.)
345//!
346//! // Convenience methods
347//! DbError::query("test failed")        // Create query error
348//! DbError::connection("timeout")       // Create connection error
349//! DbError::not_found("user #42")       // Create not-found error
350//! err.is_retryable()                   // Whether retryable
351//! err.error_code()                     // "DB001"
352//! ```
353//!
354//! ## Validation Methods
355//!
356//! SZ-ORM ensures quality through a **7-layer validation system**:
357//!
358//! | Method | Description | Test File |
359//! |---------|------|---------|
360//! | **TDD** | 115+ unit tests for core modules | `core.rs` |
361//! | **Integration** | End-to-end with real MySQL/PG/SQLite/Oracle | `integration_mysql.rs`, `integration_pg.rs`, `integration_sqlite.rs` |
362//! | **Jepsen** | 29 concurrency correctness tests + 10 real DB Jepsen | `jepsen.rs`, `real_db_jepsen.rs` |
363//! | **Fuzz** | 11 boundary/edge case discoveries | `fuzz.rs` |
364//! | **Stress** | 77 performance benchmarks | `stress.rs`, `core_bench.rs` |
365//! | **Chaos** | 16 fault robustness tests | `chaos.rs` |
366//! | **Formal** | 14 formal verification invariants | `formal.rs` |
367//!
368//! **Total: 1,723 tests** (1,317 `#[test]` + 406 `#[tokio::test]`; some require real services)
369//!
370//! ## Type Aliases and Constants
371//!
372//! ```rust,ignore
373//! // Type aliases
374//! pub type Shared<T> = Arc<T>;
375//! pub type Boxed<T> = Box<T>;
376//! pub type DbResult<T> = Result<T, DbError>;
377//! pub type PoolResult<T> = Result<T, PoolError>;
378//! pub type CacheResult<T> = Result<T, CacheError>;
379//! pub type TxResult<T> = Result<T, TxError>;
380//!
381//! // Default constants
382//! pub const DEFAULT_BATCH_SIZE: usize = 1000;
383//! pub const DEFAULT_ACQUIRE_TIMEOUT: u64 = 30;   // seconds
384//! pub const DEFAULT_IDLE_TIMEOUT: u64 = 600;      // seconds
385//! pub const DEFAULT_MAX_LIFETIME: u64 = 1800;     // seconds
386//! pub const DEFAULT_MIN_IDLE: u32 = 5;
387//! pub const DEFAULT_MAX_SIZE: u32 = 100;
388//! ```
389//!
390//! ## Export Manifest
391//!
392//! `use sz_orm_core::*;` imports all public symbols from the following modules:
393//!
394//! - `async_trait` (re-exported), `bytes::Bytes`, `chrono::{DateTime, Utc}`, `serde::{Deserialize, Serialize}`
395//! - `cache::*` — `Cache`, `MemoryCache`, `MultiLevelCache`, `CacheStats`
396//! - `db_type::*` — `DbType` enum (11 database types)
397//! - `dialect::*` — `Dialect`, `MySqlDialect`, `PostgreSqlDialect`, `SqliteDialect`, `OracleDialect`, `get_dialect()`
398//! - `error::*` — `DbError`, `PoolError`, `CacheError`, `TxError`
399//! - `migration::*` — `Migration`, `Migrator`, `SchemaBuilder`, `ColumnDef`, `IndexDef`, `ForeignKeyDef`
400//! - `model::*` — `Model`, `ModelExt`, `Relation`, `BelongsTo`, `HasMany`, `HasOne`, `BelongsToMany`
401//! - `pool::*` — `Pool`, `PoolConfig`, `PoolConfigBuilder`, `Connection`, `ConnectionFactory`, `PoolStatus`
402//! - `query::*` — `QueryBuilder<M>` (chainable SQL builder)
403//! - `transaction::*` — `Transaction`, `TransactionManager`, `TransactOptions`, `IsolationLevel`
404//! - `value::*` — `Value` enum (20 variants)
405
406// 文档完整性:全局启用 missing_docs lint(v3.6.0 已补齐全部 pub API 文档)
407#![warn(missing_docs)]
408
409// v3.9.0 M1-T3:derive(Validate) 宏生成 sz_orm_core 绝对路径,
410// crate 内部测试需 self 别名使该路径解析到当前 crate
411#[cfg(test)]
412extern crate self as sz_orm_core;
413
414use std::sync::Arc;
415
416/// Re-export async traits
417pub use async_trait::async_trait;
418
419/// Re-export common types
420pub use bytes::Bytes;
421pub use chrono::{DateTime, Utc};
422pub use serde::{Deserialize, Serialize};
423
424pub mod access_control;
425pub mod accessors;
426pub mod active_model;
427#[allow(missing_docs)]
428pub mod api_coverage;
429pub mod behaviors;
430#[cfg(feature = "benchmark-suite")]
431pub mod benchmark;
432pub mod bloom;
433mod cache;
434pub mod change_tracker;
435pub mod circuit_breaker;
436#[cfg(feature = "circuit-breaker")]
437#[allow(missing_docs)]
438pub mod degradation;
439#[allow(missing_docs)]
440pub mod binding_coverage;
441#[cfg(feature = "type-safe-columns")]
442pub mod column;
443#[cfg(feature = "zero-copy")]
444pub mod columnar;
445#[cfg(any(
446    feature = "prepared-stmt-cache",
447    feature = "async-row-stream",
448    feature = "parallel-batch"
449))]
450pub mod connection_ext;
451pub mod cursor_stream;
452pub mod cycle_detection;
453pub mod data_permission;
454mod db_type;
455pub mod dialect;
456#[cfg(feature = "prod-dialect-security")]
457pub mod dialect_security;
458pub mod dirty_attributes;
459#[cfg(feature = "dist-cache")]
460pub mod dist_cache;
461#[cfg(feature = "dist-cache-cluster")]
462#[allow(missing_docs)]
463pub mod dist_cache_cluster;
464pub mod dynamic_filter;
465pub mod dynamic_sql;
466pub mod eager_loader;
467pub mod entity_graph;
468mod error;
469pub mod find_with_related;
470#[cfg(feature = "compile-governance")]
471pub mod governance;
472pub mod guard;
473pub mod hooks;
474#[cfg(feature = "composable-plugin")]
475pub use hooks::{ExtensionHandler, ExtensionPoint, ExtensionPointRegistry};
476pub mod hydration_plugin;
477pub mod i18n;
478pub mod join_dsl;
479pub mod json_query;
480#[cfg(feature = "l1-cache")]
481pub mod l1_cache;
482pub mod l2_cache;
483pub mod lambda;
484pub mod lazy_loader;
485pub mod linq;
486pub mod migration;
487#[cfg(feature = "migration-dry-run")]
488pub mod migration_dry_run;
489pub mod mock;
490mod model;
491#[cfg(feature = "multi-tenant-pool")]
492#[allow(missing_docs)]
493pub mod multi_tenant_pool;
494pub mod n1_eliminator;
495pub mod nested_active_model;
496pub mod observer;
497pub mod optimistic_lock;
498pub mod paginator;
499pub mod partial_model;
500pub mod phinx_migration;
501#[cfg(feature = "plan-cache")]
502pub mod plan_cache;
503pub mod plugin;
504#[cfg(feature = "composable-plugin")]
505pub use plugin::{MiddlewareChain, PanicSafeRegistry, PluginSigner, PluginState, SignatureStatus};
506mod pool;
507#[cfg(feature = "prepared-stmt-cache")]
508pub mod prepared_cache;
509#[cfg(feature = "auto-prewarm")]
510pub mod prewarm;
511#[cfg(feature = "prod-ready")]
512pub mod prod_ready_check;
513mod query;
514pub mod query_cache;
515#[cfg(feature = "query-result-cache")]
516#[allow(missing_docs)]
517pub mod query_result_cache;
518#[cfg(feature = "async-row-stream")]
519pub mod row_stream;
520#[cfg(feature = "rw-split-enhanced")]
521#[allow(missing_docs)]
522pub mod rw_split_enhanced;
523#[cfg(feature = "saga-tx")]
524#[allow(missing_docs)]
525pub mod saga;
526
527#[cfg(feature = "pool-elastic")]
528#[allow(missing_docs)]
529pub mod pool_elastic;
530
531#[cfg(feature = "serverless-adapt")]
532pub use pool_elastic::{
533    CdcCheckpoint, GracefulShutdown, GracefulShutdownConfig, ShutdownError, ShutdownResult,
534};
535#[cfg(feature = "serverless-adapt")]
536pub use prewarm::{ColdStartOptimizer, ColdStartStats};
537
538#[cfg(feature = "io-uring")]
539#[allow(missing_docs)]
540 pub mod io_uring_probe;
541
542/// v7.6.0 任务 1.4:IO_uring 异步 IO 集成
543#[cfg(feature = "io-uring")]
544#[allow(missing_docs)]
545pub mod io_uring_io;
546
547#[cfg(feature = "field-encryption")]
548#[allow(missing_docs)]
549pub mod field_cipher;
550#[cfg(feature = "tde-interceptor")]
551pub use field_cipher::{TdeError, TdeInterceptor};
552#[cfg(feature = "tde-interceptor")]
553pub use sz_orm_crypto::{
554    ColumnCryptoConfig, ColumnEncryptionPolicy, DekBuffer, EncryptionAlgo, KmsClient,
555    LocalKmsClient,
556};
557
558#[cfg(feature = "data-validation")]
559pub mod validation;
560/// Re-export QueryBuilder for external use
561pub use query::QueryBuilder;
562#[cfg(feature = "adaptive-query")]
563pub mod adaptive_adapter;
564#[cfg(feature = "cache-coherence")]
565pub mod cache_coherence;
566#[cfg(feature = "l1-cache")]
567#[allow(missing_docs)]
568pub mod cache_warmup_protection;
569#[cfg(feature = "config-center")]
570pub mod config_adapter;
571#[cfg(feature = "connection-level-tenant")]
572pub mod connection_tenant;
573#[cfg(feature = "forward-compat-sandbox")]
574#[allow(missing_docs)]
575pub mod forward_compat_sandbox;
576#[cfg(feature = "graph")]
577pub mod graph_adapter;
578#[cfg(feature = "graphql")]
579pub mod graphql_adapter;
580#[cfg(feature = "structured-logging")]
581pub mod logger_adapter;
582#[cfg(feature = "postgis")]
583pub mod postgis_adapter;
584#[cfg(feature = "read-write-splitting")]
585pub mod rw_adapter;
586#[cfg(feature = "search")]
587pub mod search_adapter;
588#[cfg(feature = "timeseries")]
589pub mod timeseries_adapter;
590#[cfg(feature = "distributed-tracing")]
591pub mod tracing_adapter;
592
593#[cfg(feature = "migration-branch")]
594pub mod migration_branch;
595#[cfg(feature = "l1-cache")]
596pub mod process_l1_cache;
597#[cfg(feature = "qb-migration-tool")]
598pub mod qb_migration_fix;
599#[cfg(feature = "qb-migration-tool")]
600pub mod qb_migration_lint;
601pub mod queryable;
602pub mod quick_query;
603pub mod rate_limiter;
604pub mod relation_trait;
605pub mod repository;
606pub mod result_map;
607pub mod retry;
608#[cfg(feature = "zero-downtime-rollback")]
609pub mod rollback_zero_downtime;
610#[cfg(feature = "schema-diff-viz")]
611pub mod schema_diff_viz;
612pub mod schema_gen;
613pub mod schema_sync;
614#[cfg(feature = "data-seeding")]
615pub mod seeding;
616pub mod select_types;
617pub mod shadow;
618#[cfg(feature = "simd")]
619pub mod simd;
620pub mod smart_eager_loader;
621pub mod sql_buffer;
622pub mod sql_safety;
623#[cfg(feature = "sql-verify-proc")]
624pub mod sql_verify;
625pub mod stream_api;
626#[cfg(feature = "streaming-export")]
627pub mod streaming_export;
628pub mod telemetry;
629#[cfg(feature = "multi-tenant-enhanced")]
630pub mod tenant_context;
631#[cfg(feature = "tenant-quota-rls-enhanced")]
632#[allow(missing_docs)]
633pub mod tenant_quota_rls;
634#[cfg(feature = "multi-tenant-enhanced")]
635pub mod tenant_security;
636mod transaction;
637pub mod type_handler;
638pub mod typed;
639pub mod typed_ast;
640#[cfg(feature = "typed-relation")]
641pub mod typed_relation;
642mod value;
643#[cfg(feature = "zero-copy")]
644pub mod value_borrowed;
645#[cfg(feature = "zero-copy-deep")]
646#[allow(missing_docs)]
647pub mod zero_copy_pipeline;
648
649// v7.4.0 任务 3.5:性能指标暴露(perf_metrics 模块始终可用)
650pub mod perf_metrics;
651
652#[cfg(any(
653    feature = "cdc-mysql",
654    feature = "cdc-postgres",
655    feature = "cdc-sqlite",
656    feature = "cdc-realtime-sync"
657))]
658#[allow(missing_docs)]
659pub mod cdc;
660
661#[cfg(feature = "rbac-abac-enhanced")]
662#[allow(missing_docs)]
663pub mod column_mask_interceptor;
664
665#[cfg(feature = "rbac-abac-enhanced")]
666#[allow(missing_docs)]
667pub mod row_level_policy;
668
669#[cfg(feature = "olap-vectorized")]
670#[allow(missing_docs)]
671pub mod olap;
672
673#[cfg(feature = "executor-opt")]
674#[allow(missing_docs)]
675pub mod executor_passes;
676
677// Re-export proc macros
678pub use queryable::Query;
679pub use queryable::QueryAs;
680pub use sz_orm_macros::api_beta;
681pub use sz_orm_macros::api_stable;
682pub use sz_orm_macros::migrate;
683pub use sz_orm_macros::query;
684pub use sz_orm_macros::query_as;
685pub use sz_orm_macros::schema;
686pub use sz_orm_macros::sql_string;
687pub use sz_orm_macros::typed_query;
688// FromQueryResult derive 宏(与 value.rs 中同名 trait 通过显式 use 遮蔽 glob 导出)
689#[cfg(feature = "n1-lint")]
690pub use sz_orm_macros::detect_n_plus_one;
691pub use sz_orm_macros::FromQueryResult;
692pub use sz_orm_macros::RelationTrait;
693#[cfg(feature = "data-validation")]
694pub use sz_orm_macros::Validate;
695
696pub use change_tracker::{ChangeTracker, EntityEntry, EntityState};
697pub use lazy_loader::{LazyCollection, LazyLoader, LazyRef};
698pub use linq::LinqQuery;
699pub use query_cache::{QueryCache, QueryCacheKey, TimestampCache};
700
701pub use cache::*;
702pub use cycle_detection::{CycleDetector, CyclePolicy};
703pub use db_type::*;
704#[allow(ambiguous_glob_reexports)]
705pub use dialect::*;
706pub use eager_loader::NestedEagerResult;
707pub use error::*;
708#[allow(ambiguous_glob_reexports)]
709pub use migration::*;
710pub use model::*;
711pub use nested_active_model::CascadeStrategy;
712pub use pool::*;
713#[allow(unused_imports)]
714pub use query::*;
715pub use schema_sync::{Confirm, DataMigrationHook, DestructiveSyncResult};
716pub use transaction::*;
717pub use value::*;
718
719/// Alias for `Arc<T>`
720pub type Shared<T> = Arc<T>;
721
722/// Alias for `Box<T>`
723pub type Boxed<T> = Box<T>;
724
725/// Alias for Result<T, DbError>
726pub type DbResult<T> = Result<T, DbError>;
727
728/// Result type for pool operations
729pub type PoolResult<T> = Result<T, PoolError>;
730
731/// Result type for cache operations
732pub type CacheResult<T> = Result<T, CacheError>;
733
734/// Result type for transaction operations
735pub type TxResult<T> = Result<T, TxError>;
736
737/// Default batch size for bulk operations
738pub const DEFAULT_BATCH_SIZE: usize = 1000;
739
740/// Default connection timeout in seconds
741pub const DEFAULT_ACQUIRE_TIMEOUT: u64 = 30;
742
743/// Default idle timeout in seconds
744pub const DEFAULT_IDLE_TIMEOUT: u64 = 600;
745
746/// Default max lifetime in seconds
747pub const DEFAULT_MAX_LIFETIME: u64 = 1800;
748
749/// Default minimum idle connections
750pub const DEFAULT_MIN_IDLE: u32 = 5;
751
752/// Default maximum pool size
753pub const DEFAULT_MAX_SIZE: u32 = 100;
754
755// ============================================================================
756// v7.3.0 性能加速配置与指标聚合(perf-accel feature gate)
757// ============================================================================
758
759/// 性能加速配置(v7.3.0)
760///
761/// 统一驱动 SIMD 向量化、零拷贝序列化、连接池预热、查询计划缓存四项加速能力。
762/// 所有加速开关默认 false(plan_cache_enabled 默认 true 保持既有行为),
763/// 不改变 v7.2.0 既有行为。
764#[cfg(feature = "perf-accel")]
765#[derive(Debug, Clone)]
766pub struct PerfConfig {
767    /// 是否启用 SIMD 向量化加速
768    pub simd_enabled: bool,
769    /// SIMD 批量处理最低行数阈值(低于此值走标量路径)
770    pub simd_row_threshold: usize,
771    /// 是否启用零拷贝序列化
772    pub zero_copy_enabled: bool,
773    /// 是否启用连接池预热
774    pub prewarm_enabled: bool,
775    /// 预热连接数
776    pub prewarm_count: usize,
777    /// 是否启用查询计划缓存
778    pub plan_cache_enabled: bool,
779    /// 计划缓存容量
780    pub plan_cache_capacity: usize,
781    /// 计划缓存 TTL(毫秒)
782    pub plan_cache_ttl_ms: u64,
783}
784
785#[cfg(feature = "perf-accel")]
786impl Default for PerfConfig {
787    fn default() -> Self {
788        Self {
789            simd_enabled: false,
790            simd_row_threshold: 1024,
791            zero_copy_enabled: false,
792            prewarm_enabled: false,
793            prewarm_count: 1,
794            plan_cache_enabled: true,
795            plan_cache_capacity: 256,
796            plan_cache_ttl_ms: 300_000,
797        }
798    }
799}
800
801#[cfg(feature = "perf-accel")]
802impl PerfConfig {
803    /// 校验配置合法性
804    pub fn validate(&self) -> Result<(), DbError> {
805        if self.simd_row_threshold < 1 {
806            return Err(DbError::ConfigError(
807                "simd_row_threshold must be >= 1".to_string(),
808            ));
809        }
810        if self.prewarm_count < 1 {
811            return Err(DbError::ConfigError(
812                "prewarm_count must be >= 1".to_string(),
813            ));
814        }
815        if self.plan_cache_capacity < 1 {
816            return Err(DbError::ConfigError(
817                "plan_cache_capacity must be >= 1".to_string(),
818            ));
819        }
820        if self.plan_cache_ttl_ms == 0 {
821            return Err(DbError::ConfigError(
822                "plan_cache_ttl_ms must be > 0".to_string(),
823            ));
824        }
825        Ok(())
826    }
827
828    /// 创建 builder
829    pub fn builder() -> PerfConfigBuilder {
830        PerfConfigBuilder::default()
831    }
832}
833
834/// 性能加速配置 builder(v7.3.0)
835#[cfg(feature = "perf-accel")]
836#[derive(Debug, Clone, Default)]
837pub struct PerfConfigBuilder {
838    config: PerfConfig,
839}
840
841#[cfg(feature = "perf-accel")]
842impl PerfConfigBuilder {
843    /// 设置 SIMD 启用
844    pub fn simd(mut self, enabled: bool) -> Self {
845        self.config.simd_enabled = enabled;
846        self
847    }
848
849    /// 设置 SIMD 行阈值
850    pub fn simd_row_threshold(mut self, threshold: usize) -> Self {
851        self.config.simd_row_threshold = threshold;
852        self
853    }
854
855    /// 设置零拷贝启用
856    pub fn zero_copy(mut self, enabled: bool) -> Self {
857        self.config.zero_copy_enabled = enabled;
858        self
859    }
860
861    /// 设置预热启用
862    pub fn prewarm(mut self, enabled: bool) -> Self {
863        self.config.prewarm_enabled = enabled;
864        self
865    }
866
867    /// 设置预热连接数
868    pub fn prewarm_count(mut self, count: usize) -> Self {
869        self.config.prewarm_count = count;
870        self
871    }
872
873    /// 设置计划缓存启用
874    pub fn plan_cache(mut self, enabled: bool) -> Self {
875        self.config.plan_cache_enabled = enabled;
876        self
877    }
878
879    /// 设置计划缓存容量
880    pub fn plan_cache_capacity(mut self, capacity: usize) -> Self {
881        self.config.plan_cache_capacity = capacity;
882        self
883    }
884
885    /// 设置计划缓存 TTL(毫秒)
886    pub fn plan_cache_ttl_ms(mut self, ttl_ms: u64) -> Self {
887        self.config.plan_cache_ttl_ms = ttl_ms;
888        self
889    }
890
891    /// 构建配置(校验合法性)
892    pub fn build(self) -> Result<PerfConfig, DbError> {
893        self.config.validate()?;
894        Ok(self.config)
895    }
896}
897
898/// 性能加速指标快照(v7.3.0)
899#[cfg(feature = "perf-accel")]
900#[derive(Debug, Clone, Default)]
901pub struct PerfMetricsSnapshot {
902    /// SIMD 命中次数
903    pub simd_hit_count: u64,
904    /// SIMD 未命中次数
905    pub simd_miss_count: u64,
906    /// SIMD 延迟降低百分比
907    pub simd_latency_reduction_pct: f64,
908    /// 零拷贝命中次数
909    pub zero_copy_hit_count: u64,
910    /// 零拷贝 RSS 降低百分比
911    pub zero_copy_rss_reduction_pct: f64,
912    /// 预热成功次数
913    pub prewarm_success_count: u64,
914    /// 计划缓存命中率
915    pub plan_cache_hit_rate: f64,
916    /// 计划缓存淘汰次数
917    pub plan_cache_eviction_count: u64,
918}
919
920/// 性能加速指标聚合(v7.3.0)
921///
922/// 使用无锁原子计数器采集 SIMD/零拷贝/预热/计划缓存四项加速能力的运行指标。
923#[cfg(feature = "perf-accel")]
924#[derive(Debug, Default)]
925pub struct PerfMetrics {
926    simd_hit_count: std::sync::atomic::AtomicU64,
927    simd_miss_count: std::sync::atomic::AtomicU64,
928    simd_latency_reduction_pct: std::sync::atomic::AtomicU64,
929    zero_copy_hit_count: std::sync::atomic::AtomicU64,
930    zero_copy_rss_reduction_pct: std::sync::atomic::AtomicU64,
931    prewarm_success_count: std::sync::atomic::AtomicU64,
932    plan_cache_hit_rate: std::sync::atomic::AtomicU64,
933    plan_cache_eviction_count: std::sync::atomic::AtomicU64,
934}
935
936#[cfg(feature = "perf-accel")]
937impl PerfMetrics {
938    /// 创建新的指标实例
939    pub fn new() -> Self {
940        Self::default()
941    }
942
943    /// 记录 SIMD 命中
944    pub fn record_simd_hit(&self) {
945        self.simd_hit_count
946            .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
947    }
948
949    /// 记录 SIMD 未命中
950    pub fn record_simd_miss(&self) {
951        self.simd_miss_count
952            .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
953    }
954
955    /// 记录零拷贝命中
956    pub fn record_zero_copy_hit(&self) {
957        self.zero_copy_hit_count
958            .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
959    }
960
961    /// 记录预热成功
962    pub fn record_prewarm_success(&self) {
963        self.prewarm_success_count
964            .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
965    }
966
967    /// 记录计划缓存淘汰
968    pub fn record_plan_cache_eviction(&self) {
969        self.plan_cache_eviction_count
970            .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
971    }
972
973    /// 设置 SIMD 延迟降低百分比
974    pub fn set_simd_latency_reduction_pct(&self, pct: f64) {
975        self.simd_latency_reduction_pct
976            .store(pct.to_bits(), std::sync::atomic::Ordering::Relaxed);
977    }
978
979    /// 设置零拷贝 RSS 降低百分比
980    pub fn set_zero_copy_rss_reduction_pct(&self, pct: f64) {
981        self.zero_copy_rss_reduction_pct
982            .store(pct.to_bits(), std::sync::atomic::Ordering::Relaxed);
983    }
984
985    /// 设置计划缓存命中率
986    pub fn set_plan_cache_hit_rate(&self, rate: f64) {
987        self.plan_cache_hit_rate
988            .store(rate.to_bits(), std::sync::atomic::Ordering::Relaxed);
989    }
990
991    /// 采集指标快照
992    pub fn snapshot(&self) -> PerfMetricsSnapshot {
993        let o = std::sync::atomic::Ordering::Relaxed;
994        PerfMetricsSnapshot {
995            simd_hit_count: self.simd_hit_count.load(o),
996            simd_miss_count: self.simd_miss_count.load(o),
997            simd_latency_reduction_pct: f64::from_bits(self.simd_latency_reduction_pct.load(o)),
998            zero_copy_hit_count: self.zero_copy_hit_count.load(o),
999            zero_copy_rss_reduction_pct: f64::from_bits(self.zero_copy_rss_reduction_pct.load(o)),
1000            prewarm_success_count: self.prewarm_success_count.load(o),
1001            plan_cache_hit_rate: f64::from_bits(self.plan_cache_hit_rate.load(o)),
1002            plan_cache_eviction_count: self.plan_cache_eviction_count.load(o),
1003        }
1004    }
1005}
1006
1007// ============================================================================
1008// v7.3.0 高可用配置聚合(auto-failover feature gate)
1009// ============================================================================
1010
1011/// 回切策略(v7.3.0)
1012///
1013/// - `Manual`:故障转移后等待运维确认再回切
1014/// - `Auto`:经健康+一致性校验后自动回切
1015#[cfg(feature = "auto-failover")]
1016#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1017pub enum FailbackStrategy {
1018    /// 等待运维确认再回切
1019    Manual,
1020    /// 经健康+一致性校验后自动回切
1021    Auto,
1022}
1023
1024/// 故障转移配置(v7.3.0)
1025///
1026/// 凭证经既有配置加密链路加载(禁止明文)。
1027#[cfg(feature = "auto-failover")]
1028#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1029pub struct FailoverConfig {
1030    /// 主库连接 URL(已加密,运行时解密)
1031    pub primary_url: String,
1032    /// 备库连接 URL(已加密,运行时解密)
1033    pub replica_url: String,
1034    /// 探活间隔(必须 ≤ 5s 以保证 RTO ≤ 5s)
1035    pub probe_interval: std::time::Duration,
1036    /// 连续探活失败多少次触发故障转移(默认 3)
1037    pub probe_failure_threshold: u32,
1038    /// 回切策略
1039    pub failback_strategy: FailbackStrategy,
1040}
1041
1042#[cfg(feature = "auto-failover")]
1043impl Default for FailoverConfig {
1044    fn default() -> Self {
1045        Self {
1046            primary_url: String::new(),
1047            replica_url: String::new(),
1048            probe_interval: std::time::Duration::from_secs(1),
1049            probe_failure_threshold: 3,
1050            failback_strategy: FailbackStrategy::Manual,
1051        }
1052    }
1053}
1054
1055/// 高可用配置聚合(v7.3.0)
1056///
1057/// 统一驱动故障转移、限流熔断、健康检查、追踪四项高可用能力。
1058/// `failover_enabled` 默认 false,不改变单库行为。
1059#[cfg(feature = "auto-failover")]
1060#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1061pub struct HaConfig {
1062    /// 是否启用故障转移(默认 false,单库行为不变)
1063    pub failover_enabled: bool,
1064    /// 故障转移配置(failover_enabled=false 时为 None)
1065    pub failover: Option<FailoverConfig>,
1066    /// 限流阈值(每秒请求数,0 表示不限)
1067    pub rate_limit_threshold: f64,
1068    /// 限流排队超时(毫秒,默认 100)
1069    pub rate_limit_queue_timeout_ms: u64,
1070    /// 熔断错误率阈值 ∈ (0,1),默认 0.5
1071    pub circuit_breaker_error_threshold: f64,
1072    /// 半开探测请求数(≥ 1)
1073    pub circuit_breaker_half_open_probes: u32,
1074    /// 追踪采样率 ∈ \[0,1\]
1075    pub trace_sample_rate: f64,
1076    /// OTLP 导出端点(None 表示不导出)
1077    pub trace_otlp_endpoint: Option<String>,
1078}
1079
1080#[cfg(feature = "auto-failover")]
1081impl Default for HaConfig {
1082    fn default() -> Self {
1083        Self {
1084            failover_enabled: false,
1085            failover: None,
1086            rate_limit_threshold: 0.0,
1087            rate_limit_queue_timeout_ms: 100,
1088            circuit_breaker_error_threshold: 0.5,
1089            circuit_breaker_half_open_probes: 1,
1090            trace_sample_rate: 1.0,
1091            trace_otlp_endpoint: None,
1092        }
1093    }
1094}
1095
1096#[cfg(feature = "auto-failover")]
1097impl HaConfig {
1098    /// 校验配置合法性
1099    pub fn validate(&self) -> Result<(), DbError> {
1100        if let Some(failover) = &self.failover {
1101            if failover.probe_interval > std::time::Duration::from_secs(5) {
1102                return Err(DbError::ConfigError(
1103                    "probe_interval must be <= 5s for RTO <= 5s".to_string(),
1104                ));
1105            }
1106            if failover.probe_failure_threshold == 0 {
1107                return Err(DbError::ConfigError(
1108                    "probe_failure_threshold must be >= 1".to_string(),
1109                ));
1110            }
1111        }
1112        if self.circuit_breaker_error_threshold <= 0.0
1113            || self.circuit_breaker_error_threshold >= 1.0
1114        {
1115            return Err(DbError::ConfigError(
1116                "circuit_breaker_error_threshold must be in (0, 1)".to_string(),
1117            ));
1118        }
1119        if self.circuit_breaker_half_open_probes == 0 {
1120            return Err(DbError::ConfigError(
1121                "circuit_breaker_half_open_probes must be >= 1".to_string(),
1122            ));
1123        }
1124        if self.trace_sample_rate < 0.0 || self.trace_sample_rate > 1.0 {
1125            return Err(DbError::ConfigError(
1126                "trace_sample_rate must be in [0, 1]".to_string(),
1127            ));
1128        }
1129        Ok(())
1130    }
1131
1132    /// 创建 builder
1133    pub fn builder() -> HaConfigBuilder {
1134        HaConfigBuilder::default()
1135    }
1136}
1137
1138/// 高可用配置 builder(v7.3.0)
1139#[cfg(feature = "auto-failover")]
1140#[derive(Debug, Clone, Default)]
1141pub struct HaConfigBuilder {
1142    config: HaConfig,
1143}
1144
1145#[cfg(feature = "auto-failover")]
1146impl HaConfigBuilder {
1147    /// 设置故障转移启用
1148    pub fn failover_enabled(mut self, enabled: bool) -> Self {
1149        self.config.failover_enabled = enabled;
1150        self
1151    }
1152
1153    /// 设置故障转移配置
1154    pub fn failover(mut self, config: FailoverConfig) -> Self {
1155        self.config.failover = Some(config);
1156        self
1157    }
1158
1159    /// 设置限流阈值
1160    pub fn rate_limit_threshold(mut self, threshold: f64) -> Self {
1161        self.config.rate_limit_threshold = threshold;
1162        self
1163    }
1164
1165    /// 设置限流排队超时(毫秒)
1166    pub fn rate_limit_queue_timeout_ms(mut self, ms: u64) -> Self {
1167        self.config.rate_limit_queue_timeout_ms = ms;
1168        self
1169    }
1170
1171    /// 设置熔断错误率阈值
1172    pub fn circuit_breaker_error_threshold(mut self, threshold: f64) -> Self {
1173        self.config.circuit_breaker_error_threshold = threshold;
1174        self
1175    }
1176
1177    /// 设置半开探测请求数
1178    pub fn circuit_breaker_half_open_probes(mut self, probes: u32) -> Self {
1179        self.config.circuit_breaker_half_open_probes = probes;
1180        self
1181    }
1182
1183    /// 设置追踪采样率
1184    pub fn trace_sample_rate(mut self, rate: f64) -> Self {
1185        self.config.trace_sample_rate = rate;
1186        self
1187    }
1188
1189    /// 设置 OTLP 导出端点
1190    pub fn trace_otlp_endpoint(mut self, endpoint: impl Into<String>) -> Self {
1191        self.config.trace_otlp_endpoint = Some(endpoint.into());
1192        self
1193    }
1194
1195    /// 构建配置(校验合法性)
1196    pub fn build(self) -> Result<HaConfig, DbError> {
1197        self.config.validate()?;
1198        Ok(self.config)
1199    }
1200}
1201
1202// ============================================================================
1203// v7.3.0 任务 4.1:EcoConfig 生态扩展配置聚合
1204// ============================================================================
1205
1206/// Web 框架枚举(v7.3.0 生态扩展)
1207#[cfg(feature = "eco-config")]
1208#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1209pub enum WebFramework {
1210    /// axum
1211    Axum,
1212    /// actix-web
1213    Actix,
1214    /// warp
1215    Warp,
1216}
1217
1218/// 中间件特性枚举(v7.3.0 生态扩展)
1219#[cfg(feature = "eco-config")]
1220#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1221pub enum MiddlewareFeature {
1222    /// 连接池注入
1223    PoolInject,
1224    /// 事务
1225    Transaction,
1226    /// 限流
1227    RateLimit,
1228    /// 追踪
1229    Tracing,
1230    /// 健康端点
1231    HealthEndpoint,
1232}
1233
1234/// 源 ORM 枚举(v7.3.0 生态扩展,用于迁移源识别)
1235#[cfg(feature = "eco-config")]
1236#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1237pub enum SourceOrm {
1238    /// Diesel
1239    Diesel,
1240    /// SeaORM
1241    SeaOrm,
1242    /// SQLx
1243    Sqlx,
1244}
1245
1246/// 生态扩展配置聚合(v7.3.0 任务 4.1)
1247///
1248/// 统一驱动 warp 中间件适配、源 ORM 迁移、schema diff 三项生态扩展能力。
1249/// `migration_dry_run` 默认 true(不自动执行 DDL)。
1250#[cfg(feature = "eco-config")]
1251#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1252pub struct EcoConfig {
1253    /// Web 框架(默认 Axum)
1254    pub web_framework: WebFramework,
1255    /// 启用的中间件特性列表
1256    pub middleware_features: Vec<MiddlewareFeature>,
1257    /// 迁移源 ORM(None 表示不从其他 ORM 迁移)
1258    pub migration_source_orm: Option<SourceOrm>,
1259    /// 迁移 dry-run 模式(默认 true,不自动执行 DDL)
1260    pub migration_dry_run: bool,
1261    /// schema diff 左库 URL(None 表示不启用 schema diff)
1262    pub schema_diff_left_url: Option<String>,
1263    /// schema diff 右库 URL
1264    pub schema_diff_right_url: Option<String>,
1265}
1266
1267#[cfg(feature = "eco-config")]
1268impl Default for EcoConfig {
1269    fn default() -> Self {
1270        Self {
1271            web_framework: WebFramework::Axum,
1272            middleware_features: Vec::new(),
1273            migration_source_orm: None,
1274            migration_dry_run: true,
1275            schema_diff_left_url: None,
1276            schema_diff_right_url: None,
1277        }
1278    }
1279}
1280
1281#[cfg(feature = "eco-config")]
1282impl EcoConfig {
1283    /// 校验配置合法性
1284    pub fn validate(&self) -> Result<(), DbError> {
1285        // schema diff:left/right 必须同时提供或同时缺失
1286        if self.schema_diff_left_url.is_some() != self.schema_diff_right_url.is_some() {
1287            return Err(DbError::ConfigError(
1288                "schema_diff_left_url 和 schema_diff_right_url 必须同时提供或同时缺失".to_string(),
1289            ));
1290        }
1291        // 迁移源 ORM 提供时,dry_run 允许 true/false(不强制),但需提示
1292        Ok(())
1293    }
1294
1295    /// 创建 builder
1296    pub fn builder() -> EcoConfigBuilder {
1297        EcoConfigBuilder::default()
1298    }
1299}
1300
1301/// 生态扩展配置 builder(v7.3.0 任务 4.1)
1302#[cfg(feature = "eco-config")]
1303#[derive(Debug, Clone, Default)]
1304pub struct EcoConfigBuilder {
1305    config: EcoConfig,
1306}
1307
1308#[cfg(feature = "eco-config")]
1309impl EcoConfigBuilder {
1310    /// 设置 Web 框架
1311    pub fn web_framework(mut self, fw: WebFramework) -> Self {
1312        self.config.web_framework = fw;
1313        self
1314    }
1315
1316    /// 设置中间件特性列表
1317    pub fn middleware_features(mut self, features: Vec<MiddlewareFeature>) -> Self {
1318        self.config.middleware_features = features;
1319        self
1320    }
1321
1322    /// 设置迁移源 ORM
1323    pub fn migration_source_orm(mut self, orm: SourceOrm) -> Self {
1324        self.config.migration_source_orm = Some(orm);
1325        self
1326    }
1327
1328    /// 设置迁移 dry-run
1329    pub fn migration_dry_run(mut self, dry_run: bool) -> Self {
1330        self.config.migration_dry_run = dry_run;
1331        self
1332    }
1333
1334    /// 设置 schema diff 左库 URL
1335    pub fn schema_diff_left_url(mut self, url: impl Into<String>) -> Self {
1336        self.config.schema_diff_left_url = Some(url.into());
1337        self
1338    }
1339
1340    /// 设置 schema diff 右库 URL
1341    pub fn schema_diff_right_url(mut self, url: impl Into<String>) -> Self {
1342        self.config.schema_diff_right_url = Some(url.into());
1343        self
1344    }
1345
1346    /// 构建配置(校验合法性)
1347    pub fn build(self) -> Result<EcoConfig, DbError> {
1348        self.config.validate()?;
1349        Ok(self.config)
1350    }
1351}
1352
1353#[cfg(test)]
1354mod tests {
1355    use super::*;
1356    use std::error::Error;
1357
1358    #[test]
1359    fn test_db_type() {
1360        assert_eq!(DbType::MySQL.as_str(), "mysql");
1361        assert_eq!(DbType::PostgreSQL.as_str(), "postgres");
1362        assert_eq!(DbType::Sqlite.as_str(), "sqlite");
1363    }
1364
1365    #[test]
1366    fn test_value() {
1367        let v = Value::Null;
1368        assert!(v.is_null());
1369
1370        let v = Value::I64(42);
1371        assert!(v.is_i64());
1372
1373        let v = Value::String("hello".to_string());
1374        assert!(v.is_string());
1375    }
1376
1377    #[test]
1378    fn test_db_error_display() {
1379        let err = DbError::QueryError("test query failed".to_string());
1380        assert_eq!(format!("{}", err), "Query error: test query failed");
1381
1382        let err = DbError::ConnectionRefused("localhost".to_string());
1383        assert_eq!(format!("{}", err), "Connection refused: localhost");
1384    }
1385
1386    #[test]
1387    fn test_db_error_source() {
1388        let err = DbError::PoolError(PoolError::Timeout);
1389        assert!(err.source().is_some());
1390    }
1391
1392    #[tokio::test]
1393    async fn test_async_trait_export() {
1394        fn _check_send_sync<T: Send + Sync>() {}
1395
1396        struct TestImpl;
1397        #[async_trait]
1398        trait AsyncFoo: Send + Sync {
1399            async fn foo(&self);
1400        }
1401
1402        #[async_trait]
1403        impl AsyncFoo for TestImpl {
1404            async fn foo(&self) {}
1405        }
1406
1407        let impl_ = TestImpl;
1408        impl_.foo().await;
1409        _check_send_sync::<TestImpl>();
1410    }
1411
1412    // ---- compile-time SQL validation macro tests ----
1413
1414    /// Valid SQL should compile and be usable as a string
1415    #[test]
1416    fn test_sql_string_valid_select() {
1417        let sql = sql_string!("SELECT * FROM users WHERE id = 1");
1418        assert!(sql.contains("SELECT"));
1419        assert!(sql.contains("FROM"));
1420    }
1421
1422    #[test]
1423    fn test_sql_string_valid_insert() {
1424        let sql = sql_string!("INSERT INTO users (name) VALUES ('alice')");
1425        assert!(sql.contains("INSERT"));
1426    }
1427
1428    #[test]
1429    fn test_sql_string_valid_update() {
1430        let sql = sql_string!("UPDATE users SET name = 'bob' WHERE id = 1");
1431        assert!(sql.contains("UPDATE"));
1432    }
1433
1434    #[test]
1435    fn test_sql_string_valid_delete() {
1436        let sql = sql_string!("DELETE FROM users WHERE id = 1");
1437        assert!(sql.contains("DELETE"));
1438    }
1439
1440    #[test]
1441    fn test_sql_string_valid_create() {
1442        let sql = sql_string!("CREATE TABLE test (id INT PRIMARY KEY)");
1443        assert!(sql.contains("CREATE"));
1444    }
1445
1446    #[test]
1447    fn test_sql_string_with_params() {
1448        let sql = sql_string!("SELECT * FROM users WHERE id = ?"; params: 1);
1449        assert!(sql.contains("?"));
1450    }
1451
1452    #[test]
1453    fn test_sql_string_complex_query() {
1454        let sql = sql_string!(
1455            "SELECT u.*, o.total FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE u.status = 'active'"
1456        );
1457        assert!(sql.contains("LEFT JOIN"));
1458    }
1459
1460    #[test]
1461    fn test_sql_string_nested_parens() {
1462        let sql = sql_string!("SELECT * FROM (SELECT * FROM users) t");
1463        assert!(sql.contains("SELECT"));
1464    }
1465}