Skip to main content

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};