lib.rs
Overview
This file provides a set of utilities and abstractions focused on database schema migration management. It enables version-controlled migration of SQLite databases using embedded migration scripts. The core functionality revolves around applying, validating, and managing migrations to keep the database schema in sync with application requirements.
The file defines structures to represent database metadata and maintenance tasks, as well as the migration target version enumerations and helper functions for version resolution. It integrates with the [rusqlite] crate for database connections and [rusqlite_migration] for migration execution, while embedding migration files at compile time using the [include_dir] crate. Error handling is augmented by [anyhow] for context-rich results.
Key Components and Their Details
Struct: DbInfo
Represents metadata about a specific database, including its name and embedded migration scripts.
Fields:
name: &'static str— The static name identifier for the database (e.g.,"bm-archive").migrations: Dir<'static>— A directory of embedded migration files, loaded at compile time.
Constants:
BM_ARCHIVE— A constant instance ofDbInfofor the"bm-archive"database, with migrations loaded from the path $CARGO_MANIFEST_DIR/migrations/bm-archive.
Struct: DbMaintenance
Encapsulates maintenance operations on a database, such as migrations.
Fields:
path: PathBuf— Filesystem path to the database file.info: &'static DbInfo— Reference to the associatedDbInfometadata.
Methods:
new(info: &'static DbInfo, db_dir: impl AsRef<Path>) -> SelfConstructs a new
DbMaintenanceinstance given database info and a directory path. It resolves the full database file path by joining the directory with the database name plus.dbextension.Parameters:
info: Reference to the database metadata.db_dir: Path to the directory containing the database file.
Returns:
A new
DbMaintenanceinstance.
Usage Example:
let db_maintenance = DbMaintenance::new(&DbInfo::BM_ARCHIVE, "./data");migrate_all_to_latest(db_dir: impl AsRef<Path>, options: DbMaintenanceOptions) -> anyhow::Result<()>Performs migration of all known databases to their latest schema versions. Currently, only migrates the
BM_ARCHIVEdatabase.Parameters:
db_dir: Directory containing the database files.options: Options controlling migration behavior (e.g., silent mode).
Returns:
Ok(())on success.Error wrapped in
anyhow::Resulton failure.
Usage Example:
DbMaintenance::migrate_all_to_latest("./data", DbMaintenanceOptions::default())?;migrate(&self, migrate_to: MigrateTo, options: DbMaintenanceOptions) -> anyhow::Result<()>Applies migrations to the target database, migrating either up or down to a specified version.
Parameters:
migrate_to: Target version enum indicating whether to migrate to latest, none, or a specific version.options: Controls verbosity and other behaviors (e.g.,silent).
Returns:
Ok(())if migration succeeds.Errif migration fails or invalid version is requested.
Implementation Details:
Ensures the parent directory for the database exists.
Opens a SQLite connection to the database.
Reads the current schema version from the
user_versionpragma.Loads embedded migrations and validates them.
Prints migration info unless silent.
Resolves the target version and performs the migration using
rusqlite_migration.Prints migration progress and result if not silent.
Usage Example:
let db_maintenance = DbMaintenance::new(&DbInfo::BM_ARCHIVE, "./data"); db_maintenance.migrate(MigrateTo::Latest, DbMaintenanceOptions { silent: false })?;
Struct: DbMaintenanceOptions
Holds options to configure the behavior of database maintenance operations.
Fields:
silent: bool— Iftrue, suppresses informational output during migrations.
Marked with
DefaultandClone, allowing easy instantiation and duplication.
Enum: MigrateTo
Defines migration target versions.
Variants:
None— No migration to be performed.Latest— Migrate to the latest schema version available.Version(u32)— Migrate to a specific schema version number.
Implements
TryFrom<Option<String>>for parsing from optional string inputs:"latest"maps toLatest.Numeric strings map to
Version.Nonemaps toNone.Invalid strings cause an error.
Functions
resolve_version(migrate_to: &MigrateTo, latest_migrations_version: u32) -> anyhow::Result<u32>
Resolves the effective target version number to migrate to based on the MigrateTo enum and the highest available migration version.
If
LatestorNone, returns the latest migration version.If a specific
Version(n), verifies thatnis not greater than the latest version, otherwise errors.
get_latest_migration_version(migrations_dir: &'static Dir<'static>) -> anyhow::Result<u32>
Extracts the highest migration version number from the embedded migrations directory structure.
Iterates through subdirectories whose names start with a numeric prefix (e.g.,
"001-init").Returns the maximum numeric prefix found as the latest migration version.
Testing
The
testsmodule useslazy_staticto initialize migration sets once.Includes a test to validate the embedded migrations for the
BM_ARCHIVEdatabase.
Implementation Details and Algorithms
Database migrations are embedded at compile-time using the [
include_dir] crate. This avoids runtime file system dependencies.Migration directories are expected to be named with leading version numbers (e.g.,
001-init,002-add_table), which are parsed to determine migration order.The migration version is tracked using the SQLite
user_versionpragma, a standard practice for lightweight versioning.Migration operations use the [
rusqlite_migration] crate, which manages applying SQL scripts in order and supports both upgrades and downgrades.The migration logic supports silent mode to suppress standard output for integration scenarios.
Error handling uses the [
anyhow] crate to provide context-rich error messages.
Interaction with Other System Components
Depends on embedded migration files located under the
migrationsdirectory relative to the Cargo manifest directory.Relies on
rusqlitefor database connection handling, integrating with the SQLite engine.Uses
rusqlite_migrationto apply migration scripts and manage schema versions.The migration utilities here can be invoked during application startup or maintenance operations to ensure the database schema is current.
The
DbInfoabstraction allows extension to multiple databases by adding new constants and migration directories.
Mermaid Diagram: Structure of lib.rs
classDiagram
class DbInfo {
-name: &'static str
-migrations: Dir
+BM_ARCHIVE: DbInfo
}
class DbMaintenance {
-path: PathBuf
-info: &'static DbInfo
+new()
+migrate()
+migrate_all_to_latest()
}
class DbMaintenanceOptions {
+silent: bool
}
class MigrateTo {
<<enum>>
+None
+Latest
+Version(u32)
}
DbMaintenance o-- DbInfo
DbMaintenance ..> DbMaintenanceOptions
DbMaintenance ..> MigrateTo