prax_migrate/lib.rs
1//! # prax-migrate
2//!
3//! Migration engine for the Prax ORM.
4//!
5//! This crate provides functionality for:
6//! - Schema diffing between Prax schema definitions and database state
7//! - SQL migration generation for PostgreSQL (with MySQL/SQLite planned)
8//! - Migration file management on the filesystem
9//! - Migration history tracking in the database
10//! - Safe, transactional migration application and rollback
11//! - **Resolution system** for handling migration conflicts and checksums
12//!
13//! ## Architecture
14//!
15//! The migration engine compares your Prax schema definition with the current
16//! database state and generates SQL scripts to bring the database up to date.
17//! It tracks applied migrations in a `_prax_migrations` table.
18//!
19//! ```text
20//! ┌──────────────┐ ┌────────────────┐ ┌─────────────┐
21//! │ Prax Schema │────▶│ Schema Differ │────▶│ SQL Gen │
22//! └──────────────┘ └────────────────┘ └─────────────┘
23//! │ │
24//! ▼ ▼
25//! ┌────────────────┐ ┌─────────────┐
26//! │ Migration Plan │────▶│ Apply SQL │
27//! └────────────────┘ └─────────────┘
28//! │
29//! ▼
30//! ┌─────────────┐
31//! │ History Tbl │
32//! └─────────────┘
33//! ```
34//!
35//! ## Example
36//!
37//! ```rust,ignore
38//! use prax_migrate::{MigrationConfig, MigrationEngine};
39//!
40//! async fn run_migrations() -> Result<(), Box<dyn std::error::Error>> {
41//! // Parse your schema
42//! let schema = prax_schema::parse_schema(r#"
43//! model User {
44//! id Int @id @auto
45//! email String @unique
46//! name String?
47//! }
48//! "#)?;
49//!
50//! // Configure migrations
51//! let config = MigrationConfig::new()
52//! .migrations_dir("./migrations");
53//!
54//! // Create engine with your history repository
55//! let history = /* your history implementation */;
56//! let engine = MigrationEngine::new(config, history);
57//!
58//! // Initialize (creates migrations table)
59//! engine.initialize().await?;
60//!
61//! // Plan migrations
62//! let plan = engine.plan(&schema).await?;
63//! println!("Plan: {}", plan.summary());
64//!
65//! // Apply migrations
66//! let result = engine.migrate().await?;
67//! println!("Applied {} migrations in {}ms",
68//! result.applied_count, result.duration_ms);
69//!
70//! Ok(())
71//! }
72//! ```
73//!
74//! ## Migration Files
75//!
76//! Migrations are stored as directories with `up.sql` and `down.sql` files:
77//!
78//! ```text
79//! migrations/
80//! ├── 20231215120000_create_users/
81//! │ ├── up.sql
82//! │ └── down.sql
83//! ├── 20231216090000_add_posts/
84//! │ ├── up.sql
85//! │ └── down.sql
86//! └── resolutions.toml # Migration resolutions
87//! ```
88//!
89//! ## Resolution System
90//!
91//! The resolution system handles common migration issues:
92//!
93//! - **Checksum Mismatches**: When a migration is modified after being applied
94//! - **Skipped Migrations**: Intentionally skip migrations (e.g., legacy tables)
95//! - **Baseline Migrations**: Mark migrations as applied without running them
96//! - **Renamed Migrations**: Map old migration IDs to new ones
97//! - **Conflict Resolution**: Handle conflicts between migrations
98//!
99//! ```rust,ignore
100//! use prax_migrate::{Resolution, ResolutionConfig};
101//!
102//! let mut resolutions = ResolutionConfig::new();
103//!
104//! // Accept a checksum change
105//! resolutions.add(Resolution::accept_checksum(
106//! "20240101_create_users",
107//! "old_checksum",
108//! "new_checksum",
109//! "Fixed column type",
110//! ));
111//!
112//! // Skip a migration
113//! resolutions.add(Resolution::skip(
114//! "20240102_legacy_table",
115//! "Already exists in production",
116//! ));
117//!
118//! // Mark as baseline (applied without running)
119//! resolutions.add(Resolution::baseline(
120//! "20240103_initial",
121//! "Database was imported from backup",
122//! ));
123//!
124//! // Save to file
125//! resolutions.save("migrations/resolutions.toml").await?;
126//! ```
127
128pub mod diff;
129pub mod engine;
130pub mod error;
131pub mod file;
132pub mod history;
133pub mod introspect;
134pub mod procedure;
135pub mod resolution;
136pub mod shadow;
137pub mod sql;
138
139// Re-exports
140pub use diff::{
141 EnumAlterDiff, EnumDiff, FieldAlterDiff, FieldDiff, IndexDiff, ModelAlterDiff, ModelDiff,
142 SchemaDiff, SchemaDiffer, UniqueConstraint,
143};
144pub use engine::{
145 MigrationConfig, MigrationEngine, MigrationPlan, MigrationResult, MigrationStatus,
146};
147pub use error::{MigrateResult, MigrationError};
148pub use file::{MigrationFile, MigrationFileManager};
149pub use history::{MigrationHistoryRepository, MigrationLock, MigrationRecord};
150pub use introspect::{
151 ColumnInfo, ConstraintInfo, EnumInfo, IndexInfo, IntrospectionConfig, IntrospectionResult,
152 Introspector, SchemaBuilder, SkippedTable, TableInfo,
153};
154pub use procedure::{
155 // MongoDB Atlas Triggers
156 AtlasOperation,
157 AtlasTrigger,
158 AtlasTriggerType,
159 AuthOperation,
160 // Procedure types
161 ChangeType,
162 // Event Scheduler types (MySQL)
163 EventAlterDiff,
164 EventDiff,
165 EventInterval,
166 EventSchedule,
167 IntervalUnit,
168 // SQL Agent types (MSSQL)
169 JobSchedule,
170 JobStep,
171 NotifyLevel,
172 OnCompletion,
173 ParallelSafety,
174 ParameterMode,
175 ProcedureAlterDiff,
176 ProcedureChange,
177 ProcedureDefinition,
178 ProcedureDiff,
179 ProcedureDiffer,
180 ProcedureHistoryEntry,
181 ProcedureLanguage,
182 ProcedureParameter,
183 ProcedureSqlGenerator,
184 ProcedureStore,
185 ReturnColumn,
186 ScheduleFrequency,
187 ScheduledEvent,
188 SqlAgentJob,
189 StepAction,
190 StepType,
191 // Trigger types
192 TriggerAlterDiff,
193 TriggerDefinition,
194 TriggerEvent,
195 TriggerLevel,
196 TriggerTiming,
197 Volatility,
198 Weekday,
199};
200pub use resolution::{
201 ConflictStrategy, Resolution, ResolutionAction, ResolutionBuilder, ResolutionConfig,
202 ResolutionCounts, ResolutionWarning,
203};
204pub use shadow::{
205 FieldDrift, IndexDrift, SchemaDrift, ShadowConfig, ShadowDatabase, ShadowDatabaseManager,
206 ShadowDiffResult, ShadowState, detect_drift,
207};
208pub use sql::{MigrationSql, PostgresSqlGenerator};