feat(transfer): add tree-based object selection
This commit is contained in:
1 parent
fb7b2878fd
commit
473ef910b6
28 files changed
+5395
-205
No files matched your search
@@ -2798,6 +2798,14 @@ fn wants_routine_objects(object_types: Option<&[String]>) -> bool {
|
||||
requested_object_type(object_types, "PROCEDURE") || requested_object_type(object_types, "FUNCTION")
|
||||
}
|
||||
|
||||
fn wants_trigger_objects(object_types: Option<&[String]>) -> bool {
|
||||
requested_object_type(object_types, "TRIGGER")
|
||||
}
|
||||
|
||||
fn wants_event_objects(object_types: Option<&[String]>) -> bool {
|
||||
requested_object_type(object_types, "EVENT")
|
||||
}
|
||||
|
||||
fn sql_pagination(limit: Option<usize>, offset: Option<usize>) -> String {
|
||||
limit.map_or_else(String::new, |limit| format!(" LIMIT {limit} OFFSET {}", offset.unwrap_or(0)))
|
||||
}
|
||||
@@ -2888,6 +2896,32 @@ fn row_to_object(row: &mysql_async::Row, database: &str) -> ObjectInfo {
|
||||
}
|
||||
}
|
||||
|
||||
fn list_triggers_objects_sql(database: &str) -> String {
|
||||
format!(
|
||||
"SELECT TRIGGER_NAME AS object_name, 'TRIGGER' AS object_type, NULL AS object_comment, \
|
||||
CREATED AS created_at, NULL AS updated_at, \
|
||||
TRIGGER_SCHEMA AS parent_schema, EVENT_OBJECT_TABLE AS parent_name, \
|
||||
5 AS sort_order \
|
||||
FROM information_schema.TRIGGERS \
|
||||
WHERE TRIGGER_SCHEMA = {} \
|
||||
ORDER BY object_name",
|
||||
quote_value(database)
|
||||
)
|
||||
}
|
||||
|
||||
fn list_events_objects_sql(database: &str) -> String {
|
||||
format!(
|
||||
"SELECT EVENT_NAME AS object_name, 'EVENT' AS object_type, NULL AS object_comment, \
|
||||
CREATED AS created_at, LAST_ALTERED AS updated_at, \
|
||||
EVENT_SCHEMA AS parent_schema, NULL AS parent_name, \
|
||||
6 AS sort_order \
|
||||
FROM information_schema.EVENTS \
|
||||
WHERE EVENT_SCHEMA = {} \
|
||||
ORDER BY object_name",
|
||||
quote_value(database)
|
||||
)
|
||||
}
|
||||
|
||||
pub struct PagedObjectList {
|
||||
pub objects: Vec<ObjectInfo>,
|
||||
pub paging_applied: bool,
|
||||
@@ -2985,6 +3019,40 @@ pub async fn list_objects(
|
||||
}
|
||||
}
|
||||
|
||||
if wants_trigger_objects(object_types) {
|
||||
let triggers_sql = list_triggers_objects_sql(database);
|
||||
match conn.query_iter(&triggers_sql).await {
|
||||
Ok(result) => match result.collect_and_drop::<mysql_async::Row>().await {
|
||||
Ok(trigger_rows) => {
|
||||
objects.extend(trigger_rows.iter().map(|row| row_to_object(row, database)));
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("Skipping triggers for database `{}` in object browser: {}", database, e);
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::warn!("Skipping triggers for database `{}` in object browser: {}", database, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if wants_event_objects(object_types) {
|
||||
let events_sql = list_events_objects_sql(database);
|
||||
match conn.query_iter(&events_sql).await {
|
||||
Ok(result) => match result.collect_and_drop::<mysql_async::Row>().await {
|
||||
Ok(event_rows) => {
|
||||
objects.extend(event_rows.iter().map(|row| row_to_object(row, database)));
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("Skipping events for database `{}` in object browser: {}", database, e);
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::warn!("Skipping events for database `{}` in object browser: {}", database, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(PagedObjectList { objects, paging_applied })
|
||||
}
|
||||
|
||||
@@ -5179,6 +5247,19 @@ mod tests {
|
||||
assert!(sql.contains("TRIGGER_SCHEMA = 'app'"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lists_triggers_and_events_via_information_schema() {
|
||||
let sql = list_triggers_objects_sql("shop");
|
||||
assert!(sql.contains("information_schema.TRIGGERS"));
|
||||
assert!(sql.contains("TRIGGER_SCHEMA = 'shop'"));
|
||||
let sql = list_events_objects_sql("shop");
|
||||
assert!(sql.contains("information_schema.EVENTS"));
|
||||
assert!(sql.contains("EVENT_SCHEMA = 'shop'"));
|
||||
assert!(wants_trigger_objects(Some(&["TRIGGER".to_string()])));
|
||||
assert!(!wants_trigger_objects(Some(&["TABLE".to_string()])));
|
||||
assert!(wants_event_objects(Some(&["EVENT".to_string()])));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mysql_completion_like_pattern_uses_prefix_by_default() {
|
||||
assert_eq!(mysql_completion_like_pattern("Temp", Some(&CompletionAssistantMatchMode::Prefix)), "Temp%");
|
||||
|
||||
+2106
-12
File diff suppressed because it is too large.
Load diff
@@ -218,6 +218,8 @@ async fn live_postgres_transfer_preserves_data_and_schema_objects() {
|
||||
target_catalog: None,
|
||||
tables: vec!["users".to_string(), "audit_logs".to_string(), "files".to_string()],
|
||||
create_table: true,
|
||||
content: dbx_core::transfer::TransferContent::default(),
|
||||
objects: Vec::new(),
|
||||
mode: TransferMode::Append,
|
||||
target_table_name_case: TransferTableNameCase::Preserve,
|
||||
ownership_policy: TransferOwnershipPolicy::Preserve,
|
||||
@@ -501,6 +503,8 @@ async fn live_postgres_transfer_skips_create_ddl_for_existing_target_table() {
|
||||
target_catalog: None,
|
||||
tables: vec!["items".to_string()],
|
||||
create_table: true,
|
||||
content: dbx_core::transfer::TransferContent::default(),
|
||||
objects: Vec::new(),
|
||||
mode: TransferMode::Append,
|
||||
target_table_name_case: TransferTableNameCase::Preserve,
|
||||
ownership_policy: TransferOwnershipPolicy::Preserve,
|
||||
|
||||
@@ -1361,6 +1361,8 @@ async fn live_sqlserver_transfer_table_skips_rowversion_insert_column() {
|
||||
target_catalog: None,
|
||||
tables: vec![source_table.clone()],
|
||||
create_table: true,
|
||||
content: dbx_core::transfer::TransferContent::default(),
|
||||
objects: Vec::new(),
|
||||
mode: dbx_core::transfer::TransferMode::Append,
|
||||
target_table_name_case: dbx_core::transfer::TransferTableNameCase::Upper,
|
||||
ownership_policy: dbx_core::transfer::TransferOwnershipPolicy::Preserve,
|
||||
|
||||
Reference in new issue
Block a user