1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
//! # OxiMod
//!
//! Schema-aware MongoDB modeling for Rust.
//!
//! OxiMod is a lightweight modeling layer built on top of the official
//! MongoDB Rust driver. It provides builder-style model construction,
//! validation, defaults, index declarations, and optional lifecycle hooks,
//! while preserving direct access to the underlying driver when needed.
//!
//! ## Features
//!
//! - derive-based model definitions
//! - builder-style model construction
//! - validation and defaults
//! - index declarations
//! - optional lifecycle hooks
//! - global and explicit-client workflows
//! - typed and raw MongoDB collection access
//!
//! ## Quick Start
//!
//! ```rust,no_run
//! use mongodb::bson::{doc, oid::ObjectId};
//! use oximod::{Model, OxiClient};
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Debug, Serialize, Deserialize, Model)]
//! #[db("my_app_db")]
//! #[collection("users")]
//! struct User {
//! #[serde(skip_serializing_if = "Option::is_none")]
//! _id: Option<ObjectId>,
//!
//! #[index(unique, name = "email_idx")]
//! #[validate(email)]
//! email: String,
//!
//! #[validate(min_length = 3, max_length = 32)]
//! name: String,
//!
//! #[validate(non_negative)]
//! age: i32,
//!
//! #[default(false)]
//! active: bool,
//! }
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! OxiClient::init_global("mongodb://localhost:27017".to_string()).await?;
//!
//! User::clear().await?;
//!
//! let user = User::new()
//! .email("alice@example.com")
//! .name("Alice")
//! .age(30)
//! .active(true);
//!
//! let id = user.save().await?;
//!
//! if let Some(found) = User::find_by_id(id).await? {
//! println!("Found user: {}", found.name);
//! }
//!
//! let count = User::count(doc! {}).await?;
//! println!("Total users: {}", count);
//!
//! let collection = User::get_collection()?;
//!
//! collection
//! .update_one(
//! doc! { "_id": id },
//! doc! { "$set": { "active": false } },
//! )
//! .await?;
//!
//! Ok(())
//! }
//! ```
//!
//! For more complete examples, see the
//! [`examples/`](https://github.com/arshia-eskandari/oximod/tree/main/oximod/examples) directory.
// --- public API ---
/// Primary error type used by OxiMod.
///
/// This type is returned by model operations that fail due to validation,
/// hook execution, client initialization, or MongoDB driver errors.
pub use OxiModError;
/// Represents a validation failure for a specific model field.
pub use ValidationError;
/// Represents one or more validation failures collected during model validation.
pub use ValidationErrors;
/// MongoDB client wrapper used by OxiMod.
///
/// `OxiClient` supports both global and explicit-client workflows.
///
/// Global usage:
///
/// ```rust,no_run
/// use oximod::OxiClient;
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// OxiClient::init_global("mongodb://localhost:27017".to_string()).await?;
/// Ok(())
/// }
/// ```
///
/// Explicit usage:
///
/// ```rust,no_run
/// use mongodb::bson::oid::ObjectId;
/// use oximod::{Model, OxiClient};
/// use serde::{Deserialize, Serialize};
///
/// #[derive(Debug, Serialize, Deserialize, Model)]
/// #[db("app")]
/// #[collection("users")]
/// struct User {
/// #[serde(skip_serializing_if = "Option::is_none")]
/// _id: Option<ObjectId>,
/// name: String,
/// }
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// OxiClient::init_global("mongodb://localhost:27017".to_string()).await?;
///
/// let user = User::new().name("Alice");
/// let _id = user.save().await?;
///
/// Ok(())
/// }
/// ```
pub use OxiClient;
/// Trait for defining lifecycle hooks on OxiMod models.
///
/// Hooks allow custom logic to run before and after save, update, delete,
/// and query operations.
///
/// Hooks are optional and must be enabled with `#[hooks]` on the model.
pub use Hooks;
/// Core trait implemented by all OxiMod models.
///
/// This trait provides the primary model API, including persistence,
/// lookup, mutation, counting, existence checks, and access to both typed
/// and raw MongoDB collections.
///
/// It is implemented automatically by `#[derive(Model)]`.
pub use Model;
/// Derive macro for defining OxiMod models.
///
/// This macro generates:
///
/// - builder methods
/// - model methods
/// - validation support
/// - default handling
/// - index initialization
/// - optional hook integration
///
/// # Example
///
/// ```rust
/// use oximod::Model;
/// use serde::{Deserialize, Serialize};
///
/// #[derive(Debug, Serialize, Deserialize, Model)]
/// #[db("app")]
/// #[collection("users")]
/// struct User {
/// name: String,
/// }
/// ```
pub use Model;
// --- Internal API ---
pub use async_trait as _async_trait;
pub use futures_util as _futures_util;
pub use mongodb as _mongodb;
pub use feature as _feature;
pub use helpers as _helpers;
pub use regex as _regex; // removes the need of importing the trait