feat(schema-diff): select fields and indexes for synchronization
This commit is contained in:
1 parent
d8bc5153d2
commit
726f86e24c
32 files changed
+1185
-413
No files matched your search
@@ -397,6 +397,17 @@ pub struct SchemaDiffPreparation {
|
||||
pub dependency_graph: Option<DependencyGraph>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SchemaSyncSqlPlan {
|
||||
pub sync_sql: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub rollback_sync_sql: Option<String>,
|
||||
pub rollback_completeness: RollbackCompleteness,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub missing_rollback_objects: Vec<MissingRollbackObject>,
|
||||
}
|
||||
|
||||
fn default_rollback_complete() -> RollbackCompleteness {
|
||||
RollbackCompleteness::Complete
|
||||
}
|
||||
@@ -3839,6 +3850,50 @@ pub fn generate_schema_sync_sql(
|
||||
.0
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn generate_schema_sync_sql_plan(
|
||||
diffs: &[TableDiff],
|
||||
function_diffs: &[FunctionDiff],
|
||||
sequence_diffs: &[SequenceDiff],
|
||||
rule_diffs: &[RuleDiff],
|
||||
owner_diffs: &[OwnerDiff],
|
||||
db_type: DatabaseType,
|
||||
schema: Option<&str>,
|
||||
cascade_delete: bool,
|
||||
source_dialect: Option<DialectKind>,
|
||||
field_mappings: &[FieldMapping],
|
||||
enable_rollback: bool,
|
||||
) -> SchemaSyncSqlPlan {
|
||||
let (sync_sql, _) = generate_schema_sync_sql_inner(
|
||||
diffs,
|
||||
function_diffs,
|
||||
sequence_diffs,
|
||||
rule_diffs,
|
||||
owner_diffs,
|
||||
db_type,
|
||||
schema,
|
||||
cascade_delete,
|
||||
source_dialect,
|
||||
field_mappings,
|
||||
);
|
||||
|
||||
let (rollback_sync_sql, missing_rollback_objects) = if enable_rollback {
|
||||
let dependency_graph = DependencyGraph { nodes: HashMap::new(), topological_order: Vec::new() };
|
||||
let rollback_graph = RollbackGraph::from_forward_diffs(diffs, &[], &dependency_graph);
|
||||
let (sql, missing) = generate_rollback_sync_sql_with_missing(&rollback_graph, db_type, schema, cascade_delete);
|
||||
(Some(sql), missing)
|
||||
} else {
|
||||
(None, Vec::new())
|
||||
};
|
||||
let rollback_completeness = if missing_rollback_objects.is_empty() {
|
||||
RollbackCompleteness::Complete
|
||||
} else {
|
||||
RollbackCompleteness::Incomplete
|
||||
};
|
||||
|
||||
SchemaSyncSqlPlan { sync_sql, rollback_sync_sql, rollback_completeness, missing_rollback_objects }
|
||||
}
|
||||
|
||||
fn generate_schema_sync_sql_inner(
|
||||
diffs: &[TableDiff],
|
||||
function_diffs: &[FunctionDiff],
|
||||
@@ -5952,6 +6007,43 @@ mod tests {
|
||||
assert!(!table_sync_sql.contains("CREATE TABLE"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn schema_sync_plan_builds_matching_forward_and_rollback_sql_for_selected_children() {
|
||||
let selected_diff = TableDiff {
|
||||
diff_type: "modified".to_string(),
|
||||
object_type: Some("table".to_string()),
|
||||
name: "users".to_string(),
|
||||
columns: Some(vec![ColumnDiff {
|
||||
diff_type: "added".to_string(),
|
||||
name: "nickname".to_string(),
|
||||
source: Some(column("nickname", "varchar(64)", None)),
|
||||
target: None,
|
||||
changes: Vec::new(),
|
||||
add_position: None,
|
||||
}]),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let plan = generate_schema_sync_sql_plan(
|
||||
&[selected_diff],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
DatabaseType::Mysql,
|
||||
Some("shop"),
|
||||
false,
|
||||
None,
|
||||
&[],
|
||||
true,
|
||||
);
|
||||
|
||||
assert!(plan.sync_sql.contains("ADD COLUMN `nickname`"), "{}", plan.sync_sql);
|
||||
let rollback = plan.rollback_sync_sql.expect("rollback SQL");
|
||||
assert!(rollback.contains("DROP COLUMN `nickname`"), "{rollback}");
|
||||
assert_eq!(plan.rollback_completeness, RollbackCompleteness::Complete);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn qualifies_generated_schema_sync_sql_with_target_schema() {
|
||||
let diffs = vec![TableDiff {
|
||||
|
||||
@@ -448,6 +448,7 @@ async fn main() {
|
||||
.route("/dialect/data-types", get(routes::dialect::list_data_types))
|
||||
.route("/schema-diff/prepare", post(routes::schema_diff::prepare_schema_diff))
|
||||
.route("/schema-diff/generate-sync-sql", post(routes::schema_diff::generate_schema_sync_sql))
|
||||
.route("/schema-diff/generate-sync-plan", post(routes::schema_diff::generate_schema_sync_plan))
|
||||
.route(
|
||||
"/schema/cache",
|
||||
post(routes::schema_cache::save_schema_cache).get(routes::schema_cache::load_schema_cache),
|
||||
|
||||
@@ -14,6 +14,25 @@ pub struct GenerateSchemaSyncSqlRequest {
|
||||
pub cascade_delete: Option<bool>,
|
||||
pub source_dialect: Option<String>,
|
||||
pub field_mappings: Option<Vec<dbx_core::schema_diff::FieldMapping>>,
|
||||
pub enable_rollback: Option<bool>,
|
||||
}
|
||||
|
||||
pub async fn generate_schema_sync_plan(
|
||||
Json(req): Json<GenerateSchemaSyncSqlRequest>,
|
||||
) -> Json<dbx_core::schema_diff::SchemaSyncSqlPlan> {
|
||||
Json(dbx_core::schema_diff::generate_schema_sync_sql_plan(
|
||||
&req.diffs,
|
||||
req.function_diffs.as_deref().unwrap_or_default(),
|
||||
req.sequence_diffs.as_deref().unwrap_or_default(),
|
||||
req.rule_diffs.as_deref().unwrap_or_default(),
|
||||
req.owner_diffs.as_deref().unwrap_or_default(),
|
||||
req.database_type,
|
||||
req.target_schema.as_deref(),
|
||||
req.cascade_delete.unwrap_or(false),
|
||||
req.source_dialect.as_deref().and_then(dbx_core::sql_dialect::descriptor::DialectKind::from_label),
|
||||
req.field_mappings.as_deref().unwrap_or(&[]),
|
||||
req.enable_rollback.unwrap_or(false),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn prepare_schema_diff(
|
||||
|
||||
Reference in new issue
Block a user