1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
use super::{differ_database::DifferDatabase, ColumnTypeChange};
use crate::{migration_pair::MigrationPair, sql_migration::SqlMigrationStep, sql_schema_differ};
use sql_schema_describer::{
walkers::{IndexWalker, TableColumnWalker, TableWalker},
TableColumnId,
};
mod mssql;
mod mysql;
mod postgres;
mod sqlite;
/// Trait to specialize SQL schema diffing (resulting in migration steps) by SQL backend.
pub(crate) trait SqlSchemaDifferFlavour {
fn can_alter_primary_keys(&self) -> bool {
false
}
fn can_redefine_tables_with_inbound_foreign_keys(&self) -> bool {
false
}
/// If this returns `true`, the differ will generate
/// SqlMigrationStep::RedefineIndex steps instead of
/// SqlMigrationStep::AlterIndex.
fn can_rename_index(&self) -> bool {
true
}
/// Returns true only if the database can cope with an optional column
/// constrained by a foreign key being made NOT NULL.
fn can_cope_with_foreign_key_column_becoming_non_nullable(&self) -> bool {
true
}
/// Controls whether we will generate `RenameForeignKey` steps for this flavour.
fn can_rename_foreign_key(&self) -> bool;
/// This method must return whether a column became or ceased to be autoincrementing.
fn column_autoincrement_changed(&self, columns: MigrationPair<TableColumnWalker<'_>>) -> bool {
columns.previous.is_autoincrement() != columns.next.is_autoincrement()
}
/// Return whether a column's type needs to be migrated, and how.
fn column_type_change(&self, differ: MigrationPair<TableColumnWalker<'_>>) -> Option<ColumnTypeChange>;
/// Push enum-related steps.
fn push_enum_steps(&self, _steps: &mut Vec<SqlMigrationStep>, _db: &DifferDatabase<'_>) {}
/// Push AlterSequence steps.
fn push_alter_sequence_steps(&self, _steps: &mut Vec<SqlMigrationStep>, _db: &DifferDatabase<'_>) {}
/// Push AlterExtension steps.
fn push_extension_steps(&self, _steps: &mut Vec<SqlMigrationStep>, _db: &DifferDatabase<'_>) {}
/// Define database-specific extension modules.
fn define_extensions(&self, _db: &mut DifferDatabase<'_>) {}
/// Connector-specific criterias deciding whether two indexes match.
fn indexes_match(&self, _a: IndexWalker<'_>, _b: IndexWalker<'_>) -> bool {
true
}
/// Returns whether the underlying database implicitly drops indexes on dropped (and potentially recreated) columns.
fn indexes_should_be_recreated_after_column_drop(&self) -> bool {
false
}
/// Return whether an index should be renamed by the migration.
fn index_should_be_renamed(&self, indexes: MigrationPair<IndexWalker<'_>>) -> bool {
indexes.previous.name() != indexes.next.name()
}
fn lower_cases_table_names(&self) -> bool {
false
}
/// Did something connector-specific change in the primary key definition?
fn primary_key_changed(&self, _tables: MigrationPair<TableWalker<'_>>) -> bool {
false
}
/// Evaluate indexes/constraints that need to be dropped and re-created based on other changes in the schema
fn push_index_changes_for_column_changes(
&self,
_table: &sql_schema_differ::TableDiffer<'_, '_>,
_column_index: MigrationPair<TableColumnId>,
_column_changes: sql_schema_differ::ColumnChanges,
_steps: &mut Vec<SqlMigrationStep>,
) {
}
/// Whether the differ should produce CreateIndex steps for the indexes of
/// new tables.
fn should_create_indexes_from_created_tables(&self) -> bool {
true
}
/// Whether the indexes of dropped tables should be dropped before the table
/// is dropped.
fn should_drop_indexes_from_dropped_tables(&self) -> bool {
false
}
/// Whether the foreign keys of dropped tables should be dropped before the table
/// is dropped.
fn should_drop_foreign_keys_from_dropped_tables(&self) -> bool {
true
}
/// Whether to skip diffing JSON defaults.
fn should_ignore_json_defaults(&self) -> bool {
false
}
/// Whether `AddForeignKey` steps should be generated for created tables.
fn should_push_foreign_keys_from_created_tables(&self) -> bool {
true
}
/// Whether indexes matching a foreign key should be skipped.
fn should_skip_fk_indexes(&self) -> bool {
false
}
/// Whether a specific index should *not* be produced.
fn should_skip_index_for_new_table(&self, _index: IndexWalker<'_>) -> bool {
false
}
/// Whether the primary key should be recreated if the column part of it is
/// recreated.
fn should_recreate_the_primary_key_on_column_recreate(&self) -> bool {
false
}
/// Does the sql expression string match the provided byte array?
fn string_matches_bytes(&self, string: &str, bytes: &[u8]) -> bool {
string.as_bytes() == bytes
}
fn table_names_match(&self, names: MigrationPair<&str>) -> bool {
names.previous == names.next
}
/// Return the tables that cannot be migrated without being redefined. This
/// is currently useful only on SQLite.
fn set_tables_to_redefine(&self, _db: &mut DifferDatabase<'_>) {}
/// By implementing this method, the flavour signals the differ that
/// specific tables should be ignored. This is mostly for system tables.
fn table_should_be_ignored(&self, _table_name: &str) -> bool {
false
}
fn view_should_be_ignored(&self, _view_name: &str) -> bool {
false
}
/// Supports named Foreign Keys.
fn has_unnamed_foreign_keys(&self) -> bool {
false
}
}