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}