This is an automated email from the ASF dual-hosted git repository.

jiayuliu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-datafusion.git


The following commit(s) were added to refs/heads/master by this push:
     new 32528f1  add editor support for datafusion cli with validation (#1251)
32528f1 is described below

commit 32528f1e7f645d45e9059b7ab60d98bef8b603ec
Author: Jiayu Liu <[email protected]>
AuthorDate: Sat Nov 6 20:04:31 2021 +0800

    add editor support for datafusion cli with validation (#1251)
---
 datafusion-cli/src/exec.rs   | 23 +++++---------
 datafusion-cli/src/helper.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++
 datafusion-cli/src/lib.rs    |  1 +
 3 files changed, 81 insertions(+), 15 deletions(-)

diff --git a/datafusion-cli/src/exec.rs b/datafusion-cli/src/exec.rs
index 349c2d3..103dd72 100644
--- a/datafusion-cli/src/exec.rs
+++ b/datafusion-cli/src/exec.rs
@@ -20,12 +20,14 @@
 use crate::{
     command::Command,
     context::Context,
+    helper::CliHelper,
     print_format::{all_print_formats, PrintFormat},
     print_options::PrintOptions,
 };
 use datafusion::arrow::record_batch::RecordBatch;
 use datafusion::arrow::util::pretty;
 use datafusion::error::{DataFusionError, Result};
+use rustyline::config::Config;
 use rustyline::error::ReadlineError;
 use rustyline::Editor;
 use std::fs::File;
@@ -78,12 +80,12 @@ pub async fn exec_from_lines(
 
 /// run and execute SQL statements and commands against a context with the 
given print options
 pub async fn exec_from_repl(ctx: &mut Context, print_options: &PrintOptions) {
-    let mut rl = Editor::<()>::new();
+    let mut rl = Editor::<CliHelper>::new();
+    rl.set_helper(Some(CliHelper::default()));
     rl.load_history(".history").ok();
 
-    let mut query = "".to_owned();
     loop {
-        match rl.readline("> ") {
+        match rl.readline("❯ ") {
             Ok(line) if line.starts_with('\\') => {
                 rl.add_history_entry(line.trim_end());
                 if let Ok(cmd) = &line[1..].parse::<Command>() {
@@ -99,21 +101,12 @@ pub async fn exec_from_repl(ctx: &mut Context, 
print_options: &PrintOptions) {
                     eprintln!("'\\{}' is not a valid command", &line[1..]);
                 }
             }
-            Ok(line) if line.starts_with("--") => {
-                continue;
-            }
-            Ok(line) if line.trim_end().ends_with(';') => {
-                query.push_str(line.trim_end());
-                rl.add_history_entry(query.clone());
-                match exec_and_print(ctx, print_options, query).await {
+            Ok(line) => {
+                rl.add_history_entry(line.trim_end());
+                match exec_and_print(ctx, print_options, line).await {
                     Ok(_) => {}
                     Err(err) => eprintln!("{:?}", err),
                 }
-                query = "".to_owned();
-            }
-            Ok(line) => {
-                query.push_str(&line);
-                query.push('\n');
             }
             Err(ReadlineError::Interrupted) => {
                 println!("^C");
diff --git a/datafusion-cli/src/helper.rs b/datafusion-cli/src/helper.rs
new file mode 100644
index 0000000..ac417d2
--- /dev/null
+++ b/datafusion-cli/src/helper.rs
@@ -0,0 +1,72 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+//! Helper that helps with interactive editing, including multi-line parsing 
and validation,
+//! hinting and auto-completion, etc.
+
+use datafusion::sql::parser::DFParser;
+use rustyline::completion::Completer;
+use rustyline::error::ReadlineError;
+use rustyline::highlight::Highlighter;
+use rustyline::hint::Hinter;
+use rustyline::validate::ValidationContext;
+use rustyline::validate::ValidationResult;
+use rustyline::validate::Validator;
+use rustyline::Context;
+use rustyline::Helper;
+use rustyline::Result;
+
+#[derive(Default)]
+pub(crate) struct CliHelper {}
+
+impl Highlighter for CliHelper {}
+
+impl Hinter for CliHelper {
+    type Hint = String;
+}
+
+impl Completer for CliHelper {
+    type Candidate = String;
+}
+
+impl Validator for CliHelper {
+    fn validate(&self, ctx: &mut ValidationContext<'_>) -> 
Result<ValidationResult> {
+        let input = ctx.input().trim_end();
+        if let Some(sql) = input.strip_suffix(';') {
+            match DFParser::parse_sql(sql) {
+                Ok(statements) if statements.is_empty() => 
Ok(ValidationResult::Invalid(
+                    Some("  🤔 You entered an empty statement".to_string()),
+                )),
+                Ok(statements) if statements.len() > 1 => 
Ok(ValidationResult::Invalid(
+                    Some("  🤔 You entered more than one 
statement".to_string()),
+                )),
+                Ok(_statements) => Ok(ValidationResult::Valid(None)),
+                Err(err) => Ok(ValidationResult::Invalid(Some(format!(
+                    "  🤔 Invalid statement: {}",
+                    err
+                )))),
+            }
+        } else if input.starts_with('\\') {
+            // command
+            Ok(ValidationResult::Valid(None))
+        } else {
+            Ok(ValidationResult::Incomplete)
+        }
+    }
+}
+
+impl Helper for CliHelper {}
diff --git a/datafusion-cli/src/lib.rs b/datafusion-cli/src/lib.rs
index 89776f0..e9c6c25 100644
--- a/datafusion-cli/src/lib.rs
+++ b/datafusion-cli/src/lib.rs
@@ -22,5 +22,6 @@ pub const DATAFUSION_CLI_VERSION: &str = 
env!("CARGO_PKG_VERSION");
 pub mod command;
 pub mod context;
 pub mod exec;
+pub mod helper;
 pub mod print_format;
 pub mod print_options;

Reply via email to