1 parent
2517307801
commit
6a88df5500
3 files changed
+204
-9
No files matched your search
@@ -182,6 +182,7 @@ pub fn build_create_table_sql(mut options: TableStructureSqlOptions) -> TableStr
|
||||
&mut warnings,
|
||||
options.schema.as_deref(),
|
||||
&options.table_name,
|
||||
false,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -47,13 +47,17 @@ pub(super) fn build_index_sql(options: &TableStructureSqlOptions, warnings: &mut
|
||||
warnings.push(format!("Primary index \"{}\" cannot be edited from this editor.", original.name));
|
||||
continue;
|
||||
}
|
||||
statements.push(build_drop_index_sql(
|
||||
options.database_type,
|
||||
dialect,
|
||||
&table,
|
||||
options.schema.as_deref(),
|
||||
&original.name,
|
||||
));
|
||||
let or_replace =
|
||||
options.database_type == Some(DatabaseType::Dameng) && clean(&index.name) == clean(&original.name);
|
||||
if !or_replace {
|
||||
statements.push(build_drop_index_sql(
|
||||
options.database_type,
|
||||
dialect,
|
||||
&table,
|
||||
options.schema.as_deref(),
|
||||
&original.name,
|
||||
));
|
||||
}
|
||||
statements.extend(build_create_index_statements(
|
||||
dialect,
|
||||
&table,
|
||||
@@ -61,6 +65,7 @@ pub(super) fn build_index_sql(options: &TableStructureSqlOptions, warnings: &mut
|
||||
warnings,
|
||||
options.schema.as_deref(),
|
||||
&options.table_name,
|
||||
or_replace,
|
||||
));
|
||||
continue;
|
||||
}
|
||||
@@ -76,6 +81,7 @@ pub(super) fn build_index_sql(options: &TableStructureSqlOptions, warnings: &mut
|
||||
warnings,
|
||||
options.schema.as_deref(),
|
||||
&options.table_name,
|
||||
false,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -161,6 +167,7 @@ pub(super) fn build_create_index_statements(
|
||||
warnings: &mut Vec<String>,
|
||||
schema: Option<&str>,
|
||||
table_name: &str,
|
||||
or_replace: bool,
|
||||
) -> Vec<String> {
|
||||
let capabilities = capabilities_for(database_type_for_dialect(dialect));
|
||||
let name = clean(&index.name);
|
||||
@@ -171,6 +178,7 @@ pub(super) fn build_create_index_statements(
|
||||
}
|
||||
|
||||
let unique = if index.is_unique { "UNIQUE " } else { "" };
|
||||
let replace = if or_replace { "OR REPLACE " } else { "" };
|
||||
let cols = columns
|
||||
.iter()
|
||||
.map(|column| {
|
||||
@@ -236,11 +244,11 @@ pub(super) fn build_create_index_statements(
|
||||
if dialect == StructureDialect::Sqlite { quote_ident(dialect, table_name) } else { table.to_string() };
|
||||
let create_sql = if dialect == StructureDialect::Postgres {
|
||||
format!(
|
||||
"CREATE {unique}{type_prefix}INDEX {index_name} ON {create_table}{using_clause} ({cols}){include_clause}{where_clause};"
|
||||
"CREATE {replace}{unique}{type_prefix}INDEX {index_name} ON {create_table}{using_clause} ({cols}){include_clause}{where_clause};"
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"CREATE {unique}{type_prefix}INDEX {index_name}{using_clause} ON {create_table} ({cols}){include_clause}{where_clause}{comment_clause};"
|
||||
"CREATE {replace}{unique}{type_prefix}INDEX {index_name}{using_clause} ON {create_table} ({cols}){include_clause}{where_clause}{comment_clause};"
|
||||
)
|
||||
};
|
||||
let mut statements = vec![create_sql];
|
||||
|
||||
@@ -78,6 +78,40 @@ fn index(name: &str, columns: &[&str]) -> EditableStructureIndex {
|
||||
}
|
||||
}
|
||||
|
||||
fn existing_index(name: &str, columns: &[&str], is_unique: bool) -> EditableStructureIndex {
|
||||
let mut index = index(name, columns);
|
||||
index.is_unique = is_unique;
|
||||
index.original = Some(IndexInfo {
|
||||
name: name.to_string(),
|
||||
columns: columns.iter().map(|column| column.to_string()).collect(),
|
||||
is_unique,
|
||||
is_primary: false,
|
||||
filter: None,
|
||||
index_type: None,
|
||||
included_columns: None,
|
||||
comment: None,
|
||||
});
|
||||
index
|
||||
}
|
||||
|
||||
fn index_change_options(
|
||||
database_type: DatabaseType,
|
||||
schema: Option<&str>,
|
||||
index: EditableStructureIndex,
|
||||
) -> TableStructureSqlOptions {
|
||||
TableStructureSqlOptions {
|
||||
database_type: Some(database_type),
|
||||
schema: schema.map(str::to_string),
|
||||
table_name: "USERS".to_string(),
|
||||
columns: Vec::new(),
|
||||
indexes: vec![index],
|
||||
foreign_keys: Vec::new(),
|
||||
triggers: Vec::new(),
|
||||
table_comment: None,
|
||||
original_table_comment: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn foreign_key(name: &str, column: &str, ref_table: &str, ref_column: &str) -> EditableStructureForeignKey {
|
||||
EditableStructureForeignKey {
|
||||
id: name.to_string(),
|
||||
@@ -163,6 +197,158 @@ fn builds_mysql_column_and_index_changes() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dameng_replaces_same_name_index_before_validating_uniqueness() {
|
||||
let mut changed = existing_index("IDX_USERS_EMAIL", &["EMAIL"], false);
|
||||
changed.name = " IDX_USERS_EMAIL ".to_string();
|
||||
changed.is_unique = true;
|
||||
|
||||
let mut options = index_change_options(DatabaseType::Dameng, Some("SYSDBA"), changed);
|
||||
options.table_name = "DBX_6002_USERS".to_string();
|
||||
let result = build_table_structure_change_sql(options);
|
||||
|
||||
assert_eq!(result.warnings, Vec::<String>::new());
|
||||
assert_eq!(
|
||||
result.statements,
|
||||
vec!["CREATE OR REPLACE UNIQUE INDEX \"IDX_USERS_EMAIL\" ON \"SYSDBA\".\"DBX_6002_USERS\" (\"EMAIL\");"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dameng_replaces_same_name_unique_index_with_normal_index() {
|
||||
let mut changed = existing_index("IDX_USERS_EMAIL", &["EMAIL"], true);
|
||||
changed.is_unique = false;
|
||||
|
||||
let result = build_table_structure_change_sql(index_change_options(DatabaseType::Dameng, Some("APP"), changed));
|
||||
|
||||
assert_eq!(result.warnings, Vec::<String>::new());
|
||||
assert_eq!(
|
||||
result.statements,
|
||||
vec!["CREATE OR REPLACE INDEX \"IDX_USERS_EMAIL\" ON \"APP\".\"USERS\" (\"EMAIL\");"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dameng_replaces_same_name_index_when_columns_change() {
|
||||
let mut changed = existing_index("IDX_USERS_EMAIL", &["EMAIL"], false);
|
||||
changed.columns = vec!["LOGIN".to_string(), "EMAIL".to_string()];
|
||||
|
||||
let result = build_table_structure_change_sql(index_change_options(DatabaseType::Dameng, Some("APP"), changed));
|
||||
|
||||
assert_eq!(result.warnings, Vec::<String>::new());
|
||||
assert_eq!(
|
||||
result.statements,
|
||||
vec!["CREATE OR REPLACE INDEX \"IDX_USERS_EMAIL\" ON \"APP\".\"USERS\" (\"LOGIN\", \"EMAIL\");"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dameng_replaces_same_name_index_when_type_changes_to_bitmap() {
|
||||
let mut changed = existing_index("IDX_USERS_EMAIL", &["EMAIL"], false);
|
||||
changed.index_type = "bitmap".to_string();
|
||||
|
||||
let result = build_table_structure_change_sql(index_change_options(DatabaseType::Dameng, Some("APP"), changed));
|
||||
|
||||
assert_eq!(result.warnings, Vec::<String>::new());
|
||||
assert_eq!(
|
||||
result.statements,
|
||||
vec!["CREATE OR REPLACE BITMAP INDEX \"IDX_USERS_EMAIL\" ON \"APP\".\"USERS\" (\"EMAIL\");"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dameng_replaces_same_name_index_without_unsupported_comment_clause() {
|
||||
let mut changed = existing_index("IDX_USERS_EMAIL", &["EMAIL"], false);
|
||||
changed.comment = "New comment".to_string();
|
||||
changed.original.as_mut().unwrap().comment = Some("Old comment".to_string());
|
||||
|
||||
let result = build_table_structure_change_sql(index_change_options(DatabaseType::Dameng, Some("APP"), changed));
|
||||
|
||||
assert_eq!(result.warnings, Vec::<String>::new());
|
||||
assert_eq!(
|
||||
result.statements,
|
||||
vec!["CREATE OR REPLACE INDEX \"IDX_USERS_EMAIL\" ON \"APP\".\"USERS\" (\"EMAIL\");"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dameng_renamed_index_keeps_drop_then_create_path() {
|
||||
let mut changed = existing_index("IDX_USERS_EMAIL", &["EMAIL"], false);
|
||||
changed.name = "IDX_USERS_LOGIN".to_string();
|
||||
|
||||
let result = build_table_structure_change_sql(index_change_options(DatabaseType::Dameng, Some("APP"), changed));
|
||||
|
||||
assert_eq!(result.warnings, Vec::<String>::new());
|
||||
assert_eq!(
|
||||
result.statements,
|
||||
vec![
|
||||
"DROP INDEX \"APP\".\"IDX_USERS_EMAIL\";",
|
||||
"CREATE INDEX \"IDX_USERS_LOGIN\" ON \"APP\".\"USERS\" (\"EMAIL\");",
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dameng_primary_and_unchanged_indexes_keep_existing_behavior() {
|
||||
let unchanged = existing_index("IDX_USERS_EMAIL", &["EMAIL"], false);
|
||||
let unchanged_result =
|
||||
build_table_structure_change_sql(index_change_options(DatabaseType::Dameng, Some("APP"), unchanged));
|
||||
assert_eq!(unchanged_result.warnings, Vec::<String>::new());
|
||||
assert!(unchanged_result.statements.is_empty());
|
||||
|
||||
let mut primary = existing_index("PK_USERS", &["ID"], true);
|
||||
primary.columns.push("TENANT_ID".to_string());
|
||||
primary.original.as_mut().unwrap().is_primary = true;
|
||||
let primary_result =
|
||||
build_table_structure_change_sql(index_change_options(DatabaseType::Dameng, Some("APP"), primary));
|
||||
assert!(primary_result.statements.is_empty());
|
||||
assert_eq!(primary_result.warnings, vec!["Primary index \"PK_USERS\" cannot be edited from this editor."]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dameng_new_and_dropped_indexes_do_not_use_or_replace() {
|
||||
let new_index = index("IDX_USERS_LOGIN", &["LOGIN"]);
|
||||
let new_result =
|
||||
build_table_structure_change_sql(index_change_options(DatabaseType::Dameng, Some("APP"), new_index));
|
||||
assert_eq!(new_result.warnings, Vec::<String>::new());
|
||||
assert_eq!(new_result.statements, vec!["CREATE INDEX \"IDX_USERS_LOGIN\" ON \"APP\".\"USERS\" (\"LOGIN\");"]);
|
||||
|
||||
let mut dropped = existing_index("IDX_USERS_EMAIL", &["EMAIL"], false);
|
||||
dropped.marked_for_drop = true;
|
||||
let drop_result =
|
||||
build_table_structure_change_sql(index_change_options(DatabaseType::Dameng, Some("APP"), dropped));
|
||||
assert_eq!(drop_result.warnings, Vec::<String>::new());
|
||||
assert_eq!(drop_result.statements, vec!["DROP INDEX \"APP\".\"IDX_USERS_EMAIL\";"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_dameng_index_rebuilds_do_not_use_or_replace() {
|
||||
for database_type in [
|
||||
DatabaseType::Mysql,
|
||||
DatabaseType::Postgres,
|
||||
DatabaseType::Sqlite,
|
||||
DatabaseType::SqlServer,
|
||||
DatabaseType::Oracle,
|
||||
DatabaseType::Oscar,
|
||||
DatabaseType::H2,
|
||||
DatabaseType::Informix,
|
||||
DatabaseType::Iris,
|
||||
] {
|
||||
let mut changed = existing_index("IDX_USERS_EMAIL", &["EMAIL"], false);
|
||||
changed.is_unique = true;
|
||||
let result = build_table_structure_change_sql(index_change_options(database_type, None, changed));
|
||||
|
||||
assert_eq!(result.warnings, Vec::<String>::new(), "database type: {database_type:?}");
|
||||
assert_eq!(result.statements.len(), 2, "database type: {database_type:?}");
|
||||
assert!(result.statements[0].starts_with("DROP INDEX "), "database type: {database_type:?}");
|
||||
assert!(result.statements[1].starts_with("CREATE UNIQUE INDEX "), "database type: {database_type:?}");
|
||||
assert!(
|
||||
result.statements.iter().all(|statement| !statement.contains("OR REPLACE")),
|
||||
"database type: {database_type:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builds_xugu_type_change_with_native_syntax() {
|
||||
let mut code = column("code");
|
||||
|
||||
Reference in new issue
Block a user