Skip to main content

reinhardt_db/
migrations.rs

1//! # Reinhardt Migrations
2//!
3//! Database migration system for Reinhardt framework.
4//!
5//! ## Features
6//!
7//! - **Auto-detection**: Detects model changes and generates migrations
8//! - **Migration Graph**: Manages dependencies between migrations
9//! - **AST-Based Entry Points**: Generates Rust 2024 Edition-compliant module files
10//! - **State Reconstruction**: Django-style `ProjectState` building from migration history
11//! - **Zero Downtime**: Support for safe schema changes in production
12//!
13//! ## AST-Based Entry Point Generation
14//!
15//! The `makemigrations` command uses Abstract Syntax Tree (AST) parsing to generate
16//! and maintain migration entry point files (`migrations/app_name.rs`). This ensures:
17//!
18//! 1. **Rust 2024 Edition Compliance**: Uses `app_name.rs` instead of deprecated `mod.rs`
19//! 2. **Robust Module Detection**: Structurally identifies existing migration modules
20//! 3. **Consistent Formatting**: Standardized output via `prettyplease`
21//!
22//! ### Generated Entry Point Example
23//!
24//! The migration system automatically generates entry point files:
25//!
26//! ```rust,ignore
27//! // migrations/myapp.rs (auto-generated - example only)
28//! pub mod _0001_initial;
29//! pub mod _0002_add_field;
30//!
31//! pub fn all_migrations() -> Vec<fn() -> Migration> {
32//!     vec![_0001_initial::migration, _0002_add_field::migration]
33//! }
34//! ```
35//!
36//! This file is automatically updated when new migrations are created.
37
38pub mod ast_parser;
39pub mod auto_migration;
40pub mod autodetector;
41pub mod dependency;
42pub mod di_support;
43pub mod executor;
44pub mod fields;
45pub mod graph;
46pub mod introspect;
47pub mod introspection;
48pub mod migration;
49pub mod migration_namer;
50pub mod migration_numbering;
51pub mod model_registry;
52pub mod operation_trait;
53pub mod operations;
54pub mod plan;
55pub mod recorder;
56pub mod registry;
57pub mod repository;
58pub mod schema_diff;
59pub mod schema_editor;
60pub mod service;
61pub mod source;
62pub mod squash;
63pub mod state_loader;
64pub mod visualization;
65pub mod zero_downtime;
66
67#[cfg(feature = "contenttypes")]
68pub use crate::contenttypes::migration::MigrationRecord;
69pub use autodetector::{
70	// Pattern Learning and Inference
71	ChangeTracker,
72	ConstraintDefinition,
73	DetectedChanges,
74	FieldState,
75	ForeignKeyAction,
76	ForeignKeyConstraintInfo,
77	ForeignKeyInfo,
78	IndexDefinition,
79	InferenceEngine,
80	InferenceRule,
81	InferredIntent,
82	InteractiveAutodetector,
83	MigrationAutodetector,
84	MigrationPrompt,
85	ModelState,
86	OperationRef,
87	PatternMatcher,
88	ProjectState,
89	RuleCondition,
90	SimilarityConfig,
91	to_snake_case,
92};
93pub use dependency::{
94	DependencyCondition, DependencyResolutionContext, DependencyResolver, MigrationDependency,
95	OptionalDependency, SwappableDependency,
96};
97pub use di_support::{MigrationConfig, MigrationService as DIMigrationService};
98pub use executor::{DatabaseMigrationExecutor, ExecutionResult, OperationOptimizer};
99pub use fields::FieldType;
100pub use graph::{MigrationGraph, MigrationKey, MigrationNode};
101pub use migration::Migration;
102pub use migration_namer::MigrationNamer;
103pub use migration_numbering::MigrationNumbering;
104pub use model_registry::{
105	FieldMetadata, ManyToManyMetadata, ModelMetadata, ModelRegistry, RelationshipMetadata,
106	global_registry,
107};
108pub use operation_trait::MigrationOperation;
109pub use operations::{
110	AddColumn, AlterColumn, AlterTableOptions, BulkLoadFormat, BulkLoadOptions, BulkLoadSource,
111	ColumnDefinition, Constraint, CreateTable, DeferrableOption, DropColumn, IndexType,
112	InterleaveSpec, MySqlAlgorithm, MySqlLock, Operation, PartitionDef, PartitionOptions,
113	PartitionType, PartitionValues, SqlDialect, field_type_string_to_field_type,
114};
115pub use plan::{MigrationPlan, TransactionMode};
116
117// New operations from refactored modules
118pub use auto_migration::{
119	AutoMigrationError, AutoMigrationGenerator, AutoMigrationResult, ValidationResult,
120};
121pub use operations::{
122	AddField, AlterField, CreateCollation, CreateExtension, CreateModel, DeleteModel,
123	DropExtension, FieldDefinition, MoveModel, RemoveField, RenameField, RenameModel, RunCode,
124	RunSQL, StateOperation, special::DataMigration,
125};
126pub use recorder::{DatabaseMigrationRecorder, MigrationRecorder};
127pub use repository::{MigrationRepository, filesystem::FilesystemRepository};
128pub use schema_diff::{
129	ColumnSchema, ConstraintSchema, DatabaseSchema, ForeignKeySchemaInfo, IndexSchema, SchemaDiff,
130	SchemaDiffResult, TableSchema,
131};
132pub use schema_editor::SchemaEditor;
133pub use service::MigrationService;
134pub use source::{
135	MigrationSource, composite::CompositeSource, filesystem::FilesystemSource,
136	registry::RegistrySource,
137};
138pub use squash::{MigrationSquasher, SquashOptions};
139pub use state_loader::MigrationStateLoader;
140pub use visualization::{HistoryEntry, MigrationStats, MigrationVisualizer, OutputFormat};
141pub use zero_downtime::{MigrationPhase, Strategy, ZeroDowntimeMigration};
142
143pub use introspect::{
144	GeneratedFile, GeneratedOutput, GenerationConfig, IntrospectConfig, NamingConvention,
145	OutputConfig, SchemaCodeGenerator, TableFilterConfig, TypeMapper, TypeMappingError,
146	escape_rust_keyword, generate_models, preview_output, sanitize_identifier, to_pascal_case,
147	write_output,
148};
149pub use introspection::{
150	ColumnInfo, DatabaseIntrospector, ForeignKeyInfo as IntrospectionForeignKeyInfo, IndexInfo,
151	TableInfo, UniqueConstraintInfo,
152};
153
154// Re-export types from reinhardt-backends for convenience
155pub use crate::backends::{DatabaseConnection, DatabaseType};
156
157use thiserror::Error;
158
159/// Trait for types that provide migrations.
160///
161/// This trait enables compile-time migration collection, which is necessary
162/// because Rust cannot dynamically load code at runtime like Python's Django.
163///
164/// # Example
165///
166/// Application-side implementation (migration modules would be generated):
167///
168/// ```rust,ignore
169/// use reinhardt_db::migrations::{Migration, MigrationProvider};
170///
171/// // In your application's migrations module
172/// // These modules would be generated by `makemigrations` command:
173/// // pub mod _0001_initial;
174/// // pub mod _0002_add_published;
175///
176/// pub struct PollsMigrations;
177///
178/// impl MigrationProvider for PollsMigrations {
179///     fn migrations() -> Vec<Migration> {
180///         vec![
181///             _0001_initial::migration(),
182///             _0002_add_published::migration(),
183///         ]
184///     }
185/// }
186///
187/// // Usage in tests:
188/// // let (container, db) = postgres_with_migrations_from::<PollsMigrations>().await;
189/// ```
190pub trait MigrationProvider {
191	/// Returns all migrations provided by this type.
192	///
193	/// Migrations should be returned in dependency order (base migrations first).
194	fn migrations() -> Vec<Migration>;
195}
196
197/// Errors that can occur during migration operations.
198#[non_exhaustive]
199#[derive(Debug, Error)]
200pub enum MigrationError {
201	/// The requested migration was not found.
202	#[error("Migration not found: {0}")]
203	NotFound(String),
204
205	/// A migration dependency could not be resolved.
206	#[error("Dependency error: {0}")]
207	DependencyError(String),
208
209	/// An SQL execution error occurred.
210	#[error("SQL error: {0}")]
211	SqlError(#[from] sqlx::Error),
212
213	/// A database backend error occurred.
214	#[error("Database error: {0}")]
215	DatabaseError(#[from] crate::backends::QueryDatabaseError),
216
217	/// The migration definition is invalid.
218	#[error("Invalid migration: {0}")]
219	InvalidMigration(String),
220
221	/// The migration cannot be reversed.
222	#[error("Irreversible migration: {0}")]
223	IrreversibleError(String),
224
225	/// An I/O error occurred during migration.
226	#[error("IO error: {0}")]
227	IoError(#[from] std::io::Error),
228
229	/// A formatting error occurred.
230	#[error("Format error: {0}")]
231	FmtError(#[from] std::fmt::Error),
232
233	/// Circular dependency detected in migration graph.
234	#[error("Circular dependency detected: {cycle}")]
235	CircularDependency {
236		/// Description of the dependency cycle.
237		cycle: String,
238	},
239
240	/// A required migration node was not found.
241	#[error("Node not found: {message} - {node}")]
242	NodeNotFound {
243		/// The error message.
244		message: String,
245		/// The node identifier.
246		node: String,
247	},
248
249	/// An error occurred during database introspection.
250	#[error("Introspection error: {0}")]
251	IntrospectionError(String),
252
253	/// The database type is not supported.
254	#[error("Unsupported database: {0}")]
255	UnsupportedDatabase(String),
256
257	/// Duplicate operations detected
258	///
259	/// This error occurs when a new migration has identical operations
260	/// to an existing migration, which usually indicates a problem with
261	/// from_state construction during makemigrations.
262	#[error("Duplicate operations: {0}")]
263	DuplicateOperations(String),
264
265	/// Foreign key integrity violation during table recreation
266	///
267	/// This error occurs when SQLite table recreation results in orphaned
268	/// foreign key references, indicating data integrity issues that must
269	/// be resolved before the migration can proceed.
270	#[error("Foreign key violation: {0}")]
271	ForeignKeyViolation(String),
272
273	/// Path traversal attempt detected in migration path components
274	///
275	/// This error occurs when an app label or migration name contains
276	/// path traversal sequences (e.g., `..`) that could escape the
277	/// migration root directory.
278	#[error("Path traversal detected: {0}")]
279	PathTraversal(String),
280}
281
282/// Type alias for result.
283pub type Result<T> = std::result::Result<T, MigrationError>;
284
285// Prelude for migrations
286/// Prelude module.
287pub mod prelude {
288	pub use super::fields::prelude::*;
289	pub use super::{ColumnDefinition, Constraint, ForeignKeyAction, Migration, Operation};
290}