mirror of
https://github.com/nushell/nushell.git
synced 2025-05-13 19:24:34 +00:00
# Description The meaning of the word usage is specific to describing how a command function is *used* and not a synonym for general description. Usage can be used to describe the SYNOPSIS or EXAMPLES sections of a man page where the permitted argument combinations are shown or example *uses* are given. Let's not confuse people and call it what it is a description. Our `help` command already creates its own *Usage* section based on the available arguments and doesn't refer to the description with usage. # User-Facing Changes `help commands` and `scope commands` will now use `description` or `extra_description` `usage`-> `description` `extra_usage` -> `extra_description` Breaking change in the plugin protocol: In the signature record communicated with the engine. `usage`-> `description` `extra_usage` -> `extra_description` The same rename also takes place for the methods on `SimplePluginCommand` and `PluginCommand` # Tests + Formatting - Updated plugin protocol specific changes # After Submitting - [ ] update plugin protocol doc
98 lines
3.1 KiB
Rust
98 lines
3.1 KiB
Rust
use crate::database::{values::sqlite::nu_value_to_params, SQLiteDatabase};
|
|
use nu_engine::command_prelude::*;
|
|
|
|
#[derive(Clone)]
|
|
pub struct QueryDb;
|
|
|
|
impl Command for QueryDb {
|
|
fn name(&self) -> &str {
|
|
"query db"
|
|
}
|
|
|
|
fn signature(&self) -> Signature {
|
|
Signature::build(self.name())
|
|
.input_output_types(vec![(Type::Any, Type::Any)])
|
|
.required(
|
|
"SQL",
|
|
SyntaxShape::String,
|
|
"SQL to execute against the database.",
|
|
)
|
|
.named(
|
|
"params",
|
|
// TODO: Use SyntaxShape::OneOf with Records and Lists, when Lists no longer break inside OneOf
|
|
SyntaxShape::Any,
|
|
"List of parameters for the SQL statement",
|
|
Some('p'),
|
|
)
|
|
.category(Category::Database)
|
|
}
|
|
|
|
fn description(&self) -> &str {
|
|
"Query a database using SQL."
|
|
}
|
|
|
|
fn examples(&self) -> Vec<Example> {
|
|
vec![
|
|
Example {
|
|
description: "Execute SQL against a SQLite database",
|
|
example: r#"open foo.db | query db "SELECT * FROM Bar""#,
|
|
result: None,
|
|
},
|
|
Example {
|
|
description: "Execute a SQL statement with parameters",
|
|
example: r#"stor create -t my_table -c { first: str, second: int }
|
|
stor open | query db "INSERT INTO my_table VALUES (?, ?)" -p [hello 123]"#,
|
|
result: None,
|
|
},
|
|
Example {
|
|
description: "Execute a SQL statement with named parameters",
|
|
example: r#"stor create -t my_table -c { first: str, second: int }
|
|
stor insert -t my_table -d { first: 'hello', second: '123' }
|
|
stor open | query db "SELECT * FROM my_table WHERE second = :search_second" -p { search_second: 123 }"#,
|
|
result: Some(Value::test_list(vec![Value::test_record(record! {
|
|
"first" => Value::test_string("hello"),
|
|
"second" => Value::test_int(123)
|
|
})])),
|
|
},
|
|
]
|
|
}
|
|
|
|
fn search_terms(&self) -> Vec<&str> {
|
|
vec!["database", "SQLite"]
|
|
}
|
|
|
|
fn run(
|
|
&self,
|
|
engine_state: &EngineState,
|
|
stack: &mut Stack,
|
|
call: &Call,
|
|
input: PipelineData,
|
|
) -> Result<PipelineData, ShellError> {
|
|
let sql: Spanned<String> = call.req(engine_state, stack, 0)?;
|
|
let params_value: Value = call
|
|
.get_flag(engine_state, stack, "params")?
|
|
.unwrap_or_else(|| Value::nothing(Span::unknown()));
|
|
|
|
let params = nu_value_to_params(params_value)?;
|
|
|
|
let db = SQLiteDatabase::try_from_pipeline(input, call.head)?;
|
|
db.query(&sql, params, call.head)
|
|
.map(IntoPipelineData::into_pipeline_data)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use crate::{StorCreate, StorInsert, StorOpen};
|
|
|
|
use super::*;
|
|
|
|
#[ignore = "stor db does not persist changes between pipelines"]
|
|
#[test]
|
|
fn test_examples() {
|
|
use crate::test_examples_with_commands;
|
|
|
|
test_examples_with_commands(QueryDb {}, &[&StorOpen, &StorCreate, &StorInsert])
|
|
}
|
|
}
|