# Ormkit Core ORM Guide
This guide covers the core ORM features for everyday use. Read this to get started with Ormkit in 10-15 minutes.
## Table of Contents
1. [Defining Entities](#defining-entities)
2. [Type-Safe Queries](#type-safe-queries)
3. [Repository Operations](#repository-operations)
4. [Query Builder](#query-builder)
5. [Transactions](#transactions)
6. [Pagination](#pagination)
---
## Defining Entities
Entities represent your database tables as Rust structs.
```rust
use ormkit::Entity;
use uuid::Uuid;
use chrono::{DateTime, Utc};
#[derive(ormkit::Entity, Debug, Clone)]
#[ormkit(table = "users")]
struct User {
#[ormkit(id)]
id: Uuid,
email: String,
name: String,
created_at: DateTime<Utc>,
}
```
**Key Points:**
- `#[ormkit(table = "...")]` specifies the database table name
- `#[ormkit(id)]` marks the primary key field
- Field names must match your database column names (snake_case)
### Supported Types
- `Uuid` - UUID primary keys
- `String` - VARCHAR/TEXT
- `i32`, `i64` - INTEGER/BIGINT
- `f32`, `f64` - REAL/DOUBLE PRECISION
- `bool` - BOOLEAN
- `DateTime<Utc>` - TIMESTAMP
- `serde_json::Value` - JSONB
- `Option<T>` - Nullable columns
---
## Type-Safe Queries
Ormkit provides a fluent, type-safe query DSL:
```rust
use ormkit::Entity;
// Single filter
let user: User = User::query()
.filter(User::email().eq("user@example.com"))
.fetch_one(&pool)
.await?;
// Multiple filters
let users: Vec<User> = User::query()
.filter(User::age().gte(18))
.filter(User::status().eq("active"))
.fetch_all(&pool)
.await?;
// Ordering and limits
let recent_users: Vec<User> = User::query()
.order_by(User::created_at(), ormkit::query::Order::Desc)
.limit(10)
.fetch_all(&pool)
.await?;
```
**Available Operators:**
- `eq`, `ne` - Equality
- `lt`, `lte`, `gt`, `gte` - Comparison
- `like`, `ilike` - Pattern matching
- `is_null`, `is_not_null` - Null checks
- `in` - IN clause
---
## Repository Operations
The `Repository` provides CRUD operations:
```rust
use ormkit::{Repository, Entity};
use ormkit::active_value::ActiveValue;
let repo = Repository::<User>::new(&pool);
// Find by ID
let user = repo.find_by_id(user_id).await?;
// Insert new entity
let mut user_model = UserActiveModel::default();
user_model.email = ActiveValue::Set("user@example.com".to_string());
user_model.name = ActiveValue::Set("John Doe".to_string());
let user = repo.insert(user_model).await?;
// Update (only changed fields are updated)
let mut user_model = user.into_active_model();
user_model.name = ActiveValue::Set("Jane Doe".to_string());
repo.update(user_model).await?;
// Delete
repo.delete_by_id(user_id).await?;
```
### ActiveModel Pattern
`ActiveModel` tracks field changes for efficient partial updates:
```rust
// Create from entity
let mut model = user.into_active_model();
// Set new values (only these fields will be updated)
model.name = ActiveValue::Set("New Name");
// Unset fields are not updated
let updated = repo.update(model).await?;
```
---
## Query Builder
For dynamic queries (admin panels, filters):
```rust
use ormkit::{FilterOp, Order};
let mut query = User::query();
// Apply filters dynamically
if let Some(email) = email_filter {
query = query.filter("email", FilterOp::Eq, email);
}
if let Some(min_age) = min_age_filter {
query = query.filter("age", FilterOp::Gte, min_age);
}
// Dynamic ordering
query = query.order_by("created_at", Order::Desc);
// Execute
let users = query.fetch_all(&pool).await?;
```
**Note:** Prefer the type-safe DSL for static queries. Use string-based queries only when necessary.
---
## Transactions
Automatic commit/rollback with closures:
```rust
use ormkit::transaction;
// All operations use the transaction
let user = repo.find_by_id(user_id).await?;
let mut model = user.into_active_model();
model.name = ActiveValue::Set("Updated".to_string());
repo.update(model).await?;
// Return value becomes transaction result
Ok::<(), ormkit::OrmkitError>(())
}).await?;
// Transaction commits on Ok, rolls back on Err
```
### Nested Transactions
Uses PostgreSQL SAVEPOINTs:
```rust
transaction(&tx1, |tx2| async move {
// Inner transaction (SAVEPOINT)
Ok(())
}).await
}).await
```
---
## Pagination
### Offset Pagination
```rust
use ormkit::pagination::PaginationRequest;
let repo = Repository::<User>::new(&pool);
let request = PaginationRequest::new(1, 25); // page 1, 25 per page
let page = repo.paginate(&request).await?;
println!("Page {} of {}", page.meta.page, page.meta.total_pages);
for user in page.items {
println!("{}", user.email);
}
```
### Cursor Pagination
For large datasets or real-time feeds:
```rust
use ormkit::pagination::CursorRequest;
let request = CursorRequest::new(cursor, 25);
let page = repo.paginate_cursor(&request).await?;
```
---
## Next Steps
- **Production Features**: See [PRODUCTION_FEATURES.md](PRODUCTION_FEATURES.md) for migrations and schema validation
- **Performance**: See [PERFORMANCE_OPTIMIZATIONS.md](PERFORMANCE_OPTIMIZATIONS.md) for caching and optimization
- **API Reference**: See [docs.rs](https://docs.rs/ormkit) for complete API documentation
---
**Need help?**
- Check the [Error Handling Guide](ERROR_HANDLING.md)
- See [Performance Optimizations](PERFORMANCE_OPTIMIZATIONS.md) for optimization tips