「Rust 重写 sqlite」元数据操作命令

「这是我参与11月更文挑战的第 13 天,活动详情查看:2021最后一次更文挑战


区分命令

回到项目中,正如我上面提到的,第一件事是能够区分 MetaCommandSQLCommand。可以看到在 main.rs 通过调用 get_command_type(command: &String) 来处理这个问题,它返回一个 rep::CommandType 类型的枚举,有 rep::CommanType::SQLCommand(String)rep::CommanType::MetaCommand(String) 两种选项。这样我就可以很容易地区分这两种类型的输入,并对它们分别采取适当的行动:

fn main() -> rustyline::Result<()> {
    let _matches = App::new("Rust-SQLite")
                          .version(crate_version!())
                          .author(crate_authors!())
                          .about(crate_description!())
                          .get_matches();

    let config = get_config();
    let helper = REPLHelper::default();
    let mut repl = Editor::with_config(config);
    repl.set_helper(Some(helper));
		// 循环接收命令
    loop {
        let p = format!("rust-lite> ");
        repl.helper_mut()
            .expect("No helper found")
            .colored_prompt = format!("\x1b[1;32m{}\x1b[0m", p);
        // <http://bixense.com/clicolors/>

        let readline = repl.readline(&p);
        match readline {
            Ok(command) => {
                repl.add_history_entry(command.as_str());
                // Parsing repl::CommandType
                match get_command_type(&command.trim().to_owned()) {
                    CommandType::SQLCommand(_cmd) => {
                        // process_command -> {tokenizing, parsing and executing}
                        let _ = match process_command(&command) {
                            Ok(response) => println!("{}",response),
                            Err(err) => println!("An error occured: {}", err),
                        };
                    }
                    CommandType::MetaCommand(cmd) => {
                        // handle_meta_command parses and executes the MetaCommand
                        let _ = match handle_meta_command(cmd) {
                            Ok(response) => println!("{}",response),
                            Err(err) => println!("An error occured: {}", err),
                        };
                    }
                }
            }
            Err(ReadlineError::Interrupted) => {
                break;
            }
            Err(ReadlineError::Eof) => {
                break;
            }
            Err(err) => {
                println!("An error occured: {:?}", err);
                break;
            }
        }
    }

    Ok(())
复制代码

Meta Commands

先看看 meta_command:

首先是枚举类型的定义,为了改善用户体验,我添加了一个 Unknown 选项,以匹配任何尚未定义的MetaCommands

之后,我们有一个实现 fmt::Display trait的block,它帮助我们定义自定义类型如何被输出到终端上。例如,我们想在 println! 中使用它们。

然后在后面,你会看到另一个 impl block,里面有一个 fn new(),作为我们的 MetaCommand 类型的构造函数。我这么说是因为Rust不是一种面向对象的语言,所以 fn new() 并不像Java等语言中的构造函数,事实上,你可以随心所欲地调用它而不是new。

#[derive(Debug, PartialEq)]
pub enum MetaCommand {
    Exit,
    Help,
    Open(String),
    Unknown,
}

// 负责将类型翻译成格式化文本
impl fmt::Display for MetaCommand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            MetaCommand::Exit => f.write_str(".exit"),
            MetaCommand::Help => f.write_str(".help"),
            MetaCommand::Open(_) => f.write_str(".open"),
            MetaCommand::Unknown => f.write_str("Unknown command"),
        }
    }
}

impl MetaCommand {
    pub fn new(command: String) -> MetaCommand {
        let args: Vec<&str> = command.split_whitespace().collect();
        let cmd = args[0].to_owned();
        match cmd.as_ref() {
            ".exit" => MetaCommand::Exit,
            ".help" => MetaCommand::Help,
            ".open" => MetaCommand::Open(command),
            _ => MetaCommand::Unknown,
        }
    }
}
// 处理
pub fn handle_meta_command(command: MetaCommand) -> Result<String> {
    match command {
        MetaCommand::Exit => std::process::exit(0),
        MetaCommand::Help => {
            Ok(format!("{}{}{}{}",
                            ".help - Display this message\n",
                            ".open <FILENAME> - Reopens a persistent database.\n",
                            ".ast <QUERY> - Show the AST for QUERY.\n",
                            ".exit - Quits this application"))
        },
        MetaCommand::Open(args) => Ok(format!("To be implemented: {}", args)),
        MetaCommand::Unknown => Err(SQLRiteError::UnknownCommand(format!("Unknown command or invalid arguments. Enter '.help'"))),
    }
}
复制代码

猜你喜欢

转载自juejin.im/post/7032611361481818149
今日推荐