{% extends "docs_base.html" %}
{% block content %}
<div class="prose prose-slate max-w-none">
<h1>Database Migrations</h1>
<p>Ruskit provides a robust database migration system that ensures your database schema changes are versioned, ordered, and can be rolled out consistently across different environments.</p>
<h2>Migration Commands</h2>
<h3>Create a New Model with Migration</h3>
<pre><code class="language-bash">cargo kit make:model Post</code></pre>
<p>This will:</p>
<ol>
<li>Create a new model file at <code>src/app/models/post.rs</code></li>
<li>Add the model to <code>src/app/models/mod.rs</code></li>
<li>Create an initial migration with timestamp prefix (e.g., <code>1739885809_create_posts_table</code>)</li>
<li>Set up basic model structure with id, created_at, and updated_at fields</li>
</ol>
<h3>Add a New Migration to Existing Model</h3>
<pre><code class="language-bash">cargo kit make:migration add_email_to_users --model User</code></pre>
<p>This will:</p>
<ol>
<li>Add a new migration to the specified model's migrations vector</li>
<li>Automatically prefix the migration with a timestamp (e.g., <code>1739885809_add_email_to_users</code>)</li>
<li>Create placeholders for UP and DOWN migrations</li>
</ol>
<h3>Run Migrations</h3>
<pre><code class="language-bash">cargo kit migrate</code></pre>
<p>This will:</p>
<ol>
<li>Discover all models in your application</li>
<li>Collect all migrations from these models</li>
<li>Sort migrations by timestamp to ensure consistent order</li>
<li>Run any migrations that haven't been executed yet</li>
</ol>
<h3>Fresh Migrations</h3>
<pre><code class="language-bash">cargo kit migrate:fresh</code></pre>
<p>This command will:</p>
<ol>
<li>Drop all tables in your database (including the migrations table)</li>
<li>Re-run all migrations from scratch</li>
</ol>
<p>This is useful when you want to:</p>
<ul>
<li>Reset your database to a clean state</li>
<li>Test your migrations work correctly from a fresh start</li>
<li>Resolve issues with inconsistent migration states</li>
</ul>
<p>Note: This command will delete all data in your database. Use with caution in production environments.</p>
<h2>Migration Structure</h2>
<p>Each migration consists of:</p>
<ol>
<li>A unique name with timestamp prefix (e.g., <code>1739885809_create_users_table</code>)</li>
<li>An UP migration (the changes to apply)</li>
<li>A DOWN migration (how to reverse the changes)</li>
</ol>
<p>Example migration:</p>
<pre><code class="language-rust">Migration::new(
"1739885809_add_email_to_users",
// UP migration
"ALTER TABLE users ADD COLUMN email TEXT;",
// DOWN migration
"ALTER TABLE users DROP COLUMN email;"
)</code></pre>
<h2>Migration Ordering</h2>
<p>Migrations are automatically ordered by their timestamp prefix, ensuring that:</p>
<ol>
<li>Migrations run in the order they were created</li>
<li>New migrations always run after existing ones</li>
<li>The order is consistent across all environments</li>
</ol>
<h2>Best Practices</h2>
<ol>
<li><strong>One Change Per Migration</strong>: Each migration should handle one specific change (e.g., adding a column, creating a table)</li>
<li><strong>Meaningful Names</strong>: Use descriptive names for migrations:
<ul>
<li><code>create_users_table</code></li>
<li><code>add_email_to_users</code></li>
<li><code>add_foreign_key_to_posts</code></li>
</ul>
</li>
<li><strong>Always Include DOWN Migrations</strong>: Make sure your DOWN migrations correctly reverse the changes made in UP migrations</li>
<li><strong>Run Migrations Immediately</strong>: After creating a new migration, run <code>cargo kit migrate</code> to apply it</li>
<li><strong>Version Control</strong>: Commit your migrations along with related code changes</li>
</ol>
<h2>Migration Files</h2>
<p>Migrations are stored in your model files under the <code>migrations()</code> function:</p>
<pre><code class="language-rust">impl Model for User {
fn migrations() -> Vec<Migration> {
vec![
Migration::new(
"1739885800_create_users_table",
"CREATE TABLE users (...)",
"DROP TABLE users"
),
Migration::new(
"1739885809_add_email_to_users",
"ALTER TABLE users ADD COLUMN email TEXT;",
"ALTER TABLE users DROP COLUMN email;"
),
]
}
}</code></pre>
<h2>Migration Table</h2>
<p>Ruskit maintains a <code>migrations</code> table in your database to track which migrations have been run:</p>
<pre><code class="language-sql">CREATE TABLE migrations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
batch INTEGER NOT NULL,
migration_time INTEGER NOT NULL
)</code></pre>
<p>This ensures that:</p>
<ol>
<li>Each migration runs exactly once</li>
<li>Migrations can be rolled back by batch</li>
<li>You can track when each migration was applied</li>
</ol>
</div>
{% endblock %}