Database Migrations
Relevant source files
The following files were used as context for generating this wiki page:
Database migrations in Horizon provide a structured way to manage the evolution of the PostgreSQL schema. The system ensures that the database state is synchronized across all development and production environments. It is built using the sea-orm-migration framework, which allows for programmatic, version-controlled schema changes using asynchronous Rust.
The migration system is integrated into both a standalone migration binary and the main application CLI. This enables automatic migration application during server startup or manual intervention via command-line arguments.
Sources: IMPLEMENTATION_PLAN.md:209-214, crates/cli/src/main.rs:188-193
Architecture and Components
The migration architecture consists of several layers, from the raw migration logic to the CLI runners that execute them.
Migration Logic
Individual migrations are defined as Rust structs that implement the MigrationTrait. Each migration must provide an up method to apply changes and a down method to revert them. The system uses the sea-orm schema manager to create or drop tables, columns, and indexes.
Sources: crates/migration/src/m20220101_000001_create_table.rs:6-33, crates/migration/src/lib.rs:1-10
The Migrator
The Migrator struct acts as the central registry for all migration files. It implements MigratorTrait, which requires a migrations() function that returns a vector of boxed migration traits in the order they should be executed.
Sources: crates/migration/src/lib.rs:5-10
Connection Management
Database connections are established using the connect_to_database helper, which utilizes the PostgreSQL driver with tokio-rustls.
Sources: crates/migration/src/lib.rs:12-15, crates/migration/Cargo.toml:19-25
The following diagram illustrates the relationship between the CLI, the Migrator, and the Database:
The diagram shows the flow of execution from the command-line interface through the Migrator registry to the individual migration scripts that update the PostgreSQL database.
CLI Integration and Commands
Horizon provides multiple ways to interact with the migration system through the horizon migrate subcommand.
CLI Operations
The CLI supports several operational modes:
- Up: Applies all pending migrations to the database.
- Rollback/Down: Reverts the last applied migration.
- Dry Run: Simulates the migration process and lists pending migrations without applying changes.
- Status: Checks which migrations have been applied and which are pending.
Sources: crates/cli/src/main.rs:205-246, crates/migration/README.md:1-32
| Command Shorthand | Description |
|---|---|
up | Apply all pending migrations |
down | Rollback the last applied migration |
fresh | Drop all tables and reapply all migrations |
refresh | Rollback all migrations and reapply them |
reset | Rollback all applied migrations |
status | View the current status of all migrations |
Sources: crates/migration/README.md:1-32
Automatic Migrations
When the API server starts using horizon serve, the system automatically runs Migrator::up to ensure the database schema matches the application version before the server begins listening for requests.
Sources: crates/cli/src/main.rs:188-193
Configuration and Environment
The migration system relies on standard environment variables to establish database connections. These are typically loaded from a .env file using the dotenvy crate.
Sources: crates/migration/src/main.rs:4-22, crates/cli/src/main.rs:25-36
| Environment Variable | Description | Default Value |
|---|---|---|
HORIZON_DATABASE_HOST | Host address of the PostgreSQL server | localhost |
HORIZON_DATABASE_PORT | Port number for the database | 5432 |
HORIZON_DATABASE_NAME | Name of the database | horizon |
HORIZON_DATABASE_USER | Username for authentication | horizon |
HORIZON_DATABASE_PASSWORD | Password for authentication | "" |
HORIZON_DATABASE_SSL_MODE | SSL mode for connection | require |
Sources: crates/cli/src/main.rs:38-48, crates/migration/src/main.rs:7-19
Implementation Examples
Migration Definition
A typical migration file uses the sea-orm-migration prelude to define the table structure.
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table("post")
.if_not_exists()
.col(pk_auto("id"))
.col(string("title"))
.col(string("text"))
.to_owned(),
)
.await
}
}
Sources: crates/migration/src/m20220101_000001_create_table.rs:9-24
Connection Workflow
The system constructs a PostgreSQL connection string from environment variables and uses it to initialize the migration runner.
The sequence diagram illustrates the initialization process where the CLI gathers environment configuration to establish a database connection and execute migrations.
Sources: crates/cli/src/main.rs:180-193, crates/migration/src/main.rs:4-23
Summary
The Horizon Database Migration system is a robust framework integrated into the core CLI, ensuring schema consistency through version-controlled Rust scripts. By utilizing sea-orm-migration, it provides developers with a safe, idempotent way to evolve the PostgreSQL database alongside the application code, supporting both manual control and automated startup synchronization.