1
0
mirror of https://github.com/nushell/nushell.git synced 2025-08-16 17:11:42 +02:00
Files
.cargo
.githooks
.github
assets
benches
clippy
crates
nu-cli
nu-cmd-base
nu-cmd-extra
nu-cmd-lang
nu-cmd-plugin
nu-color-config
nu-command
src
tests
commands
assignment
base
bytes
conversions
database
into_sqlite.rs
mod.rs
query_db.rs
date
debug
hash_
math
move_
network
path
platform
query
random
skip
str_
take
url
alias.rs
all.rs
any.rs
append.rs
break_.rs
cal.rs
cd.rs
chunk_by.rs
chunks.rs
compact.rs
complete.rs
config_env_default.rs
config_nu_default.rs
continue_.rs
debug_info.rs
def.rs
default.rs
detect_columns.rs
do_.rs
drop.rs
du.rs
each.rs
echo.rs
empty.rs
error_make.rs
every.rs
exec.rs
export_def.rs
fill.rs
filter.rs
find.rs
first.rs
flatten.rs
for_.rs
format.rs
generate.rs
get.rs
glob.rs
griddle.rs
group_by.rs
headers.rs
help.rs
histogram.rs
ignore.rs
insert.rs
inspect.rs
interleave.rs
into_datetime.rs
into_filesize.rs
into_int.rs
join.rs
last.rs
length.rs
let_.rs
lines.rs
loop_.rs
ls.rs
match_.rs
merge.rs
merge_deep.rs
mktemp.rs
mod.rs
mut_.rs
nu_check.rs
open.rs
par_each.rs
parse.rs
prepend.rs
print.rs
range.rs
redirection.rs
reduce.rs
reject.rs
rename.rs
return_.rs
reverse.rs
rm.rs
roll.rs
rotate.rs
run_external.rs
save.rs
select.rs
semicolon.rs
seq.rs
seq_char.rs
seq_date.rs
sort.rs
sort_by.rs
source_env.rs
split_column.rs
split_row.rs
table.rs
tee.rs
terminal.rs
to_text.rs
transpose.rs
try_.rs
ucp.rs
ulimit.rs
umkdir.rs
uname.rs
uniq.rs
uniq_by.rs
update.rs
upsert.rs
use_.rs
utouch.rs
where_.rs
which.rs
while_.rs
window.rs
with_env.rs
wrap.rs
zip.rs
format_conversions
main.rs
sort_utils.rs
Cargo.toml
LICENSE
README.md
nu-derive-value
nu-engine
nu-explore
nu-glob
nu-json
nu-lsp
nu-parser
nu-path
nu-plugin
nu-plugin-core
nu-plugin-engine
nu-plugin-protocol
nu-plugin-test-support
nu-pretty-hex
nu-protocol
nu-std
nu-system
nu-table
nu-term-grid
nu-test-support
nu-utils
nu_plugin_custom_values
nu_plugin_example
nu_plugin_formats
nu_plugin_gstat
nu_plugin_inc
nu_plugin_nu_example
nu_plugin_polars
nu_plugin_python
nu_plugin_query
nu_plugin_stress_internals
nuon
README.md
devdocs
docker
scripts
src
tests
wix
.gitattributes
.gitignore
CITATION.cff
CODE_OF_CONDUCT.md
CONTRIBUTING.md
Cargo.lock
Cargo.toml
Cross.toml
LICENSE
README.md
SECURITY.md
rust-toolchain.toml
toolkit.nu
typos.toml
nushell/crates/nu-command/tests/commands/database/query_db.rs
Doru d1a8992590 Initial --params implementation ()
# Description
This PR adds a `--params` param to `query db`. This closes .

You can't combine both named and positional parameters, I think this
might be a limitation with rusqlite itself. I tried using named
parameters with indices like `{ ':named': 123, '1': "positional" }` but
that always failed with a rusqlite error. On the flip side, the other
way around works: for something like `VALUES (:named, ?)`, you can treat
both as positional: `-p [hello 123]`.

This PR introduces some very gnarly code repetition in
`prepared_statement_to_nu_list`. I tried, I swear; the compiler wasn't
having any of it, it kept telling me to box my closures and then it said
that the reference lifetimes were incompatible in the match arms. I gave
up and put the mapping code in the match itself, but I'm still not
happy.

Another thing I'm unhappy about: I don't like how you have to put the
`:colon` in named parameters. I think nushell should insert it if it's
[missing](https://www.sqlite.org/lang_expr.html#parameters). But this is
the way [rusqlite
works](https://docs.rs/rusqlite/latest/rusqlite/trait.Params.html#example-named),
so for now, I'll let it be consistent. Just know that it's not really a
blocker, and it isn't a compatibility change to later make `{ colon: 123
}` work, without the quotes and `:`. This would require allocating and
turning our pretty little `&str` into a `String`, though

# User-Facing Changes
Less incentive to leave yourself open to SQL injection with statements
like `query db $"INSERT INTO x VALUES \($unsafe_user_input)"`.
Additionally, the `$""` syntax being annoying with parentheses plays in
our favor, making users even more likely to use ? with `--params`.

# Tests + Formatting
Hehe
2024-03-24 15:40:21 -05:00

116 lines
4.1 KiB
Rust

use nu_test_support::{nu, nu_repl_code, playground::Playground};
// Multiple nu! calls don't persist state, so we can't store it in a function
const DATABASE_INIT: &str = r#"stor open | query db "CREATE TABLE IF NOT EXISTS test_db (
name TEXT,
age INTEGER,
height REAL,
serious BOOLEAN,
created_at DATETIME,
largest_file INTEGER,
time_slept INTEGER,
null_field TEXT,
data BLOB
)""#;
#[test]
fn data_types() {
Playground::setup("empty", |_, _| {
let results = nu!(nu_repl_code(&[
DATABASE_INIT,
// Add row with our data types
r#"stor open
| query db "INSERT INTO test_db VALUES (
'nimurod',
20,
6.0,
true,
date('2024-03-23T00:15:24-03:00'),
72400000,
1000000,
NULL,
x'68656c6c6f'
)"
"#,
// Query our table with the row we just added to get its nushell types
r#"
stor open | query db "SELECT * FROM test_db" | first | values | each { describe } | str join "-"
"#
]));
// Assert data types match. Booleans are mapped to "numeric" due to internal SQLite representations:
// https://www.sqlite.org/datatype3.html
// They are simply 1 or 0 in practice, but the column could contain any valid SQLite value
assert_eq!(
results.out,
"string-int-float-int-string-int-int-nothing-binary"
);
});
}
#[test]
fn ordered_params() {
Playground::setup("empty", |_, _| {
let results = nu!(nu_repl_code(&[
DATABASE_INIT,
// Add row with our data types
r#"(stor open
| query db "INSERT INTO test_db VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
-p [ 'nimurod', 20, 6.0, true, ('2024-03-23T00:15:24-03:00' | into datetime), 72.4mb, 1ms, null, ("hello" | into binary) ]
)"#,
// Query our nu values and types
r#"
let values = (stor open | query db "SELECT * FROM test_db" | first | values);
($values | str join '-') + "_" + ($values | each { describe } | str join '-')
"#
]));
assert_eq!(
results.out,
"nimurod-20-6-1-2024-03-23 00:15:24-03:00-72400000-1000000--[104, 101, 108, 108, 111]_\
string-int-float-int-string-int-int-nothing-binary"
);
});
}
#[test]
fn named_params() {
Playground::setup("empty", |_, _| {
let results = nu!(nu_repl_code(&[
DATABASE_INIT,
// Add row with our data types. query db should support all possible named parameters
// @-prefixed, $-prefixed, and :-prefixed
// But :prefix is the "blessed" way to do it, and as such, the only one that's
// promoted to from a bare word `key: value` property in the record
// In practice, users should not use @param or $param
r#"(stor open
| query db "INSERT INTO test_db VALUES (:name, :age, @height, $serious, :created_at, :largest_file, :time_slept, :null_field, :data)"
-p {
name: 'nimurod',
':age': 20,
'@height': 6.0,
'$serious': true,
created_at: ('2024-03-23T00:15:24-03:00' | into datetime),
largest_file: 72.4mb,
time_slept: 1ms,
null_field: null,
data: ("hello" | into binary)
}
)"#,
// Query our nu values and types
r#"
let values = (stor open | query db "SELECT * FROM test_db" | first | values);
($values | str join '-') + "_" + ($values | each { describe } | str join '-')
"#
]));
assert_eq!(
results.out,
"nimurod-20-6-1-2024-03-23 00:15:24-03:00-72400000-1000000--[104, 101, 108, 108, 111]_\
string-int-float-int-string-int-int-nothing-binary"
);
});
}