fix Drop Column to only be generated if no columns conflict in Indexes

This commit is contained in:
pedrocarlo
2025-10-09 19:29:14 -03:00
parent 9c2edbb8b7
commit a149e55209

View File

@@ -1,6 +1,6 @@
use crate::generation::{
gen_random_text, pick_n_unique, pick_unique, Arbitrary, ArbitraryFrom, ArbitrarySized,
GenerationContext,
gen_random_text, pick_index, pick_n_unique, pick_unique, Arbitrary, ArbitraryFrom,
ArbitrarySized, GenerationContext,
};
use crate::model::query::alter_table::{AlterTable, AlterTableType, AlterTableTypeDiscriminants};
use crate::model::query::predicate::Predicate;
@@ -392,26 +392,52 @@ impl Arbitrary for Update {
}
}
impl Arbitrary for AlterTable {
fn arbitrary<R: Rng + ?Sized, C: GenerationContext>(rng: &mut R, context: &C) -> Self {
let table = pick(context.tables(), rng);
let choices: &'static [AlterTableTypeDiscriminants] = if table.columns.len() > 1 {
&[
AlterTableTypeDiscriminants::RenameTo,
AlterTableTypeDiscriminants::AddColumn,
// AlterTableTypeDiscriminants::AlterColumn,
AlterTableTypeDiscriminants::RenameColumn,
AlterTableTypeDiscriminants::DropColumn,
]
} else {
&[
AlterTableTypeDiscriminants::RenameTo,
AlterTableTypeDiscriminants::AddColumn,
// AlterTableTypeDiscriminants::AlterColumn,
AlterTableTypeDiscriminants::RenameColumn,
]
};
let alter_table_type = match choices.choose(rng).unwrap() {
const ALTER_TABLE_ALL: &[AlterTableTypeDiscriminants] = &[
AlterTableTypeDiscriminants::RenameTo,
AlterTableTypeDiscriminants::AddColumn,
// AlterTableTypeDiscriminants::AlterColumn,
AlterTableTypeDiscriminants::RenameColumn,
AlterTableTypeDiscriminants::DropColumn,
];
const ALTER_TABLE_NO_DROP: &[AlterTableTypeDiscriminants] = &[
AlterTableTypeDiscriminants::RenameTo,
AlterTableTypeDiscriminants::AddColumn,
// AlterTableTypeDiscriminants::AlterColumn,
AlterTableTypeDiscriminants::RenameColumn,
];
// TODO: Unfortunately this diff strategy allocates a couple of IndexSet's
// in the future maybe change this to be more efficient. This is currently acceptable because this function
// is only called for `DropColumn`
fn get_column_diff(table: &Table) -> IndexSet<&str> {
// Columns that are referenced in INDEXES cannot be dropped
let column_cannot_drop = table
.indexes
.iter()
.flat_map(|index| index.columns.iter().map(|(col_name, _)| col_name.as_str()))
.collect::<IndexSet<_>>();
if column_cannot_drop.len() == table.columns.len() {
// Optimization: all columns are present in indexes so we do not need to but the table column set
return IndexSet::new();
}
let column_set: IndexSet<_, std::hash::RandomState> =
IndexSet::from_iter(table.columns.iter().map(|col| col.name.as_str()));
let diff = column_set
.difference(&column_cannot_drop)
.copied()
.collect::<IndexSet<_, std::hash::RandomState>>();
diff
}
impl ArbitraryFrom<(&Table, &[AlterTableTypeDiscriminants])> for AlterTableType {
fn arbitrary_from<R: Rng + ?Sized, C: GenerationContext>(
rng: &mut R,
context: &C,
(table, choices): (&Table, &[AlterTableTypeDiscriminants]),
) -> Self {
match choices.choose(rng).unwrap() {
AlterTableTypeDiscriminants::RenameTo => AlterTableType::RenameTo {
new_name: Name::arbitrary(rng, context).0,
},
@@ -425,10 +451,39 @@ impl Arbitrary for AlterTable {
old: pick(&table.columns, rng).name.clone(),
new: Name::arbitrary(rng, context).0,
},
AlterTableTypeDiscriminants::DropColumn => AlterTableType::DropColumn {
column_name: pick(&table.columns, rng).name.clone(),
},
AlterTableTypeDiscriminants::DropColumn => {
let col_diff = get_column_diff(table);
if col_diff.is_empty() {
// Generate a DropColumn if we can drop a column
return AlterTableType::arbitrary_from(
rng,
context,
(table, ALTER_TABLE_NO_DROP),
);
}
let col_idx = pick_index(col_diff.len(), rng);
let col_name = col_diff.get_index(col_idx).unwrap();
AlterTableType::DropColumn {
column_name: col_name.to_string(),
}
}
}
}
}
impl Arbitrary for AlterTable {
fn arbitrary<R: Rng + ?Sized, C: GenerationContext>(rng: &mut R, context: &C) -> Self {
let table = pick(context.tables(), rng);
let choices: &'static [AlterTableTypeDiscriminants] = if table.columns.len() > 1 {
ALTER_TABLE_ALL
} else {
ALTER_TABLE_NO_DROP
};
let alter_table_type = AlterTableType::arbitrary_from(rng, context, (table, choices));
Self {
table_name: table.name.clone(),
alter_table_type,