libsql_orm/lib.rs
1//! # libsql-orm
2//!
3//! A powerful, async-first ORM for [libsql](https://github.com/libsql/libsql) with first-class support for **Cloudflare Workers** and WebAssembly environments.
4//!
5//! ## ✨ Features
6//!
7//! - 🚀 **Cloudflare Workers Ready** - Built specifically for edge computing environments
8//! - 🔄 **Async/Await Support** - Fully async API with excellent performance
9//! - 🎯 **Type-Safe** - Leverages Rust's type system for compile-time safety
10//! - 📊 **Rich Query Builder** - Fluent API for complex queries
11//! - 🔍 **Advanced Filtering** - Search, pagination, sorting, and aggregations
12//! - 🛠️ **Migration System** - Database schema management and versioning
13//! - 🎨 **Derive Macros** - Automatic model generation with `#[derive(Model)]`
14//! - 📦 **Bulk Operations** - Efficient batch inserts, updates, and deletes
15//! - 🌐 **WASM Compatible** - Optimized for WebAssembly targets
16//! - 🔄 **Type Conversion** - Automatic conversion between SQLite and Rust types
17//! - 🔄 **Upsert Operations** - Smart create_or_update and upsert methods
18//! - 📝 **Built-in Logging** - Comprehensive logging for debugging and monitoring
19//!
20//! ## 🚀 Quick Start
21//!
22//! ```rust
23//! use libsql_orm::{Model, Database};
24//! use serde::{Deserialize, Serialize};
25//! use chrono::{DateTime, Utc};
26//!
27//! #[derive(Model, Debug, Clone, Serialize, Deserialize)]
28//! struct User {
29//! pub id: Option<i64>,
30//! pub name: String,
31//! pub email: String,
32//! pub age: Option<i32>,
33//! pub is_active: bool,
34//! pub created_at: DateTime<Utc>,
35//! }
36//!
37//! async fn example() -> Result<(), Box<dyn std::error::Error>> {
38//! // Connect to database
39//! let db = Database::new_connect("libsql://your-db.turso.io", "your-auth-token").await?;
40//!
41//! // Create a user
42//! let user = User {
43//! id: None,
44//! name: "Alice".to_string(),
45//! email: "alice@example.com".to_string(),
46//! age: Some(30),
47//! is_active: true,
48//! created_at: Utc::now(),
49//! };
50//!
51//! // Save to database
52//! let saved_user = user.create(&db).await?;
53//! println!("Created user with ID: [MASKED]");
54//!
55//! // Find users
56//! let users = User::find_all(&db).await?;
57//! println!("Found {} users", users.len());
58//!
59//! // Use smart upsert operations
60//! let user_with_id = User {
61//! id: Some(123), // Will update if exists, create if not
62//! name: "Updated Name".to_string(),
63//! email: "updated@example.com".to_string(),
64//! age: Some(31),
65//! is_active: true,
66//! created_at: Utc::now(),
67//! };
68//! let smart_saved = user_with_id.create_or_update(&db).await?;
69//!
70//! // Upsert by unique constraint
71//! let unique_user = User {
72//! id: None,
73//! name: "Unique User".to_string(),
74//! email: "unique@example.com".to_string(), // Check by email
75//! age: Some(25),
76//! is_active: true,
77//! created_at: Utc::now(),
78//! };
79//! let upserted = unique_user.upsert(&["email"], &db).await?;
80//!
81//! Ok(())
82//! }
83//! ```
84//!
85//! ## 🔄 Upsert Operations
86//!
87//! Smart create-or-update operations for efficient data management:
88//!
89//! ```rust
90//! use libsql_orm::{Model, Database};
91//!
92//! // Method 1: create_or_update (based on primary key)
93//! let user = User { id: Some(123), name: "John".to_string(), ... };
94//! let saved = user.create_or_update(&db).await?; // Updates if ID exists, creates if not
95//!
96//! // Method 2: upsert (based on unique constraints)
97//! let user = User { id: None, email: "john@example.com".to_string(), ... };
98//! let saved = user.upsert(&["email"], &db).await?; // Updates if email exists, creates if not
99//!
100//! // Multiple unique constraints
101//! let saved = user.upsert(&["email", "username"], &db).await?;
102//! ```
103//!
104//! ## 📝 Built-in Logging
105//!
106//! Comprehensive logging for debugging and monitoring:
107//!
108//! ```rust
109//! // All database operations are automatically logged
110//! // Logs appear in browser console (WASM) or standard logging (native)
111//!
112//! let user = User::new("John", "john@example.com");
113//!
114//! // Logs: [INFO] users: Creating record in table: users
115//! // Logs: [DEBUG] users: SQL: INSERT INTO users (...) VALUES (...)
116//! let saved = user.create(&db).await?;
117//!
118//! // Logs: [DEBUG] users: Finding record by ID: 123
119//! let found = User::find_by_id(123, &db).await?;
120//!
121//! // Logs: [INFO] users: Updating record with ID: 123
122//! let updated = found.unwrap().update(&db).await?;
123//! ```
124//!
125//! ## 📚 Advanced Usage
126//!
127//! ### Custom Table Names and Boolean Type Safety
128//!
129//! ```rust
130//! use libsql_orm::{Model, orm_column, deserialize_bool};
131//! use serde::{Serialize, Deserialize};
132//!
133//! #[derive(Model, Debug, Clone, Serialize, Deserialize)]
134//! #[table_name("user_accounts")] // Custom table name
135//! struct User {
136//! #[orm_column(type = "INTEGER PRIMARY KEY AUTOINCREMENT")]
137//! pub id: Option<i64>,
138//!
139//! #[orm_column(not_null, unique)]
140//! pub email: String,
141//!
142//! pub is_active: bool, // ✅ Automatic SQLite integer ↔ Rust bool conversion
143//! pub is_verified: bool, // ✅ Type-safe boolean operations
144//!
145//! // For edge cases, use custom deserializer
146//! #[serde(deserialize_with = "deserialize_bool")]
147//! pub has_premium: bool, // ✅ Manual boolean conversion
148//!
149//! #[orm_column(type = "TEXT DEFAULT 'active'")]
150//! pub status: String,
151//! }
152//!
153//! // Boolean filtering works seamlessly
154//! let active_users = User::find_where(
155//! FilterOperator::Eq("is_active".to_string(), Value::Boolean(true)),
156//! &db
157//! ).await?;
158//! ```
159//!
160//! ### Query Builder
161//!
162//! ```rust
163//! use libsql_orm::{QueryBuilder, FilterOperator, Sort, SortOrder, Pagination};
164//!
165//! // Complex query with filtering and pagination
166//! let query = QueryBuilder::new("users")
167//! .select(&["id", "name", "email"])
168//! .r#where(FilterOperator::Gte("age".to_string(), Value::Integer(18)))
169//! .order_by(Sort::new("created_at", SortOrder::Desc))
170//! .limit(10)
171//! .offset(20);
172//!
173//! let (sql, params) = query.build()?;
174//! ```
175//!
176//! ### Cloudflare Workers Integration
177//!
178//! ```rust
179//! use worker::*;
180//! use libsql_orm::{Model, Database, MigrationManager, generate_migration};
181//!
182//! #[event(fetch)]
183//! async fn fetch(req: Request, env: Env, _ctx: Context) -> Result<Response> {
184//! let database_url = env.var("LIBSQL_DATABASE_URL")?.to_string();
185//! let auth_token = env.var("LIBSQL_AUTH_TOKEN")?.to_string();
186//!
187//! let db = Database::new_connect(&database_url, &auth_token).await
188//! .map_err(|e| format!("Database connection failed: {}", e))?;
189//!
190//! // Your application logic here
191//! let users = User::find_all(&db).await
192//! .map_err(|e| format!("Query failed: {}", e))?;
193//!
194//! Response::from_json(&users)
195//! }
196//! ```
197pub mod database;
198pub mod error;
199pub mod filters;
200pub mod macros;
201pub mod migrations;
202pub mod model;
203pub mod pagination;
204pub mod query;
205pub mod types;
206
207#[cfg(test)]
208mod tests;
209
210pub use database::Database;
211pub use error::{Error, Result};
212pub use filters::{Filter, FilterOperator, SearchFilter, Sort};
213pub use migrations::{templates, Migration, MigrationBuilder, MigrationManager};
214pub use model::Model;
215pub use pagination::{CursorPaginatedResult, CursorPagination, PaginatedResult, Pagination};
216pub use query::{QueryBuilder, QueryResult};
217pub use types::*;
218
219// Export the boolean deserializer
220pub use types::deserialize_bool;
221
222// Re-export commonly used types
223pub use chrono;
224pub use serde::{Deserialize, Serialize};
225pub use uuid::Uuid;
226
227/// Re-export the Model macro for convenience
228pub use libsql_orm_macros::{generate_migration, orm_column, Model};