tideorm 0.7.0

A developer-friendly ORM for Rust with clean, expressive syntax
Documentation
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
//! # TideORM
//!
//! A developer-friendly ORM for Rust with clean, expressive syntax.
//!
//! ## Quick Start
//!
//! ```rust,ignore
//! use tideorm::prelude::*;
//!
//! #[derive(Model)]
//! #[tide(table = "users")]
//! pub struct User {
//!     #[tide(primary_key, auto_increment)]
//!     pub id: i64,
//!     pub email: String,
//!     pub name: String,
//! }
//!
//! #[tokio::main]
//! async fn main() -> tideorm::Result<()> {
//!     // Initialize TideORM with database and configuration
//!     TideConfig::init()
//!         .database("postgres://localhost/myapp")
//!         .max_connections(20)
//!         .min_connections(5)
//!         .connect()
//!         .await?;
//!     
//!     // Create a record
//!     let mut user = User {
//!         id: 0,
//!         email: "john@example.com".to_string(),
//!         name: "John Doe".to_string(),
//!     };
//!     user = user.save().await?;
//!     
//!     // Find by ID
//!     let user = User::find(1).await?;
//!     
//!     // Query with conditions
//!     let users = User::query()
//!         .where_eq("name", "John")
//!         .order_by("created_at", Order::Desc)
//!         .limit(10)
//!         .get()
//!         .await?;
//!     
//!     // Update
//!     user.name = "Jane Doe".to_string();
//!     let user = user.update().await?;
//!     
//!     // Delete
//!     user.delete().await?;
//!     
//!     Ok(())
//! }
//! ```
//!
//! ## Features
//!
//! - **Clean Model Definitions** - Use `#[derive(Model)]` to define your models
//! - **Unified Configuration** - Database, pool settings, and app config in one place
//! - **Global Database Connection** - Initialize once, use anywhere
//! - **Production-Ready Pool Settings** - Configure min/max connections, timeouts
//! - **Fluent Query Builder** - Chain methods for readable queries
//! - **Type Safe** - Full Rust type safety without verbose syntax
//! - **Async First** - Built for async/await from the ground up
//! - **Database Agnostic** - PostgreSQL, MySQL, SQLite support
//! - **Zero SeaORM Exposure** - SeaORM is an internal implementation detail
//! - **Query Logging & Debugging** - Built-in query logging with timing and slow query detection
//! - **Performance Profiling** - Query analysis and optimization suggestions
//! - **Helpful Error Messages** - Clear errors with suggestions for fixes
//!
//! ## Query Logging
//!
//! Enable query logging for debugging:
//!
//! ```rust,ignore
//! use tideorm::prelude::*;
//!
//! // Enable via environment variable
//! // TIDE_LOG_QUERIES=true cargo run
//!
//! // Or enable programmatically
//! QueryLogger::global()
//!     .set_level(LogLevel::Debug)
//!     .set_slow_query_threshold_ms(100)
//!     .enable();
//!
//! // Debug a specific query
//! let debug_info = User::query()
//!     .where_eq("active", true)
//!     .where_gt("age", 18)
//!     .debug();
//! println!("{}", debug_info);
//! ```
//!
//! ## Performance Profiling
//!
//! Profile query performance:
//!
//! ```rust,ignore
//! use tideorm::prelude::*;
//!
//! // Start profiling
//! let profiler = Profiler::start();
//!
//! // Execute queries
//! let users = User::all().await?;
//!
//! // Get report
//! let report = profiler.stop();
//! println!("{}", report);
//! ```
//!
//! ## Model Definition
//!
//! Models are defined using the `#[derive(Model)]` macro with field-level attributes:
//!
//! ```rust,ignore
//! #[derive(Model)]
//! #[tide(table = "posts", soft_delete)]
//! #[index("user_id")]
//! #[unique_index("slug")]
//! pub struct Post {
//!     #[tide(primary_key, auto_increment)]
//!     pub id: i64,
//!     
//!     pub user_id: i64,
//!     pub slug: String,
//!     pub title: String,
//!     pub content: String,
//!     pub published: bool,
//!     
//!     // Auto-managed timestamps
//!     pub created_at: DateTime<Utc>,
//!     pub updated_at: DateTime<Utc>,
//!     
//!     // Soft delete support
//!     pub deleted_at: Option<DateTime<Utc>>,
//!
//!     // JSON and array fields (PostgreSQL)
//!     pub metadata: Json,                    // JSONB column
//!     pub tags: TextArray,                   // TEXT[] column
//!     pub scores: IntArray,                  // INTEGER[] column
//! }
//! ```
//!
//! ### JSON and Array Field Types
//!
//! TideORM supports PostgreSQL's native JSON and array types:
//!
//! | Rust Type | PostgreSQL Type | Description |
//! |-----------|-----------------|-------------|
//! | `Json` | `JSONB` | JSON data storage |
//! | `Jsonb` | `JSONB` | Alias for Json |
//! | `IntArray` | `INTEGER[]` | Array of integers |
//! | `BigIntArray` | `BIGINT[]` | Array of big integers |
//! | `TextArray` | `TEXT[]` | Array of strings |
//! | `BoolArray` | `BOOLEAN[]` | Array of booleans |
//! | `FloatArray` | `DOUBLE PRECISION[]` | Array of floats |
//! | `JsonArray` | `JSONB[]` | Array of JSON objects |
//!
//! ### Field Attributes
//!
//! | Attribute | Description |
//! |-----------|-------------|
//! | `#[tide(primary_key)]` | Marks the primary key field |
//! | `#[tide(auto_increment)]` | Auto-incrementing field (usually with primary_key) |
//! | `#[tide(column = "name")]` | Override the column name |
//! | `#[tide(skip)]` | Skip this field in database operations |
//!
//! ### Table Attributes
//!
//! | Attribute | Description |
//! |-----------|-------------|
//! | `#[tide(table = "name")]` | Override the table name |
//! | `#[tide(soft_delete)]` | Enable soft delete support |
//! | `#[index("col1,col2")]` | Create a composite index |
//! | `#[unique_index("col")]` | Create a unique index |
//!
//! ## Query Builder
//!
//! The fluent query builder supports all common operations:
//!
//! ```rust,ignore
//! // WHERE conditions
//! User::query()
//!     .where_eq("status", "active")      // WHERE status = 'active'
//!     .where_not("role", "banned")       // AND role != 'banned'
//!     .where_in("tier", vec!["gold", "platinum"])  // AND tier IN (...)
//!     .where_like("email", "%@company.com")       // AND email LIKE ...
//!     .where_null("deleted_at")          // AND deleted_at IS NULL
//!     .where_between("age", 18, 65)      // AND age BETWEEN 18 AND 65
//!     .get()
//!     .await?;
//!
//! // Ordering, pagination
//! User::query()
//!     .order_by("created_at", Order::Desc)
//!     .limit(10)
//!     .offset(20)
//!     .get()
//!     .await?;
//!
//! // Pagination helper
//! let page = User::query()
//!     .where_eq("active", true)
//!     .page(2, 25)  // Page 2, 25 per page
//!     .get()
//!     .await?;
//!
//! // Counting
//! let count = User::query()
//!     .where_eq("active", true)
//!     .count()
//!     .await?;
//!
//! // Bulk delete
//! let deleted = User::query()
//!     .where_eq("status", "inactive")
//!     .delete()
//!     .await?;  // Returns number of deleted rows
//! ```
//!
//! ### JSON Operations (PostgreSQL)
//!
//! Query JSON and JSONB columns with native PostgreSQL operators:
//!
//! ```rust,ignore
//! // JSON containment: column @> value
//! User::query()
//!     .where_json_contains("metadata", serde_json::json!({"role": "admin"}))
//!     .get()
//!     .await?;
//!
//! // JSON key existence: column ? key
//! User::query()
//!     .where_json_key_exists("settings", "theme")
//!     .get()
//!     .await?;
//!
//! // JSON path queries: column @? path
//! User::query()
//!     .where_json_path_exists("preferences", "$.notifications.email")
//!     .get()
//!     .await?;
//! ```
//!
//! ### Array Operations (PostgreSQL)
//!
//! Query array columns with native PostgreSQL operators:
//!
//! ```rust,ignore
//! // Array containment: column @> ARRAY[values]
//! User::query()
//!     .where_array_contains("tags", vec!["rust", "postgres"])
//!     .get()
//!     .await?;
//!
//! // Array overlap (contains any): column && ARRAY[values]
//! User::query()
//!     .where_array_overlaps("skills", vec!["javascript", "react"])
//!     .get()
//!     .await?;
//!
//! // Array contains all: ARRAY[values] <@ column
//! User::query()
//!     .where_array_contains_all("permissions", vec!["read", "write"])
//!     .get()
//!     .await?;
//! ```
//!
//! ### Conditional Queries (Scopes)
//!
//! ```rust,ignore
//! // Build queries conditionally
//! User::query()
//!     .when(filter.is_some(), |q| q.where_eq("status", filter.unwrap()))
//!     .when_some(search_term, |q, term| q.where_like("name", format!("%{}%", term)))
//!     .get()
//!     .await?;
//! ```
//!
//! ## Soft Delete
//!
//! Models with `#[tide(soft_delete)]` support soft deletion:
//!
//! ```rust,ignore
//! // Regular queries exclude soft-deleted records
//! let users = User::all().await?;
//!
//! // Include soft-deleted records
//! let all_users = User::query().with_trashed().get().await?;
//!
//! // Only soft-deleted records
//! let deleted = User::query().only_trashed().get().await?;
//!
//! // Soft delete
//! user.soft_delete().await?;
//!
//! // Restore
//! user.restore().await?;
//!
//! // Force delete (permanent)
//! user.force_delete().await?;
//! ```
//!
//! ## Callbacks
//!
//! Implement lifecycle hooks for your models:
//!
//! ```rust,ignore
//! impl Callbacks for User {
//!     fn before_save(&mut self) -> tideorm::Result<()> {
//!         // Normalize email before saving
//!         self.email = self.email.to_lowercase();
//!         Ok(())
//!     }
//!     
//!     fn after_create(&self) -> tideorm::Result<()> {
//!         // Send welcome email
//!         println!("User {} created!", self.email);
//!         Ok(())
//!     }
//! }
//! ```
//!
//! Available callbacks:
//! - `before_validation`, `after_validation`
//! - `before_save`, `after_save`
//! - `before_create`, `after_create`
//! - `before_update`, `after_update`
//! - `before_delete`, `after_delete`
//!
//! ## Model Relations
//!
//! Define relationships between models:
//!
//! ```rust,ignore
//! // BelongsTo: Post belongs to User
//! impl BelongsTo<User> for Post {
//!     fn foreign_key() -> &'static str { "user_id" }
//! }
//!
//! // HasMany: User has many Posts
//! impl HasMany<Post> for User {
//!     fn foreign_key() -> &'static str { "user_id" }
//! }
//!
//! // Load relations
//! let post = Post::find(1).await?;
//! let author: User = post.load_belongs_to().await?;
//!
//! let user = User::find(1).await?;
//! let posts: Vec<Post> = user.load_has_many().await?;
//! ```
//!
//! ## Batch Operations
//!
//! ```rust,ignore
//! // Insert many records at once
//! let users = vec![user1, user2, user3];
//! let inserted = User::insert_all(users).await?;
//!
//! // Update many records with conditions
//! User::update_all()
//!     .set("status", "inactive")
//!     .where_eq("last_login_at", None::<DateTime<Utc>>)
//!     .execute()
//!     .await?;
//! ```
//!
//! ## Raw SQL
//!
//! When you need raw SQL access:
//!
//! ```rust,ignore
//! // Execute raw SQL
//! Database::execute("TRUNCATE TABLE temp_data").await?;
//!
//! // Query with parameters
//! let users: Vec<User> = Database::raw(
//!     "SELECT * FROM users WHERE status = $1 AND age > $2"
//! ).await?;
//! ```
//!
//! ## Schema Generation
//!
//! Auto-generate schema files from database introspection:
//!
//! ```rust,ignore
//! // Configure to auto-generate schema on connect
//! TideConfig::init()
//!     .database("postgres://localhost/myapp")
//!     .schema_file("schema.sql")  // Auto-generates on connect
//!     .connect()
//!     .await?;
//!
//! // Or generate manually
//! SchemaWriter::write_schema("schema.sql").await?;
//! ```
//!
//! ## Multi-Database Support
//!
//! TideORM supports PostgreSQL, MySQL, and SQLite:
//!
//! ```rust,ignore
//! // PostgreSQL
//! TideConfig::init()
//!     .database_type(DatabaseType::Postgres)
//!     .database("postgres://user:pass@localhost/db")
//!     .connect()
//!     .await?;
//!
//! // MySQL
//! TideConfig::init()
//!     .database_type(DatabaseType::MySQL)
//!     .database("mysql://user:pass@localhost/db")
//!     .connect()
//!     .await?;
//!
//! // SQLite
//! TideConfig::init()
//!     .database_type(DatabaseType::SQLite)
//!     .database("sqlite:./data.db")
//!     .connect()
//!     .await?;
//! ```
//!
//! ## Connection Pool Configuration
//!
//! ```rust,ignore
//! TideConfig::init()
//!     .database("postgres://localhost/myapp")
//!     .max_connections(50)           // Maximum connections
//!     .min_connections(5)            // Minimum idle connections
//!     .connect_timeout(Duration::from_secs(30))
//!     .idle_timeout(Duration::from_secs(600))
//!     .max_lifetime(Duration::from_secs(1800))
//!     .connect()
//!     .await?;
//! ```
//!
//! ## Query Logging
//!
//! Enable query logging for debugging:
//!
//! ```bash
//! TIDE_LOG_QUERIES=true cargo run
//! ```
//!
//! ## Error Handling
//!
//! TideORM provides descriptive error types:
//!
//! ```rust,ignore
//! match User::find(999).await {
//!     Ok(user) => println!("Found: {}", user.name),
//!     Err(Error::NotFound { message, .. }) => println!("User not found: {}", message),
//!     Err(Error::Connection { message }) => println!("Database error: {}", message),
//!     Err(e) => println!("Other error: {}", e),
//! }
//! ```
//!
//! ## Design Philosophy
//!
//! TideORM is designed with these principles:
//!
//! 1. **Convention over Configuration** - Smart defaults, minimal boilerplate
//! 2. **Developer Happiness** - APIs that feel natural and are hard to misuse
//! 4. **Type Safety** - Catch errors at compile time when possible
//! 5. **Performance** - Zero-cost abstractions where possible

#![recursion_limit = "256"]
#![warn(missing_docs)]
#![warn(clippy::all)]
#![deny(unsafe_code)]

#[doc(hidden)]
pub mod internal;

/// Re-export sea_orm for internal macro use only
#[doc(hidden)]
pub use sea_orm;

// ============================================================================
// PUBLIC MODULES
// ============================================================================

/// Error types for TideORM
pub mod error;

/// Database connection and pool management
pub mod database;

/// Model trait and utilities
pub mod model;

/// Fluent query builder
pub mod query;

/// Attribute types and casting
pub mod types;

/// Soft delete support
pub mod soft_delete;

/// Callbacks and hooks for model lifecycle events
pub mod callbacks;

/// Database schema synchronization (DB_SYNC=true)
pub mod sync;

/// Schema generation (SQL file export)
pub mod schema;

/// Model relations (belongs_to, has_one, has_many)
pub mod relations;

/// File attachments system (attach, detach, sync)
pub mod attachments;

/// Translations system for multi-language support
pub mod translations;

/// Global configuration
pub mod config;

/// Database migrations
pub mod migration;

/// Query logging and debugging
pub mod logging;

/// Performance profiling
pub mod profiling;

/// Query caching and prepared statement caching
pub mod cache;

/// Database seeding system
pub mod seeding;

/// Model validation system
pub mod validation;

/// Full-text search support
pub mod fulltext;

/// Strongly-typed columns for compile-time type safety
pub mod columns;

/// Record tokenization for secure ID encoding
pub mod tokenization;

/// Re-exports for convenience
pub mod prelude;

// ============================================================================
// PUBLIC RE-EXPORTS
// ============================================================================

pub use database::Database;
// Global database access functions
pub use database::{db, try_db, has_global_db, require_db};
pub use error::{Error, Result};
pub use model::{Model, ModelMeta};
pub use query::{QueryBuilder, Order, JoinType, JoinClause, AggregateFunction};
pub use soft_delete::SoftDelete;
pub use config::{TideConfig, Config};
pub use callbacks::{Callbacks, CallbackRunner};
pub use relations::{BelongsTo, HasOne, HasMany, RelationExt, EagerLoadExt, WithRelations};
pub use attachments::{HasAttachments, FileAttachment, FilesData, AttachmentError};
pub use translations::{HasTranslations, TranslationsData, FieldTranslations, TranslationInput, TranslationError, ApplyTranslations};
pub use schema::SchemaWriter;
pub use migration::{Migration, Migrator, Schema, ColumnType};

// Query logging and debugging
pub use logging::{QueryLogger, LogLevel, QueryLogEntry, QueryTimer, QueryStats, QueryDebugInfo, QueryOperation};

// Performance profiling
pub use profiling::{Profiler, ProfileReport, ProfiledQuery, GlobalProfiler, GlobalStats, QueryAnalyzer, QuerySuggestion, QueryComplexity, SuggestionLevel};

// Query and statement caching
pub use cache::{QueryCache, PreparedStatementCache, CacheConfig, CacheStrategy, CacheStats, PreparedStatementStats, PreparedStatementConfig, CacheKeyBuilder, CacheOptions, CachedStatementInfo, CacheWarmer};

// Validation
pub use validation::{Validate, ValidationErrors, ValidationRule, ValidationBuilder, Validator, ValidatableValue};

// Tokenization
pub use tokenization::{TokenConfig, TokenEncoder, TokenDecoder, Tokenizable};

// Re-export the derive macro
pub use tideorm_macros::Model;

// Re-export the attribute macro
pub use tideorm_macros::model;

// Re-export relation attribute macros
pub use tideorm_macros::{belongs_to, has_one, has_many};

// Re-export async_trait for macro use
pub use async_trait;

// Re-export chrono for macro use (timestamps)
pub use chrono;

// Re-export common types that users need
pub use serde::{Deserialize, Serialize};
pub use chrono::{DateTime, NaiveDateTime, Utc};
pub use uuid::Uuid;
pub use rust_decimal::Decimal;