ormkit 0.3.0

A compile-time safe async ORM for PostgreSQL powered by SQLx
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
# Ormkit Production Guide

This guide covers production considerations: migrations, schema validation, performance features, and operational concerns.

## Table of Contents

1. [Feature Flags]#feature-flags
2. [Migrations]#migrations
3. [Schema Validation]#schema-validation
4. [Performance Features]#performance-features
5. [Error Handling]#error-handling
6. [Platform Requirements]#platform-requirements
7. [Operational Guidelines]#operational-guidelines

---

## Feature Flags

Ormkit uses feature flags to minimize dependencies:

```toml
# Core ORM (minimal)
ormkit = { version = "0.2", features = ["orm"] }

# Core + migrations (recommended)
ormkit = { version = "0.2", features = ["orm", "migrations"] }

# Core + production features
ormkit = { version = "0.2", features = ["orm", "migrations", "validate", "performance"] }

# All features (default)
ormkit = { version = "0.2", features = ["full"] }
```

### Feature Matrix

| Feature | Flag | Dependencies | Use Case |
|---------|------|--------------|----------|
| Entity derive | `orm` | sqlx | All projects |
| Migrations | `migrations` | sha2 | Schema management |
| Schema validation | `validate` | - | Runtime validation |
| Query caching | `cache` | bincode, futures | Read-heavy workloads |
| Parallel execution | `parallel` | futures | Bulk operations |
| Smart pooling | `smart-pool` | once_cell | Connection optimization |

---

## Migrations

### Setup

Enable the migrations feature:

```toml
ormkit = { version = "0.2", features = ["migrations"] }
```

### Creating Migrations

```bash
# Create a new migration
cargo run --bin ormkit-cli migration create create_users_table

# Creates: migrations/TIMESTAMP_create_users_table/up.sql
#          migrations/TIMESTAMP_create_users_table/down.sql
```

### Migration Files

**up.sql** (applied when migrating up):
```sql
CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    email VARCHAR(255) NOT NULL UNIQUE,
    name VARCHAR(255) NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE INDEX idx_users_email ON users(email);
```

**down.sql** (applied when rolling back):
```sql
DROP INDEX idx_users_email;
DROP TABLE users;
```

### Running Migrations

```rust
use ormkit::migrations::{Migrator, MigrationError};

let migrator = Migrator::new(&pool).await?;

// Run pending migrations
migrator.migrate_up().await?;

// Rollback last migration
migrator.migrate_down().await?;

// Get migration status
let status = migrator.status().await?;
println!("Current version: {}", status.current_version);
```

### Best Practices

1. **Review generated SQL** before committing
2. **Use transactions** in migrations (automatic)
3. **Test rollback** procedures
4. **Backward compatibility**: Design rollbacks carefully
5. **Index creation**: Create indexes after data load for large tables

---

## Schema Validation

Validate that your entity definitions match the database schema:

```rust
use ormkit::validate::{SchemaValidator, ValidationError};

let validator = SchemaValidator::new(&pool);

// Validate all entities
validator.validate_entity::<User>().await?;
validator.validate_entity::<Post>().await?;

// Validate all registered entities
validator.validate_all().await?;
```

### What Gets Validated

- Table exists
- Columns exist with correct types
- Primary key exists
- Not null constraints match
- Default values (optional)

### Error Handling

```rust
match validator.validate_entity::<User>().await {
    Ok(_) => println!("Schema valid"),
    Err(ValidationError::ColumnNotFound { column, .. }) => {
        eprintln!("Column {} not found in database", column);
    }
    Err(ValidationError::TypeMismatch { column, expected, actual }) => {
        eprintln!("Type mismatch for {}: expected {:?}, got {:?}", column, expected, actual);
    }
    Err(e) => eprintln!("Validation error: {}", e),
}
```

---

## Performance Features

Enable performance features:

```toml
ormkit = { version = "0.2", features = ["performance"] }
```

### Query Caching

Cache prepared statements for repeated queries:

```rust
use ormkit::performance::cache::QueryCache;

let cache = QueryCache::new(100); // 100 cached queries

// Use cached repository
let repo = CachedRepository::new(&pool, cache);
let user = repo.find_by_id(user_id).await?;
```

**Cache Invalidation:**
- UPDATE: Invalidates by primary key
- DELETE: Invalidates by primary key
- INSERT: Optional write-through
- Manual: `cache.invalidate(&key)`

### Entity Caching

Cache query results with TTL:

```rust
use ormkit::performance::cache::EntityCache;
use std::time::Duration;

let cache = EntityCache::new(1000, Duration::from_secs(60));

// First call hits database
let user1 = cache.get(&pool, user_id).await?;

// Subsequent calls hit cache (within TTL)
let user2 = cache.get(&pool, user_id).await?;
```

**Cache Consistency:**

```rust
use ormkit::performance::cache::{CacheConsistency, InvalidationStrategy};

// Strong consistency (default) - zero stale reads
let strategy = InvalidationStrategy::strong();

// Eventual consistency - stale within TTL (analytics)
let strategy = InvalidationStrategy::eventual(Duration::from_secs(60));
```

### Parallel Execution

Execute bulk operations concurrently:

```rust
use ormkit::performance::parallel::ParallelExecutor;

let executor = ParallelExecutor::new(&pool, 10); // max 10 parallel

// Bulk fetch by IDs
let users = executor.bulk_fetch_by_id(ids, "users").await?;

// Parallel insert
let result = executor.bulk_insert(entities).await?;
```

### Smart Pooling

Optimized connection pool settings:

```rust
use ormkit::performance::pool::create_smart_pool;

let pool = create_smart_pool(&database_url).await?;
```

**Default Settings:**
- Max connections: 50
- Min connections: 10
- Connection timeout: 30s
- No connection tests (performance)

---

## Error Handling

### Centralized Error Type

```rust
use ormkit::OrmkitError;

match error {
    OrmkitError::Database(sqlx::Error) => {
        // Database connection or query error
    }
    OrmkitError::EntityNotFound => {
        // No entity found for given ID
    }
    OrmkitError::Migration(MigrationError) => {
        // Migration failed
    }
    OrmkitError::Validation(SchemaValidationError) => {
        // Schema validation failed
    }
    OrmkitError::Transaction(TransactionError) => {
        // Transaction failed
    }
    _ => {}
}
```

### Retryable Errors

Check if an error is transient:

```rust
if error.is_retryable() {
    // Retry with backoff
}
```

**Retryable errors:**
- Connection failures
- Serialization failures (with retry logic)
- Timeout errors

### Error Categories

```rust
let category = error.category(); // "database", "validation", "migration", etc.
// Use for logging/metrics
```

---

## Platform Requirements

### Database

- **PostgreSQL**: 12, 13, 14, 15, 16
- **Extensions**: None required (uuid-gen for UUID defaults)

### Rust

- **Minimum Supported Rust Version (MSRV)**: 1.70
- **Edition**: 2021

### Runtime

- **Tokio**: 1.x with `multi-thread` scheduler
- **TLS**: rustls (default) or native-tls

---

## Operational Guidelines

### Connection Pooling

```rust
use sqlx::postgres::PgPoolOptions;

let pool = PgPoolOptions::new()
    .max_connections(50)
    .min_connections(10)
    .connect(&database_url)
    .await?;
```

**Guidelines:**
- Start with 10-20 connections
- Increase based on workload
- Monitor connection wait times
- Use connection pooling in production

### Monitoring

Key metrics to track:

1. **Query latency**: p50, p95, p99
2. **Connection pool utilization**
3. **Cache hit rates** (if using caching)
4. **Transaction retry rates** (serializable isolation)
5. **Migration execution time**

### Backup Strategy

1. **Database dumps**: Use `pg_dump` for backups
2. **Migration tracking**: Ormkit tracks applied migrations
3. **Rollback planning**: Test rollback procedures

### Deployment Checklist

- [ ] Enable appropriate feature flags
- [ ] Set connection pool size
- [ ] Configure cache settings (if using)
- [ ] Run migrations in deployment script
- [ ] Enable schema validation in staging
- [ ] Monitor query performance
- [ ] Set up error tracking
- [ ] Test rollback procedures

---

## Performance Tuning

### When to Use Caching

**Use caching for:**
- Read-heavy workloads
- Repeated queries with same parameters
- User session lookups
- Configuration data

**Avoid caching for:**
- Write-heavy workloads
- Real-time data
- Frequently changing data
- Large result sets

### When to Use Parallel Execution

**Use parallel for:**
- Bulk imports
- Batch reporting
- Background jobs

**Avoid parallel for:**
- User-facing requests (latency)
- Small batches (< 10 items)
- Already-fast queries

### Query Optimization

1. **Use indexes**: Ensure filtered columns are indexed
2. **Avoid N+1**: Use eager loading for relationships
3. **Limit result sets**: Use pagination
4. **Select specific columns**: Avoid `SELECT *`
5. **Use explain**: Analyze query plans

---

## Next Steps

- **Core ORM**: See [CORE_GUIDE.md]CORE_GUIDE.md
- **Performance**: See [PERFORMANCE_OPTIMIZATIONS.md]PERFORMANCE_OPTIMIZATIONS.md
- **Error Handling**: See [ERROR_HANDLING.md]ERROR_HANDLING.md

---

**Need help?**
- Check [Platform Requirements]#platform-requirements
- Review [Operational Guidelines]#operational-guidelines