Skip to main content

sz_orm_core/
lib.rs

1//! # SZ-ORM — Xianshida ORM
2//!
3//! Rust asynchronous ORM workspace (prototype stage), ThinkORM-style compatible.
4//!
5//! ## Architecture Overview
6//!
7//! The SZ-ORM workspace consists of **43 members** (41 sz-orm-* libs + cli + examples):
8//!
9//! ### Core Engine (sz-orm-core)
10//! | Module | Function |
11//! |------|------|
12//! | `model` | `Model` trait — defines table name, primary key, timestamps, soft delete, relations |
13//! | `query` | `QueryBuilder<M>` — chainable API, supports SELECT/INSERT/UPDATE/DELETE/aggregation/pagination/JOIN |
14//! | `dialect` | Multi-database dialects — MySQL (backtick), PostgreSQL (double quote), SQLite, Oracle 23ai |
15//! | `pool` | Asynchronous connection pool — configurable size, timeout, idle reaping, health checks, max lifetime |
16//! | `transaction` | ACID transactions — isolation levels, savepoints, `TransactionManager` for multi-transaction management |
17//! | `migration` | File-based migration system — up/down/rollback/reset/refresh, with `SchemaBuilder` |
18//! | `cache` | Multi-level cache — `MemoryCache`, `MultiLevelCache`, with TTL support |
19//! | `value` | Unified value type — 20 variants (integer/float/string/bytes/UUID/date/JSON/array) |
20//! | `db_type` | Database type enum — MySQL, PostgreSQL, SQLite, Oracle, Redis, MongoDB and 11 total |
21//! | `error` | Error type system — `DbError` (20 variants), `PoolError`, `CacheError`, `TxError` |
22//!
23//! ### Database Adapters
24//! - **sz-orm-sqlx** — sqlx adapter, connects to real MySQL/PostgreSQL/SQLite/Oracle
25//! - **sz-orm-sql-validator** — SQL validation and injection detection
26//!
27//! ### Extension Ecosystem Packages (18)
28//! | Package | Function |
29//! |------|------|
30//! | sz-orm-crypto | Crypto primitives (AES-256-GCM, PBKDF2, HMAC-SHA256) |
31//! | sz-orm-auth | JWT authentication (HS256) |
32//! | sz-orm-scheduler | Cron scheduled task dispatch |
33//! | sz-orm-mqtt | MQTT client (rumqttc) |
34//! | sz-orm-websocket | WebSocket server (tokio-tungstenite) |
35//! | sz-orm-queue | Message queue (RabbitMQ/lapin, Kafka, NATS, ActiveMQ, RocketMQ, Pulsar) |
36//! | sz-orm-storage | Object storage (S3/Alibaba Cloud/Tencent Cloud/Huawei Cloud/Qiniu/Upyun/Local) |
37//! | sz-orm-ai | AI integration (Embedding, RAG, Vector) |
38//! | sz-orm-grpc | gRPC server/client |
39//! | sz-orm-graphql | GraphQL query support |
40//! | sz-orm-es | Elasticsearch integration |
41//! | sz-orm-tracing | Distributed tracing |
42//! | sz-orm-logger | Logging system |
43//! | sz-orm-swagger | API documentation generation |
44//! | sz-orm-masking | Data masking |
45//! | sz-orm-health | Health checks |
46//! | sz-orm-audit | Audit log |
47//! | sz-orm-batch | Batch operations |
48//!
49//! ### Advanced Feature Packages (6)
50//! | Package | Function |
51//! |------|------|
52//! | sz-orm-dtx | Distributed transactions |
53//! | sz-orm-rw | Read-write splitting |
54//! | sz-orm-sharding | Sharding |
55//! | sz-orm-limit | Rate limiting |
56//! | sz-orm-config | Configuration management |
57//! | sz-orm-mig | Enhanced migration management |
58//!
59//! ### Platform Support
60//! - **sz-orm-wasm** — WebAssembly compile target
61//! - **sz-orm-lc** — Local/edge computing
62//! - **sz-orm-back** — Backup and restore
63//!
64//! ## Quick Start
65//!
66//! ```rust,ignore
67//! use sz_orm_core::*;
68//!
69//! // 1. Define the model
70//! #[derive(Clone)]
71//! struct User {
72//!     id: i64,
73//!     name: String,
74//!     email: String,
75//! }
76//!
77//! impl Model for User {
78//!     type PrimaryKey = i64;
79//!     fn table_name() -> &'static str { "users" }
80//!     fn pk(&self) -> Self::PrimaryKey { self.id }
81//!     fn set_pk(&mut self, pk: Self::PrimaryKey) { self.id = pk; }
82//! }
83//!
84//! // 2. Build a query
85//! let dialect = get_dialect(DbType::MySQL).unwrap();
86//! let sql = QueryBuilder::<User>::new(dialect)
87//!     .table("users")
88//!     .select(vec!["id", "name", "email"])
89//!     .where_eq("status", Value::String("active".to_string()))
90//!     .order_by("created_at")
91//!     .order_desc("id")
92//!     .limit(10)
93//!     .build_select();
94//!
95//! // 3. Validate before execution
96//! QueryBuilder::<User>::new(get_dialect(DbType::MySQL).unwrap())
97//!     .table("users")
98//!     .select(vec!["id", "name"])
99//!     .validate()?; // Validate SQL syntax, injection, parenthesis balance
100//!
101//! // 4. Other operations
102//! let mut data = std::collections::HashMap::new();
103//! data.insert("name".to_string(), Value::String("Alice".to_string()));
104//! data.insert("age".to_string(), Value::I64(25));
105//!
106//! let insert_sql = QueryBuilder::<User>::new(dialect)
107//!     .table("users")
108//!     .build_insert(&data);
109//!
110//! let update_sql = QueryBuilder::<User>::new(get_dialect(DbType::MySQL).unwrap())
111//!     .table("users")
112//!     .where_eq("id", Value::I64(1))
113//!     .build_update(&data);
114//!
115//! let delete_sql = QueryBuilder::<User>::new(get_dialect(DbType::MySQL).unwrap())
116//!     .table("users")
117//!     .where_eq("id", Value::I64(1))
118//!     .build_delete();
119//! ```
120//!
121//! ## Supported Databases
122//!
123//! | Database | Dialect Implementation | Real Connection | Quoting |
124//! |--------|---------|---------|---------|
125//! | MySQL | `MySqlDialect` (`` ` `` backtick) | sz-orm-sqlx | ✅ |
126//! | PostgreSQL | `PostgreSqlDialect` (`"` double quote) | sz-orm-sqlx | ✅ |
127//! | SQLite 3.35+ | `SqliteDialect` (`"` double quote) | sz-orm-sqlx | ✅ |
128//! | Oracle 23ai | `OracleDialect` (automatic type mapping) | sz-orm-sqlx | ✅ |
129//!
130//! Obtain a dialect instance via `get_dialect(DbType::MySQL)`. Each dialect handles:
131//! - Identifier quoting style
132//! - String escaping rules
133//! - Pagination syntax (LIMIT/OFFSET vs OFFSET/FETCH)
134//! - JSON extraction functions (JSON_EXTRACT vs #>> vs json_extract vs JSON_VALUE)
135//! - Full-text search (MATCH AGAINST vs to_tsvector vs CONTAINS)
136//! - Boolean-to-integer conversion (IF/CASE)
137//! - Auto-increment keyword (AUTO_INCREMENT/GENERATED BY DEFAULT AS IDENTITY)
138//!
139//! ## Core Features in Detail
140//!
141//! ### QueryBuilder API
142//!
143//! Most query methods return `Self`, enabling chainable calls; validation methods like `select`/`having`
144//! return `Result<Self>` (after audit M-5/M-6, column names/aggregate expressions go through identifier validation):
145//!
146//! ```rust,ignore
147//! // Basic query
148//! QueryBuilder::<M>::new(dialect)
149//!     .table("users")
150//!     .select(vec!["id", "name"])?                 // Column validation + quote
151//!     .where_eq("status", Value::String("active".to_string()))    // AND
152//!     .or_where_eq("role", Value::String("admin".to_string()))     // OR
153//!     .where_in("id", vec![Value::I64(1), Value::I64(2)])
154//!     .where_between("age", Value::I64(18), Value::I64(30))
155//!     .where_null("deleted_at")
156//!     .order_by("created_at")
157//!     .order_desc("id")
158//!     .group_by("status")
159//!     .having(AggExpr::CountStar, HavingOp::Gt, Value::I64(5))?   // Parameterized HAVING
160//!     .limit(20)
161//!     .offset(40)
162//!     .page(3, 20)                       // page=3, page_size=20
163//!     .join_inner("posts", "users.id", "posts.user_id")
164//!     .join_left("profiles", "users.id", "profiles.user_id")
165//!     .build_select();
166//!
167//! // Aggregate functions
168//! builder.build_count();    // SELECT COUNT(*)
169//! builder.build_exists();   // SELECT EXISTS(...)
170//! builder.build_max("score");
171//! builder.build_min("price");
172//! builder.build_sum("amount");
173//! builder.build_avg("value");
174//! ```
175//!
176//! ### SQL Validation
177//!
178//! ```rust,ignore
179//! // Compile-time + runtime dual validation
180//! builder.validate()?;              // Validate SELECT
181//! builder.validate_insert(&data)?;  // Validate INSERT (including empty data check)
182//! builder.validate_update(&data)?;  // Validate UPDATE (including empty data check)
183//! builder.validate_delete()?;       // Validate DELETE
184//!
185//! // Validation covers: SQL syntax, injection detection, parenthesis balance,
186//! // table/column name legitimacy, JOIN column validation
187//! ```
188//!
189//! ### Model Trait
190//!
191//! ```rust,ignore
192//! pub trait Model: Send + Sync + Sized + 'static {
193//!     type PrimaryKey: Send + Sync + Debug + Display + Clone + Default;
194//!
195//!     fn table_name() -> &'static str;          // Table name (required)
196//!     fn pk_name() -> &'static str { "id" }     // Primary key column name
197//!     fn pk(&self) -> Self::PrimaryKey;         // Get primary key value
198//!     fn set_pk(&mut self, pk: Self::PrimaryKey); // Set primary key value
199//!     fn foreign_key(relation: &str) -> String; // Foreign key naming "user_id"
200//!     fn timestamp_fields() -> Option<TimestampFields>; // Automatic timestamps
201//!     fn soft_delete_field() -> Option<&'static str>;   // Soft delete field
202//! }
203//!
204//! // ModelExt extension
205//! pub trait ModelExt: Model {
206//!     fn columns() -> Vec<&'static str>;     // All columns
207//!     fn fillable() -> Vec<&'static str>;    // Fillable columns
208//!     fn guarded() -> Vec<&'static str>;     // Guarded columns (includes primary key by default)
209//!     fn hidden() -> Vec<&'static str>;      // Hidden columns (not serialized)
210//!     fn relations() -> HashMap<&str, Relation>; // Relations
211//!     fn fill(&mut self, data: HashMap<String, Value>); // Mass assignment
212//!     fn to_json(&self) -> serde_json::Value; // Serialize
213//! }
214//!
215//! // Four relation types
216//! // BelongsTo   — many-to-one (Order → User)
217//! // HasMany     — one-to-many (User → Orders)
218//! // HasOne      — one-to-one (User → Profile)
219//! // BelongsToMany — many-to-many (User ↔ Role, through junction table)
220//! ```
221//!
222//! ### Connection Pool
223//!
224//! ```rust,ignore
225//! // Configure via Builder
226//! let config = PoolConfigBuilder::new()
227//!     .max_size(100)       // Maximum connections
228//!     .min_idle(10)        // Minimum idle connections
229//!     .acquire_timeout(30) // Acquire timeout (seconds)
230//!     .idle_timeout(600)   // Idle timeout (seconds)
231//!     .max_lifetime(1800)  // Max lifetime (seconds)
232//!     .build()?;
233//!
234//! let pool = Pool::new(config, factory)?;
235//! let conn = pool.acquire().await?;  // Acquire connection (with timeout)
236//! pool.release(conn).await;         // Release connection
237//! pool.status().await;               // PoolStatus { idle, active, max, min }
238//! pool.reap_idle().await;           // Reap idle connections
239//! pool.close_all().await;           // Close all connections
240//! ```
241//!
242//! ### Transactions
243//!
244//! ```rust,ignore
245//! // Transaction options
246//! let opts = TransactOptions::default()
247//!     .with_isolation(IsolationLevel::Serializable)
248//!     .read_only()
249//!     .with_timeout(Duration::from_secs(30));
250//!
251//! let mut tx = Transaction::new(conn, opts);
252//! tx.execute("INSERT INTO users VALUES (1)").await?;
253//! tx.query("SELECT * FROM users").await?;
254//!
255//! // Savepoints (nested transactions)
256//! let sp = tx.savepoint().await?;         // SAVEPOINT sp_N
257//! tx.rollback_to_savepoint(&sp).await?;   // ROLLBACK TO SAVEPOINT sp_N
258//! tx.release_savepoint(&sp).await?;       // RELEASE SAVEPOINT sp_N
259//!
260//! tx.commit().await?;
261//! // tx.rollback().await?;
262//!
263//! // TransactionManager: manages multiple named transactions
264//! let mgr = TransactionManager::new();
265//! mgr.begin("tx1", conn, opts).await?;
266//! mgr.commit("tx1").await?;
267//! mgr.list().await;        // ["tx1"]
268//! mgr.state("tx1").await;  // Some(TransactionState::Committed)
269//! ```
270//!
271//! ### Migration System
272//!
273//! ```rust,ignore
274//! // File naming: <version>_<name>_up.sql / <version>_<name>_down.sql
275//! // Example: 001_create_users_up.sql, 001_create_users_down.sql
276//!
277//! let resolver = FileMigrationResolver::new(PathBuf::from("./migrations"));
278//! let migrations = resolver.resolve(DbType::MySQL)?;
279//!
280//! let mut migrator = Migrator::new(MigrationContext::default())
281//!     .add_migrations(migrations);
282//!
283//! migrator.migrate().await?;                     // Execute all pending migrations
284//! migrator.up(Some("003")).await?;               // Migrate up to specified version
285//! migrator.down(Some("001")).await?;             // Rollback to specified version
286//! migrator.rollback("002").await?;               // Rollback a single migration
287//! migrator.reset().await?;                       // Rollback all + re-execute
288//! migrator.refresh().await?;                     // Same as reset
289//! migrator.progress();                            // MigrationProgress { total, applied, pending }
290//!
291//! // SchemaBuilder: programmatic table creation
292//! let sql = SchemaBuilder::new("users")
293//!     .add_column(ColumnDef::new("id", "INT").not_null().auto_increment())
294//!     .add_column(ColumnDef::new("name", "VARCHAR").length(255).not_null())
295//!     .add_index(IndexDef::new("idx_name", vec!["name"]).unique())
296//!     .add_foreign_key(
297//!         ForeignKeyDef::new("fk_role", "role_id", "roles", "id")
298//!             .on_delete("CASCADE")
299//!     )
300//!     .build(DbType::MySQL);
301//! ```
302//!
303//! ### Value Type
304//!
305//! ```rust,ignore
306//! // 20 variants, covering all database types
307//! Value::Null | Bool(bool) | I8..I64 | U8..U64 | F32 | F64
308//! | String(String) | Bytes(Vec<u8>) | Uuid(String) | Date(String)
309//! | DateTime(String) | Time(String) | Json(String) | Array(Vec<Value>)
310//!
311//! // Type conversions
312//! value.as_str()    // Option<&str>
313//! value.as_i64()    // Option<i64> (supports F32/F64/Bool/String→i64 conversion)
314//! value.as_f64()    // Option<f64>
315//! value.as_bool()   // Option<bool> (supports "true"/"1"/"yes"/"on" etc.)
316//! value.as_bytes()  // Option<&[u8]>
317//! value.to_param()  // Cow<str> — SQL parameter format
318//!
319//! // From implementations
320//! let v: Value = 42i64.into();
321//! let v: Value = "hello".into();
322//! let v: Value = vec![1u8, 2u8].into();
323//! ```
324//!
325//! ## Error Handling
326//!
327//! Unified error type system, each error carries a unique error code:
328//!
329//! ```rust,ignore
330//! // DbError — 20 variants, error codes DB001-DB020
331//! DbError::QueryError("...")
332//! DbError::ConnectionRefused("...")
333//! DbError::ConnectionTimeout("...")
334//! DbError::NotFound("...")
335//! DbError::ConstraintViolation("...")
336//! // ... etc.
337//!
338//! // PoolError — 6 variants, error codes PL001-PL006
339//! PoolError::Exhausted | Timeout | AlreadyAcquired | InvalidConfig | ...
340//!
341//! // CacheError — 6 variants, error codes CH001-CH006
342//! // TxError — 6 variants (NotStarted, CommitFailed, SavepointError, etc.)
343//!
344//! // Convenience methods
345//! DbError::query("test failed")        // Create query error
346//! DbError::connection("timeout")       // Create connection error
347//! DbError::not_found("user #42")       // Create not-found error
348//! err.is_retryable()                   // Whether retryable
349//! err.error_code()                     // "DB001"
350//! ```
351//!
352//! ## Validation Methods
353//!
354//! SZ-ORM ensures quality through a **7-layer validation system**:
355//!
356//! | Method | Description | Test File |
357//! |---------|------|---------|
358//! | **TDD** | 115+ unit tests for core modules | `core.rs` |
359//! | **Integration** | End-to-end with real MySQL/PG/SQLite/Oracle | `integration_mysql.rs`, `integration_pg.rs`, `integration_sqlite.rs` |
360//! | **Jepsen** | 29 concurrency correctness tests + 10 real DB Jepsen | `jepsen.rs`, `real_db_jepsen.rs` |
361//! | **Fuzz** | 11 boundary/edge case discoveries | `fuzz.rs` |
362//! | **Stress** | 77 performance benchmarks | `stress.rs`, `core_bench.rs` |
363//! | **Chaos** | 16 fault robustness tests | `chaos.rs` |
364//! | **Formal** | 14 formal verification invariants | `formal.rs` |
365//!
366//! **Total: 1,723 tests** (1,317 `#[test]` + 406 `#[tokio::test]`; some require real services)
367//!
368//! ## Type Aliases and Constants
369//!
370//! ```rust,ignore
371//! // Type aliases
372//! pub type Shared<T> = Arc<T>;
373//! pub type Boxed<T> = Box<T>;
374//! pub type DbResult<T> = Result<T, DbError>;
375//! pub type PoolResult<T> = Result<T, PoolError>;
376//! pub type CacheResult<T> = Result<T, CacheError>;
377//! pub type TxResult<T> = Result<T, TxError>;
378//!
379//! // Default constants
380//! pub const DEFAULT_BATCH_SIZE: usize = 1000;
381//! pub const DEFAULT_ACQUIRE_TIMEOUT: u64 = 30;   // seconds
382//! pub const DEFAULT_IDLE_TIMEOUT: u64 = 600;      // seconds
383//! pub const DEFAULT_MAX_LIFETIME: u64 = 1800;     // seconds
384//! pub const DEFAULT_MIN_IDLE: u32 = 5;
385//! pub const DEFAULT_MAX_SIZE: u32 = 100;
386//! ```
387//!
388//! ## Export Manifest
389//!
390//! `use sz_orm_core::*;` imports all public symbols from the following modules:
391//!
392//! - `async_trait` (re-exported), `bytes::Bytes`, `chrono::{DateTime, Utc}`, `serde::{Deserialize, Serialize}`
393//! - `cache::*` — `Cache`, `MemoryCache`, `MultiLevelCache`, `CacheStats`
394//! - `db_type::*` — `DbType` enum (11 database types)
395//! - `dialect::*` — `Dialect`, `MySqlDialect`, `PostgreSqlDialect`, `SqliteDialect`, `OracleDialect`, `get_dialect()`
396//! - `error::*` — `DbError`, `PoolError`, `CacheError`, `TxError`
397//! - `migration::*` — `Migration`, `Migrator`, `SchemaBuilder`, `ColumnDef`, `IndexDef`, `ForeignKeyDef`
398//! - `model::*` — `Model`, `ModelExt`, `Relation`, `BelongsTo`, `HasMany`, `HasOne`, `BelongsToMany`
399//! - `pool::*` — `Pool`, `PoolConfig`, `PoolConfigBuilder`, `Connection`, `ConnectionFactory`, `PoolStatus`
400//! - `query::*` — `QueryBuilder<M>` (chainable SQL builder)
401//! - `transaction::*` — `Transaction`, `TransactionManager`, `TransactOptions`, `IsolationLevel`
402//! - `value::*` — `Value` enum (20 variants)
403
404// 文档完整性:全局启用 missing_docs lint(v3.6.0 已补齐全部 pub API 文档)
405#![warn(missing_docs)]
406
407// v3.9.0 M1-T3:derive(Validate) 宏生成 sz_orm_core 绝对路径,
408// crate 内部测试需 self 别名使该路径解析到当前 crate
409#[cfg(test)]
410extern crate self as sz_orm_core;
411
412use std::sync::Arc;
413
414/// Re-export async traits
415pub use async_trait::async_trait;
416
417/// Re-export common types
418pub use bytes::Bytes;
419pub use chrono::{DateTime, Utc};
420pub use serde::{Deserialize, Serialize};
421
422pub mod access_control;
423pub mod accessors;
424pub mod active_model;
425pub mod behaviors;
426#[cfg(feature = "benchmark-suite")]
427pub mod benchmark;
428pub mod bloom;
429mod cache;
430pub mod change_tracker;
431pub mod circuit_breaker;
432#[cfg(feature = "type-safe-columns")]
433pub mod column;
434#[cfg(feature = "zero-copy")]
435pub mod columnar;
436pub mod cursor_stream;
437pub mod cycle_detection;
438pub mod data_permission;
439mod db_type;
440pub mod dialect;
441#[cfg(feature = "prod-dialect-security")]
442pub mod dialect_security;
443pub mod dirty_attributes;
444#[cfg(feature = "dist-cache")]
445pub mod dist_cache;
446pub mod dynamic_filter;
447pub mod dynamic_sql;
448pub mod eager_loader;
449pub mod entity_graph;
450mod error;
451pub mod find_with_related;
452#[cfg(feature = "compile-governance")]
453pub mod governance;
454pub mod guard;
455pub mod hooks;
456pub mod hydration_plugin;
457pub mod i18n;
458pub mod join_dsl;
459pub mod json_query;
460#[cfg(feature = "l1-cache")]
461pub mod l1_cache;
462pub mod l2_cache;
463pub mod lambda;
464pub mod lazy_loader;
465pub mod linq;
466pub mod migration;
467#[cfg(feature = "migration-dry-run")]
468pub mod migration_dry_run;
469pub mod mock;
470mod model;
471pub mod n1_eliminator;
472pub mod nested_active_model;
473pub mod observer;
474pub mod optimistic_lock;
475pub mod paginator;
476pub mod partial_model;
477pub mod phinx_migration;
478#[cfg(feature = "plan-cache")]
479pub mod plan_cache;
480mod pool;
481#[cfg(feature = "auto-prewarm")]
482pub mod prewarm;
483#[cfg(feature = "prod-ready")]
484pub mod prod_ready_check;
485mod query;
486pub mod query_cache;
487#[cfg(feature = "data-validation")]
488pub mod validation;
489/// Re-export QueryBuilder for external use
490pub use query::QueryBuilder;
491#[cfg(feature = "cache-coherence")]
492pub mod cache_coherence;
493#[cfg(feature = "l1-cache")]
494#[allow(missing_docs)]
495pub mod cache_warmup_protection;
496#[cfg(feature = "connection-level-tenant")]
497pub mod connection_tenant;
498#[cfg(feature = "forward-compat-sandbox")]
499#[allow(missing_docs)]
500pub mod forward_compat_sandbox;
501#[cfg(feature = "migration-branch")]
502pub mod migration_branch;
503#[cfg(feature = "l1-cache")]
504pub mod process_l1_cache;
505#[cfg(feature = "qb-migration-tool")]
506pub mod qb_migration_fix;
507#[cfg(feature = "qb-migration-tool")]
508pub mod qb_migration_lint;
509pub mod queryable;
510pub mod quick_query;
511pub mod rate_limiter;
512pub mod relation_trait;
513pub mod repository;
514pub mod result_map;
515pub mod retry;
516#[cfg(feature = "zero-downtime-rollback")]
517pub mod rollback_zero_downtime;
518#[cfg(feature = "schema-diff-viz")]
519pub mod schema_diff_viz;
520pub mod schema_gen;
521pub mod schema_sync;
522#[cfg(feature = "data-seeding")]
523pub mod seeding;
524pub mod select_types;
525pub mod shadow;
526#[cfg(feature = "simd")]
527pub mod simd;
528pub mod smart_eager_loader;
529pub mod sql_buffer;
530pub mod sql_safety;
531#[cfg(feature = "sql-verify-proc")]
532pub mod sql_verify;
533pub mod stream_api;
534#[cfg(feature = "streaming-export")]
535pub mod streaming_export;
536pub mod telemetry;
537#[cfg(feature = "multi-tenant-enhanced")]
538pub mod tenant_context;
539#[cfg(feature = "tenant-quota-rls-enhanced")]
540#[allow(missing_docs)]
541pub mod tenant_quota_rls;
542#[cfg(feature = "multi-tenant-enhanced")]
543pub mod tenant_security;
544mod transaction;
545pub mod type_handler;
546pub mod typed;
547pub mod typed_ast;
548#[cfg(feature = "typed-relation")]
549pub mod typed_relation;
550mod value;
551#[cfg(feature = "zero-copy")]
552pub mod value_borrowed;
553
554// Re-export proc macros
555pub use queryable::Query;
556pub use queryable::QueryAs;
557pub use sz_orm_macros::migrate;
558pub use sz_orm_macros::query;
559pub use sz_orm_macros::query_as;
560pub use sz_orm_macros::schema;
561pub use sz_orm_macros::sql_string;
562pub use sz_orm_macros::typed_query;
563// FromQueryResult derive 宏(与 value.rs 中同名 trait 通过显式 use 遮蔽 glob 导出)
564#[cfg(feature = "n1-lint")]
565pub use sz_orm_macros::detect_n_plus_one;
566pub use sz_orm_macros::FromQueryResult;
567pub use sz_orm_macros::RelationTrait;
568#[cfg(feature = "data-validation")]
569pub use sz_orm_macros::Validate;
570
571pub use change_tracker::{ChangeTracker, EntityEntry, EntityState};
572pub use lazy_loader::{LazyCollection, LazyLoader, LazyRef};
573pub use linq::LinqQuery;
574pub use query_cache::{QueryCache, QueryCacheKey, TimestampCache};
575
576pub use cache::*;
577pub use cycle_detection::{CycleDetector, CyclePolicy};
578pub use db_type::*;
579#[allow(ambiguous_glob_reexports)]
580pub use dialect::*;
581pub use eager_loader::NestedEagerResult;
582pub use error::*;
583#[allow(ambiguous_glob_reexports)]
584pub use migration::*;
585pub use model::*;
586pub use nested_active_model::CascadeStrategy;
587pub use pool::*;
588#[allow(unused_imports)]
589pub use query::*;
590pub use schema_sync::{Confirm, DataMigrationHook, DestructiveSyncResult};
591pub use transaction::*;
592pub use value::*;
593
594/// Alias for `Arc<T>`
595pub type Shared<T> = Arc<T>;
596
597/// Alias for `Box<T>`
598pub type Boxed<T> = Box<T>;
599
600/// Alias for Result<T, DbError>
601pub type DbResult<T> = Result<T, DbError>;
602
603/// Result type for pool operations
604pub type PoolResult<T> = Result<T, PoolError>;
605
606/// Result type for cache operations
607pub type CacheResult<T> = Result<T, CacheError>;
608
609/// Result type for transaction operations
610pub type TxResult<T> = Result<T, TxError>;
611
612/// Default batch size for bulk operations
613pub const DEFAULT_BATCH_SIZE: usize = 1000;
614
615/// Default connection timeout in seconds
616pub const DEFAULT_ACQUIRE_TIMEOUT: u64 = 30;
617
618/// Default idle timeout in seconds
619pub const DEFAULT_IDLE_TIMEOUT: u64 = 600;
620
621/// Default max lifetime in seconds
622pub const DEFAULT_MAX_LIFETIME: u64 = 1800;
623
624/// Default minimum idle connections
625pub const DEFAULT_MIN_IDLE: u32 = 5;
626
627/// Default maximum pool size
628pub const DEFAULT_MAX_SIZE: u32 = 100;
629
630#[cfg(test)]
631mod tests {
632    use super::*;
633    use std::error::Error;
634
635    #[test]
636    fn test_db_type() {
637        assert_eq!(DbType::MySQL.as_str(), "mysql");
638        assert_eq!(DbType::PostgreSQL.as_str(), "postgres");
639        assert_eq!(DbType::Sqlite.as_str(), "sqlite");
640    }
641
642    #[test]
643    fn test_value() {
644        let v = Value::Null;
645        assert!(v.is_null());
646
647        let v = Value::I64(42);
648        assert!(v.is_i64());
649
650        let v = Value::String("hello".to_string());
651        assert!(v.is_string());
652    }
653
654    #[test]
655    fn test_db_error_display() {
656        let err = DbError::QueryError("test query failed".to_string());
657        assert_eq!(format!("{}", err), "Query error: test query failed");
658
659        let err = DbError::ConnectionRefused("localhost".to_string());
660        assert_eq!(format!("{}", err), "Connection refused: localhost");
661    }
662
663    #[test]
664    fn test_db_error_source() {
665        let err = DbError::PoolError(PoolError::Timeout);
666        assert!(err.source().is_some());
667    }
668
669    #[tokio::test]
670    async fn test_async_trait_export() {
671        fn _check_send_sync<T: Send + Sync>() {}
672
673        struct TestImpl;
674        #[async_trait]
675        trait AsyncFoo: Send + Sync {
676            async fn foo(&self);
677        }
678
679        #[async_trait]
680        impl AsyncFoo for TestImpl {
681            async fn foo(&self) {}
682        }
683
684        let impl_ = TestImpl;
685        impl_.foo().await;
686        _check_send_sync::<TestImpl>();
687    }
688
689    // ---- compile-time SQL validation macro tests ----
690
691    /// Valid SQL should compile and be usable as a string
692    #[test]
693    fn test_sql_string_valid_select() {
694        let sql = sql_string!("SELECT * FROM users WHERE id = 1");
695        assert!(sql.contains("SELECT"));
696        assert!(sql.contains("FROM"));
697    }
698
699    #[test]
700    fn test_sql_string_valid_insert() {
701        let sql = sql_string!("INSERT INTO users (name) VALUES ('alice')");
702        assert!(sql.contains("INSERT"));
703    }
704
705    #[test]
706    fn test_sql_string_valid_update() {
707        let sql = sql_string!("UPDATE users SET name = 'bob' WHERE id = 1");
708        assert!(sql.contains("UPDATE"));
709    }
710
711    #[test]
712    fn test_sql_string_valid_delete() {
713        let sql = sql_string!("DELETE FROM users WHERE id = 1");
714        assert!(sql.contains("DELETE"));
715    }
716
717    #[test]
718    fn test_sql_string_valid_create() {
719        let sql = sql_string!("CREATE TABLE test (id INT PRIMARY KEY)");
720        assert!(sql.contains("CREATE"));
721    }
722
723    #[test]
724    fn test_sql_string_with_params() {
725        let sql = sql_string!("SELECT * FROM users WHERE id = ?"; params: 1);
726        assert!(sql.contains("?"));
727    }
728
729    #[test]
730    fn test_sql_string_complex_query() {
731        let sql = sql_string!(
732            "SELECT u.*, o.total FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE u.status = 'active'"
733        );
734        assert!(sql.contains("LEFT JOIN"));
735    }
736
737    #[test]
738    fn test_sql_string_nested_parens() {
739        let sql = sql_string!("SELECT * FROM (SELECT * FROM users) t");
740        assert!(sql.contains("SELECT"));
741    }
742}