Crates.io | monarch-db |
lib.rs | monarch-db |
version | 0.1.1 |
created_at | 2025-07-12 13:57:34.248588+00 |
updated_at | 2025-07-14 22:47:32.868112+00 |
description | A simple SQLite DB Migration system |
homepage | |
repository | |
max_upload_size | |
id | 1749327 |
size | 87,271 |
Monarch-DB is a lightweight rusqlite database migration tool designed to run whenever the first connection in an app opens. It provides a simple, reliable way to manage SQLite database schema evolution in Rust applications.
Add this to your Cargo.toml
:
[dependencies]
monarch-db = "0.1"
# Optional: Enable serde support for configuration
monarch-db = { version = "0.1", features = ["serde"] }
Use static configuration when you want to embed migrations directly in your binary:
use monarch_db::{StaticMonarchConfiguration, MonarchDB, ConnectionConfiguration};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Define your migrations at compile time
let config = StaticMonarchConfiguration {
name: "my_app",
enable_foreign_keys: true,
migrations: [
// Migration 1: Create users table
r#"
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
email TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
"#,
// Migration 2: Create posts table
r#"
CREATE TABLE posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
title TEXT NOT NULL,
content TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
"#,
// Migration 3: Add indexes
r#"
CREATE INDEX idx_users_username ON users(username);
CREATE INDEX idx_posts_user_id ON posts(user_id);
"#,
],
};
// Convert to MonarchDB instance
let monarch_db: MonarchDB = config.into();
// Create connection configuration
let connection_config = ConnectionConfiguration {
database: Some("./my_app.db".into()), // Use None for in-memory
};
// Create database connection with migrations applied
let connection = monarch_db.create_connection(&connection_config)?;
// Use your database normally
connection.execute(
"INSERT INTO users (username, email) VALUES (?, ?)",
["alice", "alice@example.com"],
)?;
Ok(())
}
Use directory-based configuration when you want to manage migrations as separate files:
use monarch_db::{MonarchConfiguration, MonarchDB, ConnectionConfiguration};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = MonarchConfiguration {
name: "my_app".to_string(),
enable_foreign_keys: true,
migration_directory: "./migrations".into(),
};
let monarch_db = MonarchDB::from_configuration(config)?;
let connection_config = ConnectionConfiguration {
database: Some("./my_app.db".into()),
};
let connection = monarch_db.create_connection(&connection_config)?;
// Database is ready with all migrations applied
Ok(())
}
With migration files in ./migrations/
:
migrations/
├── 001_create_users.sql
├── 002_create_posts.sql
└── 003_add_indexes.sql
001_create_users.sql:
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
email TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
002_create_posts.sql:
CREATE TABLE posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
title TEXT NOT NULL,
content TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
003_add_indexes.sql:
CREATE INDEX idx_users_username ON users(username);
CREATE INDEX idx_posts_user_id ON posts(user_id);
Create temporary databases perfect for testing:
let connection = monarch_db.open_in_memory()?;
For static configuration, you can use include_str!
for better organization:
let config = StaticMonarchConfiguration {
name: "my_app",
enable_foreign_keys: true,
migrations: [
include_str!("../migrations/001_create_users.sql"),
include_str!("../migrations/002_create_posts.sql"),
include_str!("../migrations/003_add_indexes.sql"),
],
};
Enable the serde
feature to deserialize configurations:
use serde::Deserialize;
#[derive(Deserialize)]
struct AppConfig {
database: monarch_db::MonarchConfiguration,
connection: monarch_db::ConnectionConfiguration,
}
let config: AppConfig = toml::from_str(r#"
[database]
name = "my_app"
enable_foreign_keys = true
migration_directory = "./migrations"
[connection]
database = "./app.db"
"#)?;
let monarch_db = MonarchDB::from_configuration(config.database)?;
let connection = monarch_db.create_connection(&config.connection)?;
Check the current schema version:
let current_version = monarch_db.current_version();
println!("Database schema is at version: {}", current_version);
You can apply migrations to an existing connection:
use rusqlite::Connection;
let raw_connection = Connection::open("./my_app.db")?;
let migrated_connection = monarch_db.migrations(raw_connection)?;
Monarch-DB includes a command-line tool for running migrations outside of your application code. This is useful for deployment scripts, CI/CD pipelines, or manual database management.
Apply all pending migrations to a database:
monarch migrate <migrations_dir> <app_name> <sqlite_url>
Arguments:
migrations_dir
- Path to directory containing migration filesapp_name
- Name of the application (used for version tracking)sqlite_url
- SQLite database URL (file path or :memory:
)Examples:
# Apply migrations to a file database
monarch migrate ./migrations my_app ./database.db
# Apply migrations to an in-memory database
monarch migrate ./migrations my_app :memory:
# Apply migrations for a specific environment
monarch migrate ./db/migrations production_app /var/lib/myapp/prod.db
Sample Output:
Running migrations...
Migrations directory: ./migrations
Application name: my_app
Database: ./database.db
Found 3 migration(s)
Migration completed successfully!
Current schema version: 3
Database is up to date.
Check the current migration status without applying changes:
monarch version <migrations_dir> <app_name> <sqlite_url>
Examples:
# Check migration status
monarch version ./migrations my_app ./database.db
# Check status of a database that doesn't exist yet
monarch version ./migrations my_app ./new_database.db
Sample Output:
Checking migration version...
Migrations directory: ./migrations
Application name: my_app
Database: ./database.db
Available migrations: 5
Current schema version: 3
Migrations pending: 3 -> 5 (2 new migration(s))
Run the test suite:
# Run all tests (unit + integration)
cargo test
# Run only unit tests
cargo test --lib
# Run only integration tests
cargo test --test static_configuration
cargo test --test directory_configuration
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
This project is licensed under the MIT License - see the LICENSE file for details.