fix(app): preserve object source formatting

This commit is contained in:
LRcoding authored and GitHub committed 2026-07-02 20:21:22 +08:00
1 parent 4c96aa6e40
commit f16454a403
3 files changed
+119 -3

No files matched your search

+104
View File
@@ -137,6 +137,13 @@ pub fn build_executable_object_source_statements(input: EditableObjectSourceSqlI
| DatabaseType::Questdb
) && input.object_type == ObjectSourceKind::View
{
if let Some(sql) = executable_postgres_view_ddl(source) {
return Ok(vec![sql]);
}
if source_starts_with_alter(source) {
// ALTER VIEW is already executable DDL, but it is not a view body.
return Ok(vec![ensure_semicolon(source)]);
}
return Ok(vec![format!(
"CREATE OR REPLACE VIEW {} AS\n{}",
postgres_qualified_name(input.schema.as_deref(), &input.name),
@@ -164,6 +171,19 @@ pub fn build_executable_object_source_sql(input: EditableObjectSourceSqlInput) -
/// statements.
pub fn build_editable_object_source(input: EditableObjectSourceSqlInput) -> String {
let source = input.source.clone();
if matches!(
input.database_type,
DatabaseType::Postgres
| DatabaseType::Gaussdb
| DatabaseType::Kwdb
| DatabaseType::OpenGauss
| DatabaseType::Questdb
) && input.object_type == ObjectSourceKind::View
&& source_starts_with_create_or_alter(&source)
{
// Some providers return full view DDL instead of a bare SELECT body.
return ensure_semicolon(source.trim());
}
match build_executable_object_source_statements(input) {
Ok(statements) => statements.into_iter().next().unwrap_or_default(),
Err(_) => ensure_semicolon(source.trim()),
@@ -285,6 +305,29 @@ fn ensure_semicolon(sql: &str) -> String {
}
}
fn source_starts_with_create_or_alter(source: &str) -> bool {
Regex::new(r"(?i)^\s*(?:CREATE|ALTER)\s+").unwrap().is_match(source)
}
fn source_starts_with_alter(source: &str) -> bool {
Regex::new(r"(?i)^\s*ALTER\s+").unwrap().is_match(source)
}
fn executable_postgres_view_ddl(source: &str) -> Option<String> {
let trimmed = source.trim();
if Regex::new(r"(?i)^CREATE\s+OR\s+REPLACE\s+").unwrap().is_match(trimmed) {
return Some(ensure_semicolon(trimmed));
}
let create_view = Regex::new(r"(?i)^CREATE\s+((?:(?:TEMP|TEMPORARY)\s+)?(?:RECURSIVE\s+)?VIEW\s+)").unwrap();
if create_view.is_match(trimmed) {
let replaced = create_view.replace(trimmed, "CREATE OR REPLACE $1");
return Some(ensure_semicolon(replaced.as_ref()));
}
None
}
fn postgres_qualified_name(schema: Option<&str>, name: &str) -> String {
schema
.into_iter()
@@ -547,6 +590,67 @@ mod tests {
);
}
#[test]
fn postgres_view_create_source_opens_without_rewrapping_or_reformatting() {
let source = "CREATE OR REPLACE VIEW public.active_users AS SELECT id, name FROM users WHERE active = true";
let sql = build_editable_object_source(EditableObjectSourceSqlInput {
database_type: DatabaseType::Postgres,
object_type: ObjectSourceKind::View,
schema: Some("public".to_string()),
name: "active_users".to_string(),
source: source.to_string(),
});
assert_eq!(sql, format!("{source};"));
}
#[test]
fn postgres_view_create_source_saves_as_create_or_replace_view() {
let sql = build_executable_object_source_sql(EditableObjectSourceSqlInput {
database_type: DatabaseType::Postgres,
object_type: ObjectSourceKind::View,
schema: Some("public".to_string()),
name: "active_users".to_string(),
source: "CREATE VIEW public.active_users AS SELECT id, name FROM users WHERE active = true".to_string(),
})
.unwrap();
assert_eq!(
sql,
"CREATE OR REPLACE VIEW public.active_users AS SELECT id, name FROM users WHERE active = true;"
);
}
#[test]
fn postgres_view_create_or_replace_source_saves_without_rewrapping() {
let source = "CREATE OR REPLACE VIEW public.active_users AS SELECT id, name FROM users WHERE active = true";
let sql = build_executable_object_source_sql(EditableObjectSourceSqlInput {
database_type: DatabaseType::Postgres,
object_type: ObjectSourceKind::View,
schema: Some("public".to_string()),
name: "active_users".to_string(),
source: source.to_string(),
})
.unwrap();
assert_eq!(sql, format!("{source};"));
}
#[test]
fn postgres_view_alter_source_saves_without_body_wrapping() {
let source = "ALTER VIEW public.active_users SET (security_barrier = true)";
let sql = build_executable_object_source_sql(EditableObjectSourceSqlInput {
database_type: DatabaseType::Postgres,
object_type: ObjectSourceKind::View,
schema: Some("public".to_string()),
name: "active_users".to_string(),
source: source.to_string(),
})
.unwrap();
assert_eq!(sql, format!("{source};"));
}
#[test]
fn postgres_compatible_view_body_opens_as_create_or_replace_view() {
for database_type in [DatabaseType::OpenGauss, DatabaseType::Kwdb] {