Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changepacks/changepack_log_S-V1v7UFYiEf3XeW_9d1F.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"changes":{"crates/vespertide-config/Cargo.toml":"Patch","crates/vespertide-query/Cargo.toml":"Patch","crates/vespertide-naming/Cargo.toml":"Patch","crates/vespertide-cli/Cargo.toml":"Patch","crates/vespertide/Cargo.toml":"Patch","crates/vespertide-exporter/Cargo.toml":"Patch","crates/vespertide-macro/Cargo.toml":"Patch","crates/vespertide-core/Cargo.toml":"Patch","crates/vespertide-loader/Cargo.toml":"Patch","crates/vespertide-planner/Cargo.toml":"Patch"},"note":"Add prefix option","date":"2026-01-21T09:42:55.945270800Z"}
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
echo 'merge_derives = true' >> .rustfmt.toml
echo 'use_small_heuristics = "Default"' >> .rustfmt.toml
cargo fmt
cargo tarpaulin --out Lcov Stdout --workspace --exclude app
cargo tarpaulin --engine llvm --out Lcov Stdout --workspace --exclude app
- name: Upload to codecov.io
uses: codecov/codecov-action@v5
with:
Expand Down
8 changes: 6 additions & 2 deletions crates/vespertide-cli/src/commands/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,22 @@ pub fn cmd_log(backend: DatabaseBackend) -> Result<()> {
return Ok(());
}

// Apply prefix to all migration plans
let prefix = config.prefix();
let prefixed_plans: Vec<_> = plans.into_iter().map(|p| p.with_prefix(prefix)).collect();

println!(
"{} {} {}",
"Migrations".bright_cyan().bold(),
"(oldest -> newest):".bright_white(),
plans.len().to_string().bright_yellow().bold()
prefixed_plans.len().to_string().bright_yellow().bold()
);
println!();

// Build baseline schema incrementally as we iterate through migrations
let mut baseline_schema = Vec::new();

for plan in &plans {
for plan in &prefixed_plans {
println!(
"{} {}",
"Version:".bright_cyan().bold(),
Expand Down
19 changes: 14 additions & 5 deletions crates/vespertide-cli/src/commands/sql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,24 @@ pub fn cmd_sql(backend: DatabaseBackend) -> Result<()> {
let current_models = load_models(&config)?;
let applied_plans = load_migrations(&config)?;

// Reconstruct the baseline schema from applied migrations
let baseline_schema = schema_from_plans(&applied_plans)
// Reconstruct the baseline schema from applied migrations (with prefix applied)
let prefix = config.prefix();
let prefixed_plans: Vec<_> = applied_plans
.into_iter()
.map(|p| p.with_prefix(prefix))
.collect();
let baseline_schema = schema_from_plans(&prefixed_plans)
.map_err(|e| anyhow::anyhow!("failed to reconstruct schema: {}", e))?;

// Plan next migration using the pre-computed baseline
let plan = plan_next_migration_with_baseline(&current_models, &applied_plans, &baseline_schema)
.map_err(|e| anyhow::anyhow!("planning error: {}", e))?;
let plan =
plan_next_migration_with_baseline(&current_models, &prefixed_plans, &baseline_schema)
.map_err(|e| anyhow::anyhow!("planning error: {}", e))?;

// Apply prefix to the new plan for SQL generation
let prefixed_plan = plan.with_prefix(prefix);

emit_sql(&plan, backend, &baseline_schema)
emit_sql(&prefixed_plan, backend, &baseline_schema)
}

fn emit_sql(
Expand Down
40 changes: 40 additions & 0 deletions crates/vespertide-config/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ pub struct VespertideConfig {
/// SeaORM-specific export configuration.
#[serde(default)]
pub seaorm: SeaOrmConfig,
/// Prefix to add to all table names (including migration version table).
/// Default: "" (no prefix)
#[serde(default)]
pub prefix: String,
}

fn default_model_export_dir() -> PathBuf {
Expand All @@ -101,6 +105,7 @@ impl Default for VespertideConfig {
migration_filename_pattern: default_migration_filename_pattern(),
model_export_dir: default_model_export_dir(),
seaorm: SeaOrmConfig::default(),
prefix: String::new(),
}
}
}
Expand Down Expand Up @@ -150,6 +155,20 @@ impl VespertideConfig {
pub fn seaorm(&self) -> &SeaOrmConfig {
&self.seaorm
}

/// Prefix to add to all table names.
pub fn prefix(&self) -> &str {
&self.prefix
}

/// Apply prefix to a table name.
pub fn apply_prefix(&self, table_name: &str) -> String {
if self.prefix.is_empty() {
table_name.to_string()
} else {
format!("{}{}", self.prefix, table_name)
}
}
}

#[cfg(test)]
Expand All @@ -173,5 +192,26 @@ mod tests {
vec!["vespera::Schema".to_string()]
);
assert!(config.seaorm.extra_model_derives.is_empty());
assert_eq!(config.prefix, "");
}

#[test]
fn test_vespertide_config_prefix() {
let config = VespertideConfig {
prefix: "myapp_".to_string(),
..Default::default()
};

assert_eq!(config.prefix(), "myapp_");
assert_eq!(config.apply_prefix("users"), "myapp_users");
assert_eq!(config.apply_prefix("posts"), "myapp_posts");
}

#[test]
fn test_vespertide_config_empty_prefix() {
let config = VespertideConfig::default();

assert_eq!(config.prefix(), "");
assert_eq!(config.apply_prefix("users"), "users");
}
}
Loading