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 = "type-safe-columns")]
437pub mod column;
438#[cfg(feature = "zero-copy")]
439pub mod columnar;
440#[cfg(any(
441    feature = "prepared-stmt-cache",
442    feature = "async-row-stream",
443    feature = "parallel-batch"
444))]
445pub mod connection_ext;
446pub mod cursor_stream;
447pub mod cycle_detection;
448pub mod data_permission;
449mod db_type;
450pub mod dialect;
451#[cfg(feature = "prod-dialect-security")]
452pub mod dialect_security;
453pub mod dirty_attributes;
454#[cfg(feature = "dist-cache")]
455pub mod dist_cache;
456#[cfg(feature = "dist-cache-cluster")]
457#[allow(missing_docs)]
458pub mod dist_cache_cluster;
459pub mod dynamic_filter;
460pub mod dynamic_sql;
461pub mod eager_loader;
462pub mod entity_graph;
463mod error;
464pub mod find_with_related;
465#[cfg(feature = "compile-governance")]
466pub mod governance;
467pub mod guard;
468pub mod hooks;
469#[cfg(feature = "composable-plugin")]
470pub use hooks::{ExtensionHandler, ExtensionPoint, ExtensionPointRegistry};
471pub mod hydration_plugin;
472pub mod i18n;
473pub mod join_dsl;
474pub mod json_query;
475#[cfg(feature = "l1-cache")]
476pub mod l1_cache;
477pub mod l2_cache;
478pub mod lambda;
479pub mod lazy_loader;
480pub mod linq;
481pub mod migration;
482#[cfg(feature = "migration-dry-run")]
483pub mod migration_dry_run;
484pub mod mock;
485mod model;
486#[cfg(feature = "multi-tenant-pool")]
487#[allow(missing_docs)]
488pub mod multi_tenant_pool;
489pub mod n1_eliminator;
490pub mod nested_active_model;
491pub mod observer;
492pub mod optimistic_lock;
493pub mod paginator;
494pub mod partial_model;
495pub mod phinx_migration;
496#[cfg(feature = "plan-cache")]
497pub mod plan_cache;
498pub mod plugin;
499#[cfg(feature = "composable-plugin")]
500pub use plugin::{MiddlewareChain, PanicSafeRegistry, PluginSigner, PluginState, SignatureStatus};
501mod pool;
502#[cfg(feature = "prepared-stmt-cache")]
503pub mod prepared_cache;
504#[cfg(feature = "auto-prewarm")]
505pub mod prewarm;
506#[cfg(feature = "prod-ready")]
507pub mod prod_ready_check;
508mod query;
509pub mod query_cache;
510#[cfg(feature = "query-result-cache")]
511#[allow(missing_docs)]
512pub mod query_result_cache;
513#[cfg(feature = "async-row-stream")]
514pub mod row_stream;
515#[cfg(feature = "rw-split-enhanced")]
516#[allow(missing_docs)]
517pub mod rw_split_enhanced;
518#[cfg(feature = "saga-tx")]
519#[allow(missing_docs)]
520pub mod saga;
521
522#[cfg(feature = "pool-elastic")]
523#[allow(missing_docs)]
524pub mod pool_elastic;
525
526#[cfg(feature = "serverless-adapt")]
527pub use pool_elastic::{
528    CdcCheckpoint, GracefulShutdown, GracefulShutdownConfig, ShutdownError, ShutdownResult,
529};
530#[cfg(feature = "serverless-adapt")]
531pub use prewarm::{ColdStartOptimizer, ColdStartStats};
532
533#[cfg(feature = "io-uring")]
534#[allow(missing_docs)]
535pub mod io_uring_probe;
536
537#[cfg(feature = "field-encryption")]
538#[allow(missing_docs)]
539pub mod field_cipher;
540#[cfg(feature = "tde-interceptor")]
541pub use field_cipher::{TdeError, TdeInterceptor};
542#[cfg(feature = "tde-interceptor")]
543pub use sz_orm_crypto::{
544    ColumnCryptoConfig, ColumnEncryptionPolicy, DekBuffer, EncryptionAlgo, KmsClient,
545    LocalKmsClient,
546};
547
548#[cfg(feature = "data-validation")]
549pub mod validation;
550/// Re-export QueryBuilder for external use
551pub use query::QueryBuilder;
552#[cfg(feature = "adaptive-query")]
553pub mod adaptive_adapter;
554#[cfg(feature = "cache-coherence")]
555pub mod cache_coherence;
556#[cfg(feature = "l1-cache")]
557#[allow(missing_docs)]
558pub mod cache_warmup_protection;
559#[cfg(feature = "config-center")]
560pub mod config_adapter;
561#[cfg(feature = "connection-level-tenant")]
562pub mod connection_tenant;
563#[cfg(feature = "forward-compat-sandbox")]
564#[allow(missing_docs)]
565pub mod forward_compat_sandbox;
566#[cfg(feature = "graph")]
567pub mod graph_adapter;
568#[cfg(feature = "graphql")]
569pub mod graphql_adapter;
570#[cfg(feature = "structured-logging")]
571pub mod logger_adapter;
572#[cfg(feature = "postgis")]
573pub mod postgis_adapter;
574#[cfg(feature = "read-write-splitting")]
575pub mod rw_adapter;
576#[cfg(feature = "search")]
577pub mod search_adapter;
578#[cfg(feature = "timeseries")]
579pub mod timeseries_adapter;
580#[cfg(feature = "distributed-tracing")]
581pub mod tracing_adapter;
582
583#[cfg(feature = "migration-branch")]
584pub mod migration_branch;
585#[cfg(feature = "l1-cache")]
586pub mod process_l1_cache;
587#[cfg(feature = "qb-migration-tool")]
588pub mod qb_migration_fix;
589#[cfg(feature = "qb-migration-tool")]
590pub mod qb_migration_lint;
591pub mod queryable;
592pub mod quick_query;
593pub mod rate_limiter;
594pub mod relation_trait;
595pub mod repository;
596pub mod result_map;
597pub mod retry;
598#[cfg(feature = "zero-downtime-rollback")]
599pub mod rollback_zero_downtime;
600#[cfg(feature = "schema-diff-viz")]
601pub mod schema_diff_viz;
602pub mod schema_gen;
603pub mod schema_sync;
604#[cfg(feature = "data-seeding")]
605pub mod seeding;
606pub mod select_types;
607pub mod shadow;
608#[cfg(feature = "simd")]
609pub mod simd;
610pub mod smart_eager_loader;
611pub mod sql_buffer;
612pub mod sql_safety;
613#[cfg(feature = "sql-verify-proc")]
614pub mod sql_verify;
615pub mod stream_api;
616#[cfg(feature = "streaming-export")]
617pub mod streaming_export;
618pub mod telemetry;
619#[cfg(feature = "multi-tenant-enhanced")]
620pub mod tenant_context;
621#[cfg(feature = "tenant-quota-rls-enhanced")]
622#[allow(missing_docs)]
623pub mod tenant_quota_rls;
624#[cfg(feature = "multi-tenant-enhanced")]
625pub mod tenant_security;
626mod transaction;
627pub mod type_handler;
628pub mod typed;
629pub mod typed_ast;
630#[cfg(feature = "typed-relation")]
631pub mod typed_relation;
632mod value;
633#[cfg(feature = "zero-copy")]
634pub mod value_borrowed;
635#[cfg(feature = "zero-copy-deep")]
636#[allow(missing_docs)]
637pub mod zero_copy_pipeline;
638
639#[cfg(any(
640    feature = "cdc-mysql",
641    feature = "cdc-postgres",
642    feature = "cdc-sqlite",
643    feature = "cdc-realtime-sync"
644))]
645#[allow(missing_docs)]
646pub mod cdc;
647
648#[cfg(feature = "rbac-abac-enhanced")]
649#[allow(missing_docs)]
650pub mod column_mask_interceptor;
651
652#[cfg(feature = "rbac-abac-enhanced")]
653#[allow(missing_docs)]
654pub mod row_level_policy;
655
656#[cfg(feature = "olap-vectorized")]
657#[allow(missing_docs)]
658pub mod olap;
659
660#[cfg(feature = "executor-opt")]
661#[allow(missing_docs)]
662pub mod executor_passes;
663
664// Re-export proc macros
665pub use queryable::Query;
666pub use queryable::QueryAs;
667pub use sz_orm_macros::api_beta;
668pub use sz_orm_macros::api_stable;
669pub use sz_orm_macros::migrate;
670pub use sz_orm_macros::query;
671pub use sz_orm_macros::query_as;
672pub use sz_orm_macros::schema;
673pub use sz_orm_macros::sql_string;
674pub use sz_orm_macros::typed_query;
675// FromQueryResult derive 宏(与 value.rs 中同名 trait 通过显式 use 遮蔽 glob 导出)
676#[cfg(feature = "n1-lint")]
677pub use sz_orm_macros::detect_n_plus_one;
678pub use sz_orm_macros::FromQueryResult;
679pub use sz_orm_macros::RelationTrait;
680#[cfg(feature = "data-validation")]
681pub use sz_orm_macros::Validate;
682
683pub use change_tracker::{ChangeTracker, EntityEntry, EntityState};
684pub use lazy_loader::{LazyCollection, LazyLoader, LazyRef};
685pub use linq::LinqQuery;
686pub use query_cache::{QueryCache, QueryCacheKey, TimestampCache};
687
688pub use cache::*;
689pub use cycle_detection::{CycleDetector, CyclePolicy};
690pub use db_type::*;
691#[allow(ambiguous_glob_reexports)]
692pub use dialect::*;
693pub use eager_loader::NestedEagerResult;
694pub use error::*;
695#[allow(ambiguous_glob_reexports)]
696pub use migration::*;
697pub use model::*;
698pub use nested_active_model::CascadeStrategy;
699pub use pool::*;
700#[allow(unused_imports)]
701pub use query::*;
702pub use schema_sync::{Confirm, DataMigrationHook, DestructiveSyncResult};
703pub use transaction::*;
704pub use value::*;
705
706/// Alias for `Arc<T>`
707pub type Shared<T> = Arc<T>;
708
709/// Alias for `Box<T>`
710pub type Boxed<T> = Box<T>;
711
712/// Alias for Result<T, DbError>
713pub type DbResult<T> = Result<T, DbError>;
714
715/// Result type for pool operations
716pub type PoolResult<T> = Result<T, PoolError>;
717
718/// Result type for cache operations
719pub type CacheResult<T> = Result<T, CacheError>;
720
721/// Result type for transaction operations
722pub type TxResult<T> = Result<T, TxError>;
723
724/// Default batch size for bulk operations
725pub const DEFAULT_BATCH_SIZE: usize = 1000;
726
727/// Default connection timeout in seconds
728pub const DEFAULT_ACQUIRE_TIMEOUT: u64 = 30;
729
730/// Default idle timeout in seconds
731pub const DEFAULT_IDLE_TIMEOUT: u64 = 600;
732
733/// Default max lifetime in seconds
734pub const DEFAULT_MAX_LIFETIME: u64 = 1800;
735
736/// Default minimum idle connections
737pub const DEFAULT_MIN_IDLE: u32 = 5;
738
739/// Default maximum pool size
740pub const DEFAULT_MAX_SIZE: u32 = 100;
741
742// ============================================================================
743// v7.3.0 性能加速配置与指标聚合(perf-accel feature gate)
744// ============================================================================
745
746/// 性能加速配置(v7.3.0)
747///
748/// 统一驱动 SIMD 向量化、零拷贝序列化、连接池预热、查询计划缓存四项加速能力。
749/// 所有加速开关默认 false(plan_cache_enabled 默认 true 保持既有行为),
750/// 不改变 v7.2.0 既有行为。
751#[cfg(feature = "perf-accel")]
752#[derive(Debug, Clone)]
753pub struct PerfConfig {
754    /// 是否启用 SIMD 向量化加速
755    pub simd_enabled: bool,
756    /// SIMD 批量处理最低行数阈值(低于此值走标量路径)
757    pub simd_row_threshold: usize,
758    /// 是否启用零拷贝序列化
759    pub zero_copy_enabled: bool,
760    /// 是否启用连接池预热
761    pub prewarm_enabled: bool,
762    /// 预热连接数
763    pub prewarm_count: usize,
764    /// 是否启用查询计划缓存
765    pub plan_cache_enabled: bool,
766    /// 计划缓存容量
767    pub plan_cache_capacity: usize,
768    /// 计划缓存 TTL(毫秒)
769    pub plan_cache_ttl_ms: u64,
770}
771
772#[cfg(feature = "perf-accel")]
773impl Default for PerfConfig {
774    fn default() -> Self {
775        Self {
776            simd_enabled: false,
777            simd_row_threshold: 1024,
778            zero_copy_enabled: false,
779            prewarm_enabled: false,
780            prewarm_count: 1,
781            plan_cache_enabled: true,
782            plan_cache_capacity: 256,
783            plan_cache_ttl_ms: 300_000,
784        }
785    }
786}
787
788#[cfg(feature = "perf-accel")]
789impl PerfConfig {
790    /// 校验配置合法性
791    pub fn validate(&self) -> Result<(), DbError> {
792        if self.simd_row_threshold < 1 {
793            return Err(DbError::ConfigError(
794                "simd_row_threshold must be >= 1".to_string(),
795            ));
796        }
797        if self.prewarm_count < 1 {
798            return Err(DbError::ConfigError(
799                "prewarm_count must be >= 1".to_string(),
800            ));
801        }
802        if self.plan_cache_capacity < 1 {
803            return Err(DbError::ConfigError(
804                "plan_cache_capacity must be >= 1".to_string(),
805            ));
806        }
807        if self.plan_cache_ttl_ms == 0 {
808            return Err(DbError::ConfigError(
809                "plan_cache_ttl_ms must be > 0".to_string(),
810            ));
811        }
812        Ok(())
813    }
814
815    /// 创建 builder
816    pub fn builder() -> PerfConfigBuilder {
817        PerfConfigBuilder::default()
818    }
819}
820
821/// 性能加速配置 builder(v7.3.0)
822#[cfg(feature = "perf-accel")]
823#[derive(Debug, Clone, Default)]
824pub struct PerfConfigBuilder {
825    config: PerfConfig,
826}
827
828#[cfg(feature = "perf-accel")]
829impl PerfConfigBuilder {
830    /// 设置 SIMD 启用
831    pub fn simd(mut self, enabled: bool) -> Self {
832        self.config.simd_enabled = enabled;
833        self
834    }
835
836    /// 设置 SIMD 行阈值
837    pub fn simd_row_threshold(mut self, threshold: usize) -> Self {
838        self.config.simd_row_threshold = threshold;
839        self
840    }
841
842    /// 设置零拷贝启用
843    pub fn zero_copy(mut self, enabled: bool) -> Self {
844        self.config.zero_copy_enabled = enabled;
845        self
846    }
847
848    /// 设置预热启用
849    pub fn prewarm(mut self, enabled: bool) -> Self {
850        self.config.prewarm_enabled = enabled;
851        self
852    }
853
854    /// 设置预热连接数
855    pub fn prewarm_count(mut self, count: usize) -> Self {
856        self.config.prewarm_count = count;
857        self
858    }
859
860    /// 设置计划缓存启用
861    pub fn plan_cache(mut self, enabled: bool) -> Self {
862        self.config.plan_cache_enabled = enabled;
863        self
864    }
865
866    /// 设置计划缓存容量
867    pub fn plan_cache_capacity(mut self, capacity: usize) -> Self {
868        self.config.plan_cache_capacity = capacity;
869        self
870    }
871
872    /// 设置计划缓存 TTL(毫秒)
873    pub fn plan_cache_ttl_ms(mut self, ttl_ms: u64) -> Self {
874        self.config.plan_cache_ttl_ms = ttl_ms;
875        self
876    }
877
878    /// 构建配置(校验合法性)
879    pub fn build(self) -> Result<PerfConfig, DbError> {
880        self.config.validate()?;
881        Ok(self.config)
882    }
883}
884
885/// 性能加速指标快照(v7.3.0)
886#[cfg(feature = "perf-accel")]
887#[derive(Debug, Clone, Default)]
888pub struct PerfMetricsSnapshot {
889    /// SIMD 命中次数
890    pub simd_hit_count: u64,
891    /// SIMD 未命中次数
892    pub simd_miss_count: u64,
893    /// SIMD 延迟降低百分比
894    pub simd_latency_reduction_pct: f64,
895    /// 零拷贝命中次数
896    pub zero_copy_hit_count: u64,
897    /// 零拷贝 RSS 降低百分比
898    pub zero_copy_rss_reduction_pct: f64,
899    /// 预热成功次数
900    pub prewarm_success_count: u64,
901    /// 计划缓存命中率
902    pub plan_cache_hit_rate: f64,
903    /// 计划缓存淘汰次数
904    pub plan_cache_eviction_count: u64,
905}
906
907/// 性能加速指标聚合(v7.3.0)
908///
909/// 使用无锁原子计数器采集 SIMD/零拷贝/预热/计划缓存四项加速能力的运行指标。
910#[cfg(feature = "perf-accel")]
911#[derive(Debug, Default)]
912pub struct PerfMetrics {
913    simd_hit_count: std::sync::atomic::AtomicU64,
914    simd_miss_count: std::sync::atomic::AtomicU64,
915    simd_latency_reduction_pct: std::sync::atomic::AtomicU64,
916    zero_copy_hit_count: std::sync::atomic::AtomicU64,
917    zero_copy_rss_reduction_pct: std::sync::atomic::AtomicU64,
918    prewarm_success_count: std::sync::atomic::AtomicU64,
919    plan_cache_hit_rate: std::sync::atomic::AtomicU64,
920    plan_cache_eviction_count: std::sync::atomic::AtomicU64,
921}
922
923#[cfg(feature = "perf-accel")]
924impl PerfMetrics {
925    /// 创建新的指标实例
926    pub fn new() -> Self {
927        Self::default()
928    }
929
930    /// 记录 SIMD 命中
931    pub fn record_simd_hit(&self) {
932        self.simd_hit_count
933            .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
934    }
935
936    /// 记录 SIMD 未命中
937    pub fn record_simd_miss(&self) {
938        self.simd_miss_count
939            .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
940    }
941
942    /// 记录零拷贝命中
943    pub fn record_zero_copy_hit(&self) {
944        self.zero_copy_hit_count
945            .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
946    }
947
948    /// 记录预热成功
949    pub fn record_prewarm_success(&self) {
950        self.prewarm_success_count
951            .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
952    }
953
954    /// 记录计划缓存淘汰
955    pub fn record_plan_cache_eviction(&self) {
956        self.plan_cache_eviction_count
957            .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
958    }
959
960    /// 设置 SIMD 延迟降低百分比
961    pub fn set_simd_latency_reduction_pct(&self, pct: f64) {
962        self.simd_latency_reduction_pct
963            .store(pct.to_bits(), std::sync::atomic::Ordering::Relaxed);
964    }
965
966    /// 设置零拷贝 RSS 降低百分比
967    pub fn set_zero_copy_rss_reduction_pct(&self, pct: f64) {
968        self.zero_copy_rss_reduction_pct
969            .store(pct.to_bits(), std::sync::atomic::Ordering::Relaxed);
970    }
971
972    /// 设置计划缓存命中率
973    pub fn set_plan_cache_hit_rate(&self, rate: f64) {
974        self.plan_cache_hit_rate
975            .store(rate.to_bits(), std::sync::atomic::Ordering::Relaxed);
976    }
977
978    /// 采集指标快照
979    pub fn snapshot(&self) -> PerfMetricsSnapshot {
980        let o = std::sync::atomic::Ordering::Relaxed;
981        PerfMetricsSnapshot {
982            simd_hit_count: self.simd_hit_count.load(o),
983            simd_miss_count: self.simd_miss_count.load(o),
984            simd_latency_reduction_pct: f64::from_bits(self.simd_latency_reduction_pct.load(o)),
985            zero_copy_hit_count: self.zero_copy_hit_count.load(o),
986            zero_copy_rss_reduction_pct: f64::from_bits(self.zero_copy_rss_reduction_pct.load(o)),
987            prewarm_success_count: self.prewarm_success_count.load(o),
988            plan_cache_hit_rate: f64::from_bits(self.plan_cache_hit_rate.load(o)),
989            plan_cache_eviction_count: self.plan_cache_eviction_count.load(o),
990        }
991    }
992}
993
994// ============================================================================
995// v7.3.0 高可用配置聚合(auto-failover feature gate)
996// ============================================================================
997
998/// 回切策略(v7.3.0)
999///
1000/// - `Manual`:故障转移后等待运维确认再回切
1001/// - `Auto`:经健康+一致性校验后自动回切
1002#[cfg(feature = "auto-failover")]
1003#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1004pub enum FailbackStrategy {
1005    /// 等待运维确认再回切
1006    Manual,
1007    /// 经健康+一致性校验后自动回切
1008    Auto,
1009}
1010
1011/// 故障转移配置(v7.3.0)
1012///
1013/// 凭证经既有配置加密链路加载(禁止明文)。
1014#[cfg(feature = "auto-failover")]
1015#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1016pub struct FailoverConfig {
1017    /// 主库连接 URL(已加密,运行时解密)
1018    pub primary_url: String,
1019    /// 备库连接 URL(已加密,运行时解密)
1020    pub replica_url: String,
1021    /// 探活间隔(必须 ≤ 5s 以保证 RTO ≤ 5s)
1022    pub probe_interval: std::time::Duration,
1023    /// 连续探活失败多少次触发故障转移(默认 3)
1024    pub probe_failure_threshold: u32,
1025    /// 回切策略
1026    pub failback_strategy: FailbackStrategy,
1027}
1028
1029#[cfg(feature = "auto-failover")]
1030impl Default for FailoverConfig {
1031    fn default() -> Self {
1032        Self {
1033            primary_url: String::new(),
1034            replica_url: String::new(),
1035            probe_interval: std::time::Duration::from_secs(1),
1036            probe_failure_threshold: 3,
1037            failback_strategy: FailbackStrategy::Manual,
1038        }
1039    }
1040}
1041
1042/// 高可用配置聚合(v7.3.0)
1043///
1044/// 统一驱动故障转移、限流熔断、健康检查、追踪四项高可用能力。
1045/// `failover_enabled` 默认 false,不改变单库行为。
1046#[cfg(feature = "auto-failover")]
1047#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1048pub struct HaConfig {
1049    /// 是否启用故障转移(默认 false,单库行为不变)
1050    pub failover_enabled: bool,
1051    /// 故障转移配置(failover_enabled=false 时为 None)
1052    pub failover: Option<FailoverConfig>,
1053    /// 限流阈值(每秒请求数,0 表示不限)
1054    pub rate_limit_threshold: f64,
1055    /// 限流排队超时(毫秒,默认 100)
1056    pub rate_limit_queue_timeout_ms: u64,
1057    /// 熔断错误率阈值 ∈ (0,1),默认 0.5
1058    pub circuit_breaker_error_threshold: f64,
1059    /// 半开探测请求数(≥ 1)
1060    pub circuit_breaker_half_open_probes: u32,
1061    /// 追踪采样率 ∈ \[0,1\]
1062    pub trace_sample_rate: f64,
1063    /// OTLP 导出端点(None 表示不导出)
1064    pub trace_otlp_endpoint: Option<String>,
1065}
1066
1067#[cfg(feature = "auto-failover")]
1068impl Default for HaConfig {
1069    fn default() -> Self {
1070        Self {
1071            failover_enabled: false,
1072            failover: None,
1073            rate_limit_threshold: 0.0,
1074            rate_limit_queue_timeout_ms: 100,
1075            circuit_breaker_error_threshold: 0.5,
1076            circuit_breaker_half_open_probes: 1,
1077            trace_sample_rate: 1.0,
1078            trace_otlp_endpoint: None,
1079        }
1080    }
1081}
1082
1083#[cfg(feature = "auto-failover")]
1084impl HaConfig {
1085    /// 校验配置合法性
1086    pub fn validate(&self) -> Result<(), DbError> {
1087        if let Some(failover) = &self.failover {
1088            if failover.probe_interval > std::time::Duration::from_secs(5) {
1089                return Err(DbError::ConfigError(
1090                    "probe_interval must be <= 5s for RTO <= 5s".to_string(),
1091                ));
1092            }
1093            if failover.probe_failure_threshold == 0 {
1094                return Err(DbError::ConfigError(
1095                    "probe_failure_threshold must be >= 1".to_string(),
1096                ));
1097            }
1098        }
1099        if self.circuit_breaker_error_threshold <= 0.0
1100            || self.circuit_breaker_error_threshold >= 1.0
1101        {
1102            return Err(DbError::ConfigError(
1103                "circuit_breaker_error_threshold must be in (0, 1)".to_string(),
1104            ));
1105        }
1106        if self.circuit_breaker_half_open_probes == 0 {
1107            return Err(DbError::ConfigError(
1108                "circuit_breaker_half_open_probes must be >= 1".to_string(),
1109            ));
1110        }
1111        if self.trace_sample_rate < 0.0 || self.trace_sample_rate > 1.0 {
1112            return Err(DbError::ConfigError(
1113                "trace_sample_rate must be in [0, 1]".to_string(),
1114            ));
1115        }
1116        Ok(())
1117    }
1118
1119    /// 创建 builder
1120    pub fn builder() -> HaConfigBuilder {
1121        HaConfigBuilder::default()
1122    }
1123}
1124
1125/// 高可用配置 builder(v7.3.0)
1126#[cfg(feature = "auto-failover")]
1127#[derive(Debug, Clone, Default)]
1128pub struct HaConfigBuilder {
1129    config: HaConfig,
1130}
1131
1132#[cfg(feature = "auto-failover")]
1133impl HaConfigBuilder {
1134    /// 设置故障转移启用
1135    pub fn failover_enabled(mut self, enabled: bool) -> Self {
1136        self.config.failover_enabled = enabled;
1137        self
1138    }
1139
1140    /// 设置故障转移配置
1141    pub fn failover(mut self, config: FailoverConfig) -> Self {
1142        self.config.failover = Some(config);
1143        self
1144    }
1145
1146    /// 设置限流阈值
1147    pub fn rate_limit_threshold(mut self, threshold: f64) -> Self {
1148        self.config.rate_limit_threshold = threshold;
1149        self
1150    }
1151
1152    /// 设置限流排队超时(毫秒)
1153    pub fn rate_limit_queue_timeout_ms(mut self, ms: u64) -> Self {
1154        self.config.rate_limit_queue_timeout_ms = ms;
1155        self
1156    }
1157
1158    /// 设置熔断错误率阈值
1159    pub fn circuit_breaker_error_threshold(mut self, threshold: f64) -> Self {
1160        self.config.circuit_breaker_error_threshold = threshold;
1161        self
1162    }
1163
1164    /// 设置半开探测请求数
1165    pub fn circuit_breaker_half_open_probes(mut self, probes: u32) -> Self {
1166        self.config.circuit_breaker_half_open_probes = probes;
1167        self
1168    }
1169
1170    /// 设置追踪采样率
1171    pub fn trace_sample_rate(mut self, rate: f64) -> Self {
1172        self.config.trace_sample_rate = rate;
1173        self
1174    }
1175
1176    /// 设置 OTLP 导出端点
1177    pub fn trace_otlp_endpoint(mut self, endpoint: impl Into<String>) -> Self {
1178        self.config.trace_otlp_endpoint = Some(endpoint.into());
1179        self
1180    }
1181
1182    /// 构建配置(校验合法性)
1183    pub fn build(self) -> Result<HaConfig, DbError> {
1184        self.config.validate()?;
1185        Ok(self.config)
1186    }
1187}
1188
1189// ============================================================================
1190// v7.3.0 任务 4.1:EcoConfig 生态扩展配置聚合
1191// ============================================================================
1192
1193/// Web 框架枚举(v7.3.0 生态扩展)
1194#[cfg(feature = "eco-config")]
1195#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1196pub enum WebFramework {
1197    /// axum
1198    Axum,
1199    /// actix-web
1200    Actix,
1201    /// warp
1202    Warp,
1203}
1204
1205/// 中间件特性枚举(v7.3.0 生态扩展)
1206#[cfg(feature = "eco-config")]
1207#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1208pub enum MiddlewareFeature {
1209    /// 连接池注入
1210    PoolInject,
1211    /// 事务
1212    Transaction,
1213    /// 限流
1214    RateLimit,
1215    /// 追踪
1216    Tracing,
1217    /// 健康端点
1218    HealthEndpoint,
1219}
1220
1221/// 源 ORM 枚举(v7.3.0 生态扩展,用于迁移源识别)
1222#[cfg(feature = "eco-config")]
1223#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1224pub enum SourceOrm {
1225    /// Diesel
1226    Diesel,
1227    /// SeaORM
1228    SeaOrm,
1229    /// SQLx
1230    Sqlx,
1231}
1232
1233/// 生态扩展配置聚合(v7.3.0 任务 4.1)
1234///
1235/// 统一驱动 warp 中间件适配、源 ORM 迁移、schema diff 三项生态扩展能力。
1236/// `migration_dry_run` 默认 true(不自动执行 DDL)。
1237#[cfg(feature = "eco-config")]
1238#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1239pub struct EcoConfig {
1240    /// Web 框架(默认 Axum)
1241    pub web_framework: WebFramework,
1242    /// 启用的中间件特性列表
1243    pub middleware_features: Vec<MiddlewareFeature>,
1244    /// 迁移源 ORM(None 表示不从其他 ORM 迁移)
1245    pub migration_source_orm: Option<SourceOrm>,
1246    /// 迁移 dry-run 模式(默认 true,不自动执行 DDL)
1247    pub migration_dry_run: bool,
1248    /// schema diff 左库 URL(None 表示不启用 schema diff)
1249    pub schema_diff_left_url: Option<String>,
1250    /// schema diff 右库 URL
1251    pub schema_diff_right_url: Option<String>,
1252}
1253
1254#[cfg(feature = "eco-config")]
1255impl Default for EcoConfig {
1256    fn default() -> Self {
1257        Self {
1258            web_framework: WebFramework::Axum,
1259            middleware_features: Vec::new(),
1260            migration_source_orm: None,
1261            migration_dry_run: true,
1262            schema_diff_left_url: None,
1263            schema_diff_right_url: None,
1264        }
1265    }
1266}
1267
1268#[cfg(feature = "eco-config")]
1269impl EcoConfig {
1270    /// 校验配置合法性
1271    pub fn validate(&self) -> Result<(), DbError> {
1272        // schema diff:left/right 必须同时提供或同时缺失
1273        if self.schema_diff_left_url.is_some() != self.schema_diff_right_url.is_some() {
1274            return Err(DbError::ConfigError(
1275                "schema_diff_left_url 和 schema_diff_right_url 必须同时提供或同时缺失".to_string(),
1276            ));
1277        }
1278        // 迁移源 ORM 提供时,dry_run 允许 true/false(不强制),但需提示
1279        Ok(())
1280    }
1281
1282    /// 创建 builder
1283    pub fn builder() -> EcoConfigBuilder {
1284        EcoConfigBuilder::default()
1285    }
1286}
1287
1288/// 生态扩展配置 builder(v7.3.0 任务 4.1)
1289#[cfg(feature = "eco-config")]
1290#[derive(Debug, Clone, Default)]
1291pub struct EcoConfigBuilder {
1292    config: EcoConfig,
1293}
1294
1295#[cfg(feature = "eco-config")]
1296impl EcoConfigBuilder {
1297    /// 设置 Web 框架
1298    pub fn web_framework(mut self, fw: WebFramework) -> Self {
1299        self.config.web_framework = fw;
1300        self
1301    }
1302
1303    /// 设置中间件特性列表
1304    pub fn middleware_features(mut self, features: Vec<MiddlewareFeature>) -> Self {
1305        self.config.middleware_features = features;
1306        self
1307    }
1308
1309    /// 设置迁移源 ORM
1310    pub fn migration_source_orm(mut self, orm: SourceOrm) -> Self {
1311        self.config.migration_source_orm = Some(orm);
1312        self
1313    }
1314
1315    /// 设置迁移 dry-run
1316    pub fn migration_dry_run(mut self, dry_run: bool) -> Self {
1317        self.config.migration_dry_run = dry_run;
1318        self
1319    }
1320
1321    /// 设置 schema diff 左库 URL
1322    pub fn schema_diff_left_url(mut self, url: impl Into<String>) -> Self {
1323        self.config.schema_diff_left_url = Some(url.into());
1324        self
1325    }
1326
1327    /// 设置 schema diff 右库 URL
1328    pub fn schema_diff_right_url(mut self, url: impl Into<String>) -> Self {
1329        self.config.schema_diff_right_url = Some(url.into());
1330        self
1331    }
1332
1333    /// 构建配置(校验合法性)
1334    pub fn build(self) -> Result<EcoConfig, DbError> {
1335        self.config.validate()?;
1336        Ok(self.config)
1337    }
1338}
1339
1340#[cfg(test)]
1341mod tests {
1342    use super::*;
1343    use std::error::Error;
1344
1345    #[test]
1346    fn test_db_type() {
1347        assert_eq!(DbType::MySQL.as_str(), "mysql");
1348        assert_eq!(DbType::PostgreSQL.as_str(), "postgres");
1349        assert_eq!(DbType::Sqlite.as_str(), "sqlite");
1350    }
1351
1352    #[test]
1353    fn test_value() {
1354        let v = Value::Null;
1355        assert!(v.is_null());
1356
1357        let v = Value::I64(42);
1358        assert!(v.is_i64());
1359
1360        let v = Value::String("hello".to_string());
1361        assert!(v.is_string());
1362    }
1363
1364    #[test]
1365    fn test_db_error_display() {
1366        let err = DbError::QueryError("test query failed".to_string());
1367        assert_eq!(format!("{}", err), "Query error: test query failed");
1368
1369        let err = DbError::ConnectionRefused("localhost".to_string());
1370        assert_eq!(format!("{}", err), "Connection refused: localhost");
1371    }
1372
1373    #[test]
1374    fn test_db_error_source() {
1375        let err = DbError::PoolError(PoolError::Timeout);
1376        assert!(err.source().is_some());
1377    }
1378
1379    #[tokio::test]
1380    async fn test_async_trait_export() {
1381        fn _check_send_sync<T: Send + Sync>() {}
1382
1383        struct TestImpl;
1384        #[async_trait]
1385        trait AsyncFoo: Send + Sync {
1386            async fn foo(&self);
1387        }
1388
1389        #[async_trait]
1390        impl AsyncFoo for TestImpl {
1391            async fn foo(&self) {}
1392        }
1393
1394        let impl_ = TestImpl;
1395        impl_.foo().await;
1396        _check_send_sync::<TestImpl>();
1397    }
1398
1399    // ---- compile-time SQL validation macro tests ----
1400
1401    /// Valid SQL should compile and be usable as a string
1402    #[test]
1403    fn test_sql_string_valid_select() {
1404        let sql = sql_string!("SELECT * FROM users WHERE id = 1");
1405        assert!(sql.contains("SELECT"));
1406        assert!(sql.contains("FROM"));
1407    }
1408
1409    #[test]
1410    fn test_sql_string_valid_insert() {
1411        let sql = sql_string!("INSERT INTO users (name) VALUES ('alice')");
1412        assert!(sql.contains("INSERT"));
1413    }
1414
1415    #[test]
1416    fn test_sql_string_valid_update() {
1417        let sql = sql_string!("UPDATE users SET name = 'bob' WHERE id = 1");
1418        assert!(sql.contains("UPDATE"));
1419    }
1420
1421    #[test]
1422    fn test_sql_string_valid_delete() {
1423        let sql = sql_string!("DELETE FROM users WHERE id = 1");
1424        assert!(sql.contains("DELETE"));
1425    }
1426
1427    #[test]
1428    fn test_sql_string_valid_create() {
1429        let sql = sql_string!("CREATE TABLE test (id INT PRIMARY KEY)");
1430        assert!(sql.contains("CREATE"));
1431    }
1432
1433    #[test]
1434    fn test_sql_string_with_params() {
1435        let sql = sql_string!("SELECT * FROM users WHERE id = ?"; params: 1);
1436        assert!(sql.contains("?"));
1437    }
1438
1439    #[test]
1440    fn test_sql_string_complex_query() {
1441        let sql = sql_string!(
1442            "SELECT u.*, o.total FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE u.status = 'active'"
1443        );
1444        assert!(sql.contains("LEFT JOIN"));
1445    }
1446
1447    #[test]
1448    fn test_sql_string_nested_parens() {
1449        let sql = sql_string!("SELECT * FROM (SELECT * FROM users) t");
1450        assert!(sql.contains("SELECT"));
1451    }
1452}