Skip to content

Latest commit

 

History

History
262 lines (202 loc) · 6.39 KB

File metadata and controls

262 lines (202 loc) · 6.39 KB

SQL Parser 代码改进总结

改进内容

1. 添加辅助函数减少重复代码

之前的问题

代码中大量重复的反引号移除逻辑:

// ❌ 重复出现 20+ 次
column.name.to_string().trim_matches('`').to_string()
create_table.name.to_string().trim_matches('`').to_string()
ident.value.trim_matches('`').to_string()

改进后

// ✅ 统一的辅助函数
#[inline]
fn strip_backticks(s: &str) -> String {
    s.trim_matches('`').to_string()
}

#[inline]
fn ident_to_string<T: ToString>(ident: &T) -> String {
    strip_backticks(&ident.to_string())
}

// 使用
let table_name = ident_to_string(&create_table.name);
let column_name = ident_to_string(&column.name);

优势

  • ✅ 代码更简洁
  • ✅ 易于维护(修改一处即可)
  • ✅ 性能更好(#[inline] 优化)

2. 提取索引列名处理逻辑

之前的问题

parse_standalone_indexes 中有 20+ 行的列名提取逻辑,难以阅读和维护。

改进后

// ✅ 独立的函数
fn extract_index_columns(index_columns: &[sqlparser::ast::IndexColumn]) -> Vec<String> {
    index_columns
        .iter()
        .filter_map(|index_col| {
            match &index_col.column.expr {
                Expr::Identifier(ident) => Some(strip_backticks(&ident.value)),
                Expr::CompoundIdentifier(idents) => {
                    idents.last().map(|id| strip_backticks(&id.value))
                }
                _ => Some(strip_backticks(&index_col.column.to_string())),
            }
        })
        .collect()
}

// 使用
let columns = extract_index_columns(&create_index.columns);

优势

  • ✅ 逻辑清晰,职责单一
  • ✅ 可复用
  • ✅ 易于测试
  • ✅ 有详细的文档注释

3. 简化 parse_table_constraint

之前

// ❌ 冗长
let column_names: Vec<String> = columns.iter()
    .map(|col| col.to_string().trim_matches('`').to_string())
    .collect();

let index_name = name
    .as_ref()
    .map(|n| n.to_string().trim_matches('`').to_string())
    .unwrap_or_else(|| format!("unique_{}", column_names.join("_")));

改进后

// ✅ 简洁
let column_names: Vec<String> = columns.iter().map(ident_to_string).collect();
let index_name = name.as_ref().map(ident_to_string)
    .unwrap_or_else(|| format!("unique_{}", column_names.join("_")));

优势

  • ✅ 代码减少 50%
  • ✅ 更易读
  • ✅ 函数式风格

代码统计

改进前

  • 重复代码trim_matches('')` 出现 25+ 次
  • 长函数parse_standalone_indexes 约 80 行
  • 可读性:中等

改进后

  • 重复代码:0 次(全部使用辅助函数)
  • 长函数parse_standalone_indexes 约 50 行
  • 可读性:高
  • 新增辅助函数:2 个(strip_backticks, extract_index_columns

性能影响

#[inline] 优化

#[inline]
fn strip_backticks(s: &str) -> String {
    s.trim_matches('`').to_string()
}
  • ✅ 编译器会内联这个函数
  • ✅ 没有函数调用开销
  • ✅ 性能与直接调用相同

函数式编程

columns.iter().map(ident_to_string).collect()
  • ✅ 使用迭代器,惰性求值
  • ✅ 编译器优化良好
  • ✅ 性能与 for 循环相当

可维护性提升

1. 统一的接口

所有标识符转换都通过 ident_to_string

let table_name = ident_to_string(&create_table.name);
let column_name = ident_to_string(&column.name);
let index_name = ident_to_string(&index.name);

好处

  • 如果需要修改反引号处理逻辑,只需修改一处
  • 代码风格统一
  • 新手更容易理解

2. 清晰的职责分离

// 提取列名 - 专门的函数
fn extract_index_columns(...) -> Vec<String>

// 移除反引号 - 专门的函数
fn strip_backticks(s: &str) -> String

// 标识符转换 - 专门的函数
fn ident_to_string<T: ToString>(ident: &T) -> String

好处

  • 每个函数只做一件事
  • 易于单元测试
  • 易于文档化

3. 更好的文档

/// 从 IndexColumn 列表中提取列名
/// 
/// 处理三种情况:
/// 1. 简单列名:`column_name`
/// 2. 复合标识符:`table.column` (只取最后一部分)
/// 3. 复杂表达式:函数索引等 (使用 Display)
fn extract_index_columns(index_columns: &[sqlparser::ast::IndexColumn]) -> Vec<String>

好处

  • 清楚说明函数的用途
  • 列举了所有处理的情况
  • 新手可以快速理解

未来扩展

如果需要支持更多索引类型

只需修改 extract_index_columns 函数:

fn extract_index_columns(index_columns: &[IndexColumn]) -> Vec<String> {
    index_columns
        .iter()
        .filter_map(|index_col| {
            match &index_col.column.expr {
                Expr::Identifier(ident) => Some(strip_backticks(&ident.value)),
                Expr::CompoundIdentifier(idents) => {
                    idents.last().map(|id| strip_backticks(&id.value))
                }
                // 🆕 新增:支持函数索引
                Expr::Function(func) => {
                    Some(format!("FUNC({})", func.name))
                }
                // 🆕 新增:支持表达式索引
                Expr::BinaryOp { left, op, right } => {
                    Some(format!("EXPR({} {} {})", left, op, right))
                }
                _ => Some(strip_backticks(&index_col.column.to_string())),
            }
        })
        .collect()
}

如果需要支持其他数据库

只需修改 strip_backticks 函数:

fn strip_backticks(s: &str) -> String {
    s.trim_matches('`')  // MySQL
     .trim_matches('"')  // PostgreSQL
     .trim_matches('[')  // SQL Server
     .trim_matches(']')  // SQL Server
     .to_string()
}

总结

指标 改进前 改进后 提升
代码重复 高 (25+ 处) 低 (0 处) ✅ 100%
可读性 中等 ✅ 显著提升
可维护性 中等 ✅ 显著提升
性能 良好 良好 ✅ 无影响
代码行数 ~600 ~580 ✅ -3%
函数复杂度 ✅ 降低

核心改进

  1. ✅ 消除了所有重复的反引号处理代码
  2. ✅ 提取了可复用的辅助函数
  3. ✅ 提高了代码的可读性和可维护性
  4. ✅ 没有性能损失
  5. ✅ 为未来扩展打下良好基础

这些改进使代码更加专业、简洁、易维护,符合 Rust 的最佳实践。