Skip to content

Commit 187862d

Browse files
committed
Add testcase
1 parent 84b46fc commit 187862d

1 file changed

Lines changed: 106 additions & 24 deletions

File tree

crates/vespertide-cli/src/commands/revision.rs

Lines changed: 106 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -526,40 +526,46 @@ fn rewrite_plan_for_recreation(
526526
}
527527
}
528528

529+
/// Whether the caller should continue processing the plan or return early.
529530
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
530-
enum RecreateHandling {
531-
NotNeeded,
532-
Rewritten,
533-
PlanEmptied,
531+
enum RecreateOutcome {
532+
/// No recreation was needed, or recreation succeeded. Continue processing.
533+
Continue,
534+
/// Plan is empty after recreation rewrite. Caller should return early.
535+
Done,
534536
}
535537

536538
fn handle_recreate_requirements<F>(
537539
plan: &mut MigrationPlan,
538540
current_models: &[TableDef],
539541
prompt_fn: F,
540-
) -> Result<RecreateHandling>
542+
) -> Result<RecreateOutcome>
541543
where
542544
F: Fn(&[RecreateTableRequired]) -> Result<bool>,
543545
{
544546
let recreate_tables = find_non_nullable_fk_add_columns(plan, current_models);
545547
if recreate_tables.is_empty() {
546-
return Ok(RecreateHandling::NotNeeded);
548+
return Ok(RecreateOutcome::Continue);
547549
}
548550

549551
if !prompt_fn(&recreate_tables)? {
550552
anyhow::bail!(
551-
"Migration cancelled. To proceed without recreation, make the column nullable \
552-
or add it with a default value that references an existing row."
553+
"Migration cancelled. To proceed without recreation, make the column nullable or add it with a default value that references an existing row."
553554
);
554555
}
555556

556557
rewrite_plan_for_recreation(plan, &recreate_tables, current_models);
557558

558559
if plan.actions.is_empty() {
559-
return Ok(RecreateHandling::PlanEmptied);
560+
println!(
561+
"{} {}",
562+
"No changes detected.".bright_yellow(),
563+
"Nothing to migrate.".bright_white()
564+
);
565+
return Ok(RecreateOutcome::Done);
560566
}
561567

562-
Ok(RecreateHandling::Rewritten)
568+
Ok(RecreateOutcome::Continue)
563569
}
564570

565571
pub async fn cmd_revision(message: String, fill_with_args: Vec<String>) -> Result<()> {
@@ -580,16 +586,11 @@ pub async fn cmd_revision(message: String, fill_with_args: Vec<String>) -> Resul
580586
}
581587

582588
// Check for non-nullable FK changes that require table recreation.
583-
match handle_recreate_requirements(&mut plan, &current_models, prompt_recreate_tables)? {
584-
RecreateHandling::NotNeeded | RecreateHandling::Rewritten => {}
585-
RecreateHandling::PlanEmptied => {
586-
println!(
587-
"{} {}",
588-
"No changes detected.".bright_yellow(),
589-
"Nothing to migrate.".bright_white()
590-
);
591-
return Ok(());
592-
}
589+
if matches!(
590+
handle_recreate_requirements(&mut plan, &current_models, prompt_recreate_tables)?,
591+
RecreateOutcome::Done
592+
) {
593+
return Ok(());
593594
}
594595

595596
// Reconstruct baseline schema for column type lookups
@@ -1311,7 +1312,7 @@ mod tests {
13111312
}
13121313

13131314
#[test]
1314-
fn handle_recreate_requirements_returns_not_needed() {
1315+
fn handle_recreate_requirements_returns_continue_when_no_fk() {
13151316
let mut plan = MigrationPlan {
13161317
id: String::new(),
13171318
comment: None,
@@ -1324,7 +1325,7 @@ mod tests {
13241325

13251326
let result = handle_recreate_requirements(&mut plan, &[], |_| Ok(true)).unwrap();
13261327

1327-
assert_eq!(result, RecreateHandling::NotNeeded);
1328+
assert_eq!(result, RecreateOutcome::Continue);
13281329
assert_eq!(plan.actions.len(), 1);
13291330
}
13301331

@@ -1376,7 +1377,7 @@ mod tests {
13761377
}
13771378

13781379
#[test]
1379-
fn handle_recreate_requirements_returns_plan_emptied_when_model_missing() {
1380+
fn handle_recreate_requirements_returns_done_when_model_missing() {
13801381
use vespertide_core::{ColumnDef, ColumnType, SimpleColumnType};
13811382

13821383
let mut plan = MigrationPlan {
@@ -1416,10 +1417,91 @@ mod tests {
14161417

14171418
let result = handle_recreate_requirements(&mut plan, &[], |_| Ok(true)).unwrap();
14181419

1419-
assert_eq!(result, RecreateHandling::PlanEmptied);
1420+
assert_eq!(result, RecreateOutcome::Done);
14201421
assert!(plan.actions.is_empty());
14211422
}
14221423

1424+
#[test]
1425+
fn handle_recreate_requirements_returns_continue_after_rewrite() {
1426+
use vespertide_core::{ColumnDef, ColumnType, SimpleColumnType};
1427+
1428+
let mut plan = MigrationPlan {
1429+
id: String::new(),
1430+
comment: None,
1431+
created_at: None,
1432+
version: 1,
1433+
actions: vec![
1434+
MigrationAction::AddColumn {
1435+
table: "post".into(),
1436+
column: Box::new(ColumnDef {
1437+
name: "user_id".into(),
1438+
r#type: ColumnType::Simple(SimpleColumnType::Uuid),
1439+
nullable: false,
1440+
default: None,
1441+
comment: None,
1442+
primary_key: None,
1443+
unique: None,
1444+
index: None,
1445+
foreign_key: None,
1446+
}),
1447+
fill_with: None,
1448+
},
1449+
MigrationAction::AddConstraint {
1450+
table: "post".into(),
1451+
constraint: TableConstraint::ForeignKey {
1452+
name: None,
1453+
columns: vec!["user_id".into()],
1454+
ref_table: "user".into(),
1455+
ref_columns: vec!["id".into()],
1456+
on_delete: None,
1457+
on_update: None,
1458+
},
1459+
},
1460+
],
1461+
};
1462+
1463+
let models = vec![TableDef {
1464+
name: "post".into(),
1465+
description: None,
1466+
columns: vec![
1467+
ColumnDef {
1468+
name: "id".into(),
1469+
r#type: ColumnType::Simple(SimpleColumnType::Integer),
1470+
nullable: false,
1471+
default: None,
1472+
comment: None,
1473+
primary_key: None,
1474+
unique: None,
1475+
index: None,
1476+
foreign_key: None,
1477+
},
1478+
ColumnDef {
1479+
name: "user_id".into(),
1480+
r#type: ColumnType::Simple(SimpleColumnType::Uuid),
1481+
nullable: false,
1482+
default: None,
1483+
comment: None,
1484+
primary_key: None,
1485+
unique: None,
1486+
index: None,
1487+
foreign_key: None,
1488+
},
1489+
],
1490+
constraints: vec![],
1491+
}];
1492+
1493+
let result = handle_recreate_requirements(&mut plan, &models, |_| Ok(true)).unwrap();
1494+
1495+
assert_eq!(result, RecreateOutcome::Continue);
1496+
assert_eq!(plan.actions.len(), 2);
1497+
assert!(
1498+
matches!(&plan.actions[0], MigrationAction::DeleteTable { table } if table == "post")
1499+
);
1500+
assert!(
1501+
matches!(&plan.actions[1], MigrationAction::CreateTable { table, .. } if table == "post")
1502+
);
1503+
}
1504+
14231505
#[test]
14241506
fn test_parse_fill_with_args() {
14251507
let args = vec![

0 commit comments

Comments
 (0)