mirror of
https://github.com/nushell/nushell.git
synced 2025-07-01 07:00:37 +02:00
Compare commits
78 Commits
Author | SHA1 | Date | |
---|---|---|---|
390d06d4e7 | |||
89acbda877 | |||
0d40d0438f | |||
1e8212a938 | |||
2da8310b11 | |||
c16d8f0d5f | |||
2ac5b0480a | |||
4e90b478b7 | |||
3a38fb94f0 | |||
c6f6dcb57c | |||
b80299eba7 | |||
a48616697a | |||
b82dccf0bd | |||
84caf8859f | |||
be7f35246e | |||
3917fda7ed | |||
3b357e5402 | |||
79da470239 | |||
37949e70e0 | |||
5d00ecef56 | |||
6dde231dde | |||
58fa2e51a2 | |||
cf0877bf72 | |||
a0db4ce747 | |||
6ee13126f7 | |||
1c15a4ed3a | |||
7aabc381a3 | |||
8c9dced71b | |||
06d5a31301 | |||
ffbc0b0180 | |||
c0901ef707 | |||
d3e84daa49 | |||
228ede18cf | |||
c5a69271a2 | |||
dc9d939c83 | |||
32f0f94b46 | |||
a142d1a192 | |||
173d60d59d | |||
f2989bf704 | |||
575ddbd4ef | |||
ef9b72d360 | |||
25349a1eac | |||
99e4c44862 | |||
1345f97202 | |||
f02076daa8 | |||
533e04a60a | |||
13c152b00f | |||
f231a6df4a | |||
3c0bccb900 | |||
f43a65d7a7 | |||
0827ed143d | |||
4b84825dbf | |||
82ae06865c | |||
128ce6f9b7 | |||
44cbd88b55 | |||
7164929c61 | |||
848ff8453b | |||
f94ca6cfde | |||
fab3f8fd40 | |||
dbcfcdae89 | |||
08aa248c42 | |||
9f07bcc66f | |||
2caa44cea8 | |||
28c21121cf | |||
a17d46f200 | |||
6cc8402127 | |||
5f0ad1d6ad | |||
8d7bb9147e | |||
bc48b4553c | |||
28c07a5072 | |||
30c8dabeb4 | |||
8b368b6a4e | |||
8c0d60d0fb | |||
8b0a4ccf4c | |||
cfe4eff566 | |||
38f3957edf | |||
cb66d2bcad | |||
ff73623873 |
6
.github/pull_request_template.md
vendored
6
.github/pull_request_template.md
vendored
@ -4,6 +4,12 @@
|
|||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
|
|
||||||
|
Make sure you've done the following:
|
||||||
|
|
||||||
|
- [ ] Add tests that cover your changes, either in the command examples, the crate/tests folder, or in the /tests folder.
|
||||||
|
- [ ] Try to think about corner cases and various ways how your changes could break. Cover them with tests.
|
||||||
|
- [ ] If adding tests is not possible, please document in the PR body a minimal example with steps on how to reproduce so one can verify your change works.
|
||||||
|
|
||||||
Make sure you've run and fixed any issues with these commands:
|
Make sure you've run and fixed any issues with these commands:
|
||||||
|
|
||||||
- [ ] `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes)
|
- [ ] `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes)
|
||||||
|
4
.github/workflows/release-pkg.nu
vendored
4
.github/workflows/release-pkg.nu
vendored
@ -102,8 +102,8 @@ if $os in ['ubuntu-latest', 'macos-latest'] {
|
|||||||
let releaseStem = $'($bin)-($version)-($target)'
|
let releaseStem = $'($bin)-($version)-($target)'
|
||||||
|
|
||||||
$'(char nl)Download less related stuffs...'; hr-line
|
$'(char nl)Download less related stuffs...'; hr-line
|
||||||
curl https://github.com/jftuga/less-Windows/releases/download/less-v590/less.exe -o $'($dist)\less.exe'
|
aria2c https://github.com/jftuga/less-Windows/releases/download/less-v590/less.exe -o less.exe
|
||||||
curl https://raw.githubusercontent.com/jftuga/less-Windows/master/LICENSE -o $'($dist)\LICENSE-for-less.txt'
|
aria2c https://raw.githubusercontent.com/jftuga/less-Windows/master/LICENSE -o LICENSE-for-less.txt
|
||||||
|
|
||||||
# Create Windows msi release package
|
# Create Windows msi release package
|
||||||
if (get-env _EXTRA_) == 'msi' {
|
if (get-env _EXTRA_) == 'msi' {
|
||||||
|
4
.github/workflows/winget-submission.yml
vendored
4
.github/workflows/winget-submission.yml
vendored
@ -1,4 +1,4 @@
|
|||||||
name: Submit Nushell package to Windows Package Manager Community Repository
|
name: Submit Nushell package to Windows Package Manager Community Repository
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@ -15,5 +15,5 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
|
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
|
||||||
$github = Get-Content '${{ github.event_path }}' | ConvertFrom-Json
|
$github = Get-Content '${{ github.event_path }}' | ConvertFrom-Json
|
||||||
$installerUrl = $github.release.assets | Where-Object -Property name -match 'windows.msi' | Select -ExpandProperty browser_download_url -First 1
|
$installerUrl = $github.release.assets | Where-Object -Property name -match 'windows-msvc.msi' | Select -ExpandProperty browser_download_url -First 1
|
||||||
.\wingetcreate.exe update Nushell.Nushell -s -v $github.release.tag_name -u $installerUrl -t ${{ secrets.NUSHELL_PAT }}
|
.\wingetcreate.exe update Nushell.Nushell -s -v $github.release.tag_name -u $installerUrl -t ${{ secrets.NUSHELL_PAT }}
|
||||||
|
136
Cargo.lock
generated
136
Cargo.lock
generated
@ -80,9 +80,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ansi-str"
|
name = "ansi-str"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90cb0ceb8c444d026166795e474e9dfe54b443bdc07cc21bd6c5073f5e637482"
|
checksum = "e04d04a41a1463228d6eed971b9cdadd86b5577c69c09fd2379c57fe5e159071"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi-parser",
|
"ansi-parser",
|
||||||
]
|
]
|
||||||
@ -131,9 +131,9 @@ checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrow-format"
|
name = "arrow-format"
|
||||||
version = "0.4.0"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2333f8ccf0d597ba779863c57a0b61f635721187fb2fdeabae92691d7d582fe5"
|
checksum = "216249afef413d7e9e9b4b543e73b3e371ace3a812380af98f1c871521572cdd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"planus",
|
"planus",
|
||||||
"serde",
|
"serde",
|
||||||
@ -141,26 +141,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrow2"
|
name = "arrow2"
|
||||||
version = "0.11.2"
|
version = "0.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b040061368d1314b0fd8b8f1fde0671eba1afc63a1c61a4dafaf2d4fc10c96f9"
|
checksum = "5feafd6df4e3f577529e6aa2b9b7cdb3c9fe8e8f66ebc8dc29abbe71a7e968f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow-format",
|
"arrow-format",
|
||||||
"base64",
|
"base64",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"chrono",
|
"chrono",
|
||||||
"csv-core",
|
|
||||||
"either",
|
"either",
|
||||||
"fallible-streaming-iterator",
|
"fallible-streaming-iterator",
|
||||||
"futures",
|
"futures",
|
||||||
"hash_hasher",
|
"hash_hasher",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"json-deserializer",
|
||||||
"lexical-core",
|
"lexical-core",
|
||||||
"multiversion",
|
"multiversion",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"parquet2",
|
"parquet2",
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"simdutf8",
|
"simdutf8",
|
||||||
"streaming-iterator",
|
"streaming-iterator",
|
||||||
"strength_reduce",
|
"strength_reduce",
|
||||||
@ -1875,6 +1873,12 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "json-deserializer"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "47631885425c482fcf2dc4b182fc973c3c5b81a8f43a028055559bd24cccfa6e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kernel32-sys"
|
name = "kernel32-sys"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@ -2199,13 +2203,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miette"
|
name = "miette"
|
||||||
version = "4.7.1"
|
version = "5.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c90329e44f9208b55f45711f9558cec15d7ef8295cc65ecd6d4188ae8edc58c"
|
checksum = "6ec753a43fd71bb5f28751c9ec17fbe89d6d26ca8282d1e1f82f5ac3dbd5581e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atty",
|
"atty",
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"miette-derive 4.7.1",
|
"miette-derive 5.1.0",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"owo-colors",
|
"owo-colors",
|
||||||
"supports-color",
|
"supports-color",
|
||||||
@ -2230,9 +2234,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miette-derive"
|
name = "miette-derive"
|
||||||
version = "4.7.1"
|
version = "5.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6b5bc45b761bcf1b5e6e6c4128cd93b84c218721a8d9b894aa0aff4ed180174c"
|
checksum = "fdfc33ea15c5446600f91d319299dd40301614afff7143cdfa9bf4c09da3ca64"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -2470,7 +2474,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu"
|
name = "nu"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
"chrono",
|
"chrono",
|
||||||
@ -2480,7 +2484,7 @@ dependencies = [
|
|||||||
"is_executable",
|
"is_executable",
|
||||||
"itertools",
|
"itertools",
|
||||||
"log",
|
"log",
|
||||||
"miette 4.7.1",
|
"miette 5.1.0",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
"nu-cli",
|
"nu-cli",
|
||||||
"nu-color-config",
|
"nu-color-config",
|
||||||
@ -2521,14 +2525,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-cli"
|
name = "nu-cli"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"fuzzy-matcher",
|
"fuzzy-matcher",
|
||||||
"is_executable",
|
"is_executable",
|
||||||
"log",
|
"log",
|
||||||
"miette 4.7.1",
|
"miette 5.1.0",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
"nu-color-config",
|
"nu-color-config",
|
||||||
"nu-command",
|
"nu-command",
|
||||||
@ -2545,7 +2549,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-color-config"
|
name = "nu-color-config"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
"nu-json",
|
"nu-json",
|
||||||
@ -2556,11 +2560,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-command"
|
name = "nu-command"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"Inflector",
|
"Inflector",
|
||||||
"alphanumeric-sort",
|
"alphanumeric-sort",
|
||||||
"base64",
|
"base64",
|
||||||
|
"byteorder",
|
||||||
"bytesize",
|
"bytesize",
|
||||||
"calamine",
|
"calamine",
|
||||||
"chrono",
|
"chrono",
|
||||||
@ -2617,6 +2622,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"roxmltree",
|
"roxmltree",
|
||||||
|
"rstest",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
"rust-embed",
|
"rust-embed",
|
||||||
"serde",
|
"serde",
|
||||||
@ -2625,6 +2631,7 @@ dependencies = [
|
|||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"sha2 0.10.2",
|
"sha2 0.10.2",
|
||||||
"shadow-rs",
|
"shadow-rs",
|
||||||
|
"signal-hook",
|
||||||
"sqlparser",
|
"sqlparser",
|
||||||
"strip-ansi-escapes",
|
"strip-ansi-escapes",
|
||||||
"sysinfo 0.23.13",
|
"sysinfo 0.23.13",
|
||||||
@ -2645,7 +2652,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-engine"
|
name = "nu-engine"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"nu-glob",
|
"nu-glob",
|
||||||
@ -2657,7 +2664,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-glob"
|
name = "nu-glob"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"doc-comment",
|
"doc-comment",
|
||||||
"tempdir",
|
"tempdir",
|
||||||
@ -2665,7 +2672,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-json"
|
name = "nu-json"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"linked-hash-map",
|
"linked-hash-map",
|
||||||
@ -2678,11 +2685,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-parser"
|
name = "nu-parser"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"itertools",
|
||||||
"log",
|
"log",
|
||||||
"miette 4.7.1",
|
"miette 5.1.0",
|
||||||
"nu-path",
|
"nu-path",
|
||||||
"nu-plugin",
|
"nu-plugin",
|
||||||
"nu-protocol",
|
"nu-protocol",
|
||||||
@ -2692,7 +2700,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-path"
|
name = "nu-path"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs-next",
|
"dirs-next",
|
||||||
"dunce",
|
"dunce",
|
||||||
@ -2701,7 +2709,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-plugin"
|
name = "nu-plugin"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"capnp",
|
"capnp",
|
||||||
"nu-engine",
|
"nu-engine",
|
||||||
@ -2712,7 +2720,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-pretty-hex"
|
name = "nu-pretty-hex"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heapless 0.7.13",
|
"heapless 0.7.13",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
@ -2721,13 +2729,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-protocol"
|
name = "nu-protocol"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byte-unit",
|
"byte-unit",
|
||||||
"chrono",
|
"chrono",
|
||||||
"chrono-humanize",
|
"chrono-humanize",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"miette 4.7.1",
|
"miette 5.1.0",
|
||||||
"nu-json",
|
"nu-json",
|
||||||
"nu-utils",
|
"nu-utils",
|
||||||
"num-format",
|
"num-format",
|
||||||
@ -2741,7 +2749,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-system"
|
name = "nu-system"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"errno",
|
"errno",
|
||||||
@ -2755,7 +2763,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-table"
|
name = "nu-table"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi-str",
|
"ansi-str",
|
||||||
"atty",
|
"atty",
|
||||||
@ -2768,7 +2776,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-term-grid"
|
name = "nu-term-grid"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"strip-ansi-escapes",
|
"strip-ansi-escapes",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
@ -2776,7 +2784,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-test-support"
|
name = "nu-test-support"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getset",
|
"getset",
|
||||||
"hamcrest2",
|
"hamcrest2",
|
||||||
@ -2788,14 +2796,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-utils"
|
name = "nu-utils"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossterm_winapi",
|
"crossterm_winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu_plugin_example"
|
name = "nu_plugin_example"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nu-plugin",
|
"nu-plugin",
|
||||||
"nu-protocol",
|
"nu-protocol",
|
||||||
@ -2803,7 +2811,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu_plugin_gstat"
|
name = "nu_plugin_gstat"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"git2",
|
"git2",
|
||||||
"nu-engine",
|
"nu-engine",
|
||||||
@ -2813,7 +2821,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu_plugin_inc"
|
name = "nu_plugin_inc"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nu-plugin",
|
"nu-plugin",
|
||||||
"nu-protocol",
|
"nu-protocol",
|
||||||
@ -2822,7 +2830,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu_plugin_query"
|
name = "nu_plugin_query"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gjson",
|
"gjson",
|
||||||
"nu-engine",
|
"nu-engine",
|
||||||
@ -3145,9 +3153,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parquet2"
|
name = "parquet2"
|
||||||
version = "0.12.1"
|
version = "0.13.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cbacca5619bdee7f942938890451dea1a61f082c682aac913d7b4e326e66d7b4"
|
checksum = "73fd2690ad041f9296876daef1f2706f6347073bdbcc719090887f1691e4a09d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-stream",
|
"async-stream",
|
||||||
"bitpacking",
|
"bitpacking",
|
||||||
@ -3319,9 +3327,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polars"
|
name = "polars"
|
||||||
version = "0.21.1"
|
version = "0.22.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b140da767e129c60c41c8e1968ffab5f114bcf823182edb7fa900464a31bf421"
|
checksum = "3d175c67e80ceaef7219258cfc3a8686531d9510875b0cefa25404e5b80a7933"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"polars-core",
|
"polars-core",
|
||||||
"polars-io",
|
"polars-io",
|
||||||
@ -3332,9 +3340,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polars-arrow"
|
name = "polars-arrow"
|
||||||
version = "0.21.1"
|
version = "0.22.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6d27df11ee28956bd6f5aed54e7e05ce87b886871995e1da501134627ec89077"
|
checksum = "f66c7d3da2c10a09131294dbe7802fac792f570be639dc6ebf207bfc3e144287"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow2",
|
"arrow2",
|
||||||
"hashbrown 0.12.1",
|
"hashbrown 0.12.1",
|
||||||
@ -3345,9 +3353,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polars-core"
|
name = "polars-core"
|
||||||
version = "0.21.1"
|
version = "0.22.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fdf8d12cb7ec278516228fc86469f98c62ab81ca31e4e76d2c0ccf5a09c70491"
|
checksum = "f7f15f443a90d5367c4fbbb151e203f03b5b96055c8b928c6bc30655a3644f13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@ -3356,8 +3364,8 @@ dependencies = [
|
|||||||
"comfy-table",
|
"comfy-table",
|
||||||
"hashbrown 0.12.1",
|
"hashbrown 0.12.1",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"lazy_static",
|
|
||||||
"num 0.4.0",
|
"num 0.4.0",
|
||||||
|
"once_cell",
|
||||||
"polars-arrow",
|
"polars-arrow",
|
||||||
"polars-utils",
|
"polars-utils",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
@ -3371,20 +3379,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polars-io"
|
name = "polars-io"
|
||||||
version = "0.21.1"
|
version = "0.22.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fdd4b762e5694f359ded21ca0627b5bc95b6eb49f6b330569afc1d20f0564b01"
|
checksum = "058d0a847ce5009b974c69ec878ed416e306436f21b626543019f738cee12315"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arrow2",
|
"arrow2",
|
||||||
"csv-core",
|
"csv-core",
|
||||||
"dirs",
|
"dirs",
|
||||||
"lazy_static",
|
|
||||||
"lexical",
|
"lexical",
|
||||||
|
"lexical-core",
|
||||||
"memchr",
|
"memchr",
|
||||||
"memmap2",
|
"memmap2",
|
||||||
"num 0.4.0",
|
"num 0.4.0",
|
||||||
|
"once_cell",
|
||||||
"polars-arrow",
|
"polars-arrow",
|
||||||
"polars-core",
|
"polars-core",
|
||||||
"polars-time",
|
"polars-time",
|
||||||
@ -3398,9 +3407,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polars-lazy"
|
name = "polars-lazy"
|
||||||
version = "0.21.1"
|
version = "0.22.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eedc21001f05611e41bb7439b38d0f4ef9406aa49c17f3b289b5f57d8fa40c59"
|
checksum = "dad86a4ce7e32540ff12089bce6f77270fd133a5b263328a92be61defdd6b151"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"glob",
|
"glob",
|
||||||
@ -3408,6 +3417,7 @@ dependencies = [
|
|||||||
"polars-arrow",
|
"polars-arrow",
|
||||||
"polars-core",
|
"polars-core",
|
||||||
"polars-io",
|
"polars-io",
|
||||||
|
"polars-ops",
|
||||||
"polars-time",
|
"polars-time",
|
||||||
"polars-utils",
|
"polars-utils",
|
||||||
"rayon",
|
"rayon",
|
||||||
@ -3416,31 +3426,33 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polars-ops"
|
name = "polars-ops"
|
||||||
version = "0.21.1"
|
version = "0.22.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86fae68f0992955f224f09d1f15648a6fb76d8e3b962efac2f97ccc2aa58977a"
|
checksum = "030ecd473be113cd0264f1bc19de39a844fa12fa565db9dc52c859cbc292cf04"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"polars-arrow",
|
||||||
"polars-core",
|
"polars-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polars-time"
|
name = "polars-time"
|
||||||
version = "0.21.1"
|
version = "0.22.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be499f73749e820f96689c5f9ec59669b7cdd551d864358e2bdaebb5944e4bfb"
|
checksum = "94047b20d2da3bcc55c421be187a0c6f316cf1eea7fe7ed7347c1160a32d017c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"lexical",
|
"lexical",
|
||||||
"polars-arrow",
|
"polars-arrow",
|
||||||
"polars-core",
|
"polars-core",
|
||||||
|
"polars-utils",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polars-utils"
|
name = "polars-utils"
|
||||||
version = "0.21.1"
|
version = "0.22.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c7f4cd569d383f5f000abbd6d5146550e6cb4e43fac30d1af98699499a440d56"
|
checksum = "fcd3d0238462d5d9f7fbeaaea46e73ed4d58f6fae8b70d53cbe51d7538cc43f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parking_lot 0.12.1",
|
"parking_lot 0.12.1",
|
||||||
"rayon",
|
"rayon",
|
||||||
@ -3816,14 +3828,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reedline"
|
name = "reedline"
|
||||||
version = "0.7.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f8163ab90fabf0b8978b824743bb7a384394501b4b40c198a146c0eb9670ca4"
|
checksum = "d064ec92a21deb048c440b6461ccf0d0babdb5f2160ea9dfac451bc7b4b556e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"fd-lock",
|
"fd-lock",
|
||||||
"gethostname",
|
"gethostname",
|
||||||
|
"itertools",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
"serde",
|
"serde",
|
||||||
@ -4224,7 +4237,6 @@ version = "1.0.81"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
|
checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
|
||||||
"itoa 1.0.2",
|
"itoa 1.0.2",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
|
36
Cargo.toml
36
Cargo.toml
@ -11,7 +11,7 @@ name = "nu"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/nushell/nushell"
|
repository = "https://github.com/nushell/nushell"
|
||||||
rust-version = "1.60"
|
rust-version = "1.60"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
@ -36,23 +36,23 @@ chrono = { version = "0.4.19", features = ["serde"] }
|
|||||||
crossterm = "0.23.0"
|
crossterm = "0.23.0"
|
||||||
ctrlc = "3.2.1"
|
ctrlc = "3.2.1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
miette = "4.5.0"
|
miette = "5.1.0"
|
||||||
nu-ansi-term = "0.46.0"
|
nu-ansi-term = "0.46.0"
|
||||||
nu-cli = { path="./crates/nu-cli", version = "0.64.0" }
|
nu-cli = { path="./crates/nu-cli", version = "0.65.0" }
|
||||||
nu-color-config = { path = "./crates/nu-color-config", version = "0.64.0" }
|
nu-color-config = { path = "./crates/nu-color-config", version = "0.65.0" }
|
||||||
nu-command = { path="./crates/nu-command", version = "0.64.0" }
|
nu-command = { path="./crates/nu-command", version = "0.65.0" }
|
||||||
nu-engine = { path="./crates/nu-engine", version = "0.64.0" }
|
nu-engine = { path="./crates/nu-engine", version = "0.65.0" }
|
||||||
nu-json = { path="./crates/nu-json", version = "0.64.0" }
|
nu-json = { path="./crates/nu-json", version = "0.65.0" }
|
||||||
nu-parser = { path="./crates/nu-parser", version = "0.64.0" }
|
nu-parser = { path="./crates/nu-parser", version = "0.65.0" }
|
||||||
nu-path = { path="./crates/nu-path", version = "0.64.0" }
|
nu-path = { path="./crates/nu-path", version = "0.65.0" }
|
||||||
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.64.0" }
|
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.65.0" }
|
||||||
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.64.0" }
|
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.65.0" }
|
||||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.64.0" }
|
nu-protocol = { path = "./crates/nu-protocol", version = "0.65.0" }
|
||||||
nu-system = { path = "./crates/nu-system", version = "0.64.0" }
|
nu-system = { path = "./crates/nu-system", version = "0.65.0" }
|
||||||
nu-table = { path = "./crates/nu-table", version = "0.64.0" }
|
nu-table = { path = "./crates/nu-table", version = "0.65.0" }
|
||||||
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.64.0" }
|
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.65.0" }
|
||||||
nu-utils = { path = "./crates/nu-utils", version = "0.64.0" }
|
nu-utils = { path = "./crates/nu-utils", version = "0.65.0" }
|
||||||
reedline = { version = "0.7.0", features = ["bashisms", "sqlite"]}
|
reedline = { version = "0.8.0", features = ["bashisms", "sqlite"]}
|
||||||
pretty_env_logger = "0.4.0"
|
pretty_env_logger = "0.4.0"
|
||||||
rayon = "1.5.1"
|
rayon = "1.5.1"
|
||||||
is_executable = "1.0.1"
|
is_executable = "1.0.1"
|
||||||
@ -63,7 +63,7 @@ openssl = { version = "0.10.38", features = ["vendored"], optional = true }
|
|||||||
signal-hook = { version = "0.3.14", default-features = false }
|
signal-hook = { version = "0.3.14", default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
nu-test-support = { path="./crates/nu-test-support", version = "0.64.0" }
|
nu-test-support = { path="./crates/nu-test-support", version = "0.65.0" }
|
||||||
tempfile = "3.2.0"
|
tempfile = "3.2.0"
|
||||||
assert_cmd = "2.0.2"
|
assert_cmd = "2.0.2"
|
||||||
pretty_assertions = "1.0.0"
|
pretty_assertions = "1.0.0"
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 7.3 KiB |
@ -4,24 +4,24 @@ description = "CLI-related functionality for Nushell"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "nu-cli"
|
name = "nu-cli"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
nu-test-support = { path="../nu-test-support", version = "0.64.0" }
|
nu-test-support = { path="../nu-test-support", version = "0.65.0" }
|
||||||
nu-command = { path = "../nu-command", version = "0.64.0" }
|
nu-command = { path = "../nu-command", version = "0.65.0" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nu-engine = { path = "../nu-engine", version = "0.64.0" }
|
nu-engine = { path = "../nu-engine", version = "0.65.0" }
|
||||||
nu-path = { path = "../nu-path", version = "0.64.0" }
|
nu-path = { path = "../nu-path", version = "0.65.0" }
|
||||||
nu-parser = { path = "../nu-parser", version = "0.64.0" }
|
nu-parser = { path = "../nu-parser", version = "0.65.0" }
|
||||||
nu-protocol = { path = "../nu-protocol", version = "0.64.0" }
|
nu-protocol = { path = "../nu-protocol", version = "0.65.0" }
|
||||||
nu-utils = { path = "../nu-utils", version = "0.64.0" }
|
nu-utils = { path = "../nu-utils", version = "0.65.0" }
|
||||||
nu-ansi-term = "0.46.0"
|
nu-ansi-term = "0.46.0"
|
||||||
nu-color-config = { path = "../nu-color-config", version = "0.64.0" }
|
nu-color-config = { path = "../nu-color-config", version = "0.65.0" }
|
||||||
reedline = { version = "0.7.0", features = ["bashisms", "sqlite"]}
|
reedline = { version = "0.8.0", features = ["bashisms", "sqlite"]}
|
||||||
crossterm = "0.23.0"
|
crossterm = "0.23.0"
|
||||||
miette = { version = "4.5.0", features = ["fancy"] }
|
miette = { version = "5.1.0", features = ["fancy"] }
|
||||||
thiserror = "1.0.29"
|
thiserror = "1.0.31"
|
||||||
fuzzy-matcher = "0.3.7"
|
fuzzy-matcher = "0.3.7"
|
||||||
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
@ -18,7 +18,7 @@ pub fn evaluate_commands(
|
|||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
is_perf_true: bool,
|
is_perf_true: bool,
|
||||||
table_mode: Option<Value>,
|
table_mode: Option<Value>,
|
||||||
) -> Result<()> {
|
) -> Result<Option<i64>> {
|
||||||
// Run a command (or commands) given to us by the user
|
// Run a command (or commands) given to us by the user
|
||||||
let (block, delta) = {
|
let (block, delta) = {
|
||||||
if let Some(ref t_mode) = table_mode {
|
if let Some(ref t_mode) = table_mode {
|
||||||
@ -74,7 +74,7 @@ pub fn evaluate_commands(
|
|||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
match eval_block(engine_state, stack, &block, input, false, false) {
|
let exit_code = match eval_block(engine_state, stack, &block, input, false, false) {
|
||||||
Ok(pipeline_data) => {
|
Ok(pipeline_data) => {
|
||||||
crate::eval_file::print_table_or_error(engine_state, stack, pipeline_data, &mut config)
|
crate::eval_file::print_table_or_error(engine_state, stack, pipeline_data, &mut config)
|
||||||
}
|
}
|
||||||
@ -84,11 +84,11 @@ pub fn evaluate_commands(
|
|||||||
report_error(&working_set, &err);
|
report_error(&working_set, &err);
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
if is_perf_true {
|
if is_perf_true {
|
||||||
info!("evaluate {}:{}:{}", file!(), line!(), column!());
|
info!("evaluate {}:{}:{}", file!(), line!(), column!());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(exit_code)
|
||||||
}
|
}
|
||||||
|
@ -68,14 +68,10 @@ impl NuCompleter {
|
|||||||
for pipeline in output.pipelines.into_iter() {
|
for pipeline in output.pipelines.into_iter() {
|
||||||
for expr in pipeline.expressions {
|
for expr in pipeline.expressions {
|
||||||
let flattened: Vec<_> = flatten_expression(&working_set, &expr);
|
let flattened: Vec<_> = flatten_expression(&working_set, &expr);
|
||||||
|
let span_offset: usize = alias_offset.iter().sum();
|
||||||
|
|
||||||
for (flat_idx, flat) in flattened.iter().enumerate() {
|
for (flat_idx, flat) in flattened.iter().enumerate() {
|
||||||
let alias = if alias_offset.is_empty() {
|
if pos + span_offset >= flat.0.start && pos + span_offset < flat.0.end {
|
||||||
0
|
|
||||||
} else {
|
|
||||||
alias_offset[flat_idx]
|
|
||||||
};
|
|
||||||
if pos >= flat.0.start - alias && pos < flat.0.end - alias {
|
|
||||||
// Context variables
|
// Context variables
|
||||||
let most_left_var =
|
let most_left_var =
|
||||||
most_left_variable(flat_idx, &working_set, flattened.clone());
|
most_left_variable(flat_idx, &working_set, flattened.clone());
|
||||||
@ -84,42 +80,18 @@ impl NuCompleter {
|
|||||||
let new_span = if flat_idx == 0 {
|
let new_span = if flat_idx == 0 {
|
||||||
Span {
|
Span {
|
||||||
start: flat.0.start,
|
start: flat.0.start,
|
||||||
end: flat.0.end - 1 - alias,
|
end: flat.0.end - 1 - span_offset,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Span {
|
Span {
|
||||||
start: flat.0.start - alias,
|
start: flat.0.start - span_offset,
|
||||||
end: flat.0.end - 1 - alias,
|
end: flat.0.end - 1 - span_offset,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parses the prefix
|
// Parses the prefix
|
||||||
let mut prefix = working_set.get_span_contents(flat.0).to_vec();
|
let mut prefix = working_set.get_span_contents(flat.0).to_vec();
|
||||||
prefix.remove(pos - (flat.0.start - alias));
|
prefix.remove(pos - (flat.0.start - span_offset));
|
||||||
|
|
||||||
// Completions that depends on the previous expression (e.g: use, source)
|
|
||||||
if flat_idx > 0 {
|
|
||||||
if let Some(previous_expr) = flattened.get(flat_idx - 1) {
|
|
||||||
// Read the content for the previous expression
|
|
||||||
let prev_expr_str =
|
|
||||||
working_set.get_span_contents(previous_expr.0).to_vec();
|
|
||||||
|
|
||||||
// Completion for .nu files
|
|
||||||
if prev_expr_str == b"use" || prev_expr_str == b"source" {
|
|
||||||
let mut completer =
|
|
||||||
DotNuCompletion::new(self.engine_state.clone());
|
|
||||||
|
|
||||||
return self.process_completion(
|
|
||||||
&mut completer,
|
|
||||||
&working_set,
|
|
||||||
prefix,
|
|
||||||
new_span,
|
|
||||||
offset,
|
|
||||||
pos,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Variables completion
|
// Variables completion
|
||||||
if prefix.starts_with(b"$") || most_left_var.is_some() {
|
if prefix.starts_with(b"$") || most_left_var.is_some() {
|
||||||
@ -153,6 +125,42 @@ impl NuCompleter {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Completions that depends on the previous expression (e.g: use, source)
|
||||||
|
if flat_idx > 0 {
|
||||||
|
if let Some(previous_expr) = flattened.get(flat_idx - 1) {
|
||||||
|
// Read the content for the previous expression
|
||||||
|
let prev_expr_str =
|
||||||
|
working_set.get_span_contents(previous_expr.0).to_vec();
|
||||||
|
|
||||||
|
// Completion for .nu files
|
||||||
|
if prev_expr_str == b"use" || prev_expr_str == b"source" {
|
||||||
|
let mut completer =
|
||||||
|
DotNuCompletion::new(self.engine_state.clone());
|
||||||
|
|
||||||
|
return self.process_completion(
|
||||||
|
&mut completer,
|
||||||
|
&working_set,
|
||||||
|
prefix,
|
||||||
|
new_span,
|
||||||
|
offset,
|
||||||
|
pos,
|
||||||
|
);
|
||||||
|
} else if prev_expr_str == b"ls" {
|
||||||
|
let mut completer =
|
||||||
|
FileCompletion::new(self.engine_state.clone());
|
||||||
|
|
||||||
|
return self.process_completion(
|
||||||
|
&mut completer,
|
||||||
|
&working_set,
|
||||||
|
prefix,
|
||||||
|
new_span,
|
||||||
|
offset,
|
||||||
|
pos,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Match other types
|
// Match other types
|
||||||
match &flat.1 {
|
match &flat.1 {
|
||||||
FlatShape::Custom(decl_id) => {
|
FlatShape::Custom(decl_id) => {
|
||||||
@ -185,6 +193,18 @@ impl NuCompleter {
|
|||||||
pos,
|
pos,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
FlatShape::Filepath | FlatShape::GlobPattern => {
|
||||||
|
let mut completer = FileCompletion::new(self.engine_state.clone());
|
||||||
|
|
||||||
|
return self.process_completion(
|
||||||
|
&mut completer,
|
||||||
|
&working_set,
|
||||||
|
prefix,
|
||||||
|
new_span,
|
||||||
|
offset,
|
||||||
|
pos,
|
||||||
|
);
|
||||||
|
}
|
||||||
flat_shape => {
|
flat_shape => {
|
||||||
let mut completer = CommandCompletion::new(
|
let mut completer = CommandCompletion::new(
|
||||||
self.engine_state.clone(),
|
self.engine_state.clone(),
|
||||||
@ -235,7 +255,7 @@ impl ReedlineCompleter for NuCompleter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type MatchedAlias<'a> = Vec<(&'a [u8], &'a [u8])>;
|
type MatchedAlias = Vec<(Vec<u8>, Vec<u8>)>;
|
||||||
|
|
||||||
// Handler the completion when giving lines contains at least one alias. (e.g: `g checkout`)
|
// Handler the completion when giving lines contains at least one alias. (e.g: `g checkout`)
|
||||||
// that `g` is an alias of `git`
|
// that `g` is an alias of `git`
|
||||||
@ -254,6 +274,13 @@ fn try_find_alias(line: &[u8], working_set: &StateWorkingSet) -> (Vec<u8>, Vec<u
|
|||||||
lens -= 1;
|
lens -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !line.is_empty() {
|
||||||
|
let last = line.last().expect("input is empty");
|
||||||
|
if last == &b' ' {
|
||||||
|
output.push(b' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
output = line.to_vec();
|
output = line.to_vec();
|
||||||
}
|
}
|
||||||
@ -261,7 +288,7 @@ fn try_find_alias(line: &[u8], working_set: &StateWorkingSet) -> (Vec<u8>, Vec<u
|
|||||||
(output, alias_offset)
|
(output, alias_offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_alias<'a>(input: &'a [u8], working_set: &'a StateWorkingSet) -> Option<MatchedAlias<'a>> {
|
fn search_alias(input: &[u8], working_set: &StateWorkingSet) -> Option<MatchedAlias> {
|
||||||
let mut vec_names = vec![];
|
let mut vec_names = vec![];
|
||||||
let mut vec_alias = vec![];
|
let mut vec_alias = vec![];
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
@ -269,27 +296,31 @@ fn search_alias<'a>(input: &'a [u8], working_set: &'a StateWorkingSet) -> Option
|
|||||||
for (index, character) in input.iter().enumerate() {
|
for (index, character) in input.iter().enumerate() {
|
||||||
if *character == b' ' {
|
if *character == b' ' {
|
||||||
let range = &input[pos..index];
|
let range = &input[pos..index];
|
||||||
vec_names.push(range);
|
vec_names.push(range.to_owned());
|
||||||
pos = index + 1;
|
pos = index + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Push the rest to names vector.
|
// Push the rest to names vector.
|
||||||
if pos < input.len() {
|
if pos < input.len() {
|
||||||
vec_names.push(&input[pos..]);
|
vec_names.push((&input[pos..]).to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
for name in &vec_names {
|
for name in &vec_names {
|
||||||
if let Some(alias_id) = working_set.find_alias(name) {
|
if let Some(alias_id) = working_set.find_alias(&name[..]) {
|
||||||
let alias_span = working_set.get_alias(alias_id);
|
let alias_span = working_set.get_alias(alias_id);
|
||||||
|
let mut span_vec = vec![];
|
||||||
is_alias = true;
|
is_alias = true;
|
||||||
for alias in alias_span {
|
for alias in alias_span {
|
||||||
let name = working_set.get_span_contents(*alias);
|
let name = working_set.get_span_contents(*alias);
|
||||||
if !name.is_empty() {
|
if !name.is_empty() {
|
||||||
vec_alias.push(name);
|
span_vec.push(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Join span of vector together for complex alias, e.g: `f` is an alias for `git remote -v`
|
||||||
|
let full_aliases = span_vec.join(&[b' '][..]);
|
||||||
|
vec_alias.push(full_aliases);
|
||||||
} else {
|
} else {
|
||||||
vec_alias.push(name);
|
vec_alias.push(name.to_owned());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ impl Completer for VariableCompletion {
|
|||||||
options: &CompletionOptions,
|
options: &CompletionOptions,
|
||||||
) -> Vec<Suggestion> {
|
) -> Vec<Suggestion> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
let builtins = ["$nu", "$in", "$config", "$env", "$nothing"];
|
let builtins = ["$nu", "$in", "$env", "$nothing"];
|
||||||
let var_str = std::str::from_utf8(&self.var_context.0)
|
let var_str = std::str::from_utf8(&self.var_context.0)
|
||||||
.unwrap_or("")
|
.unwrap_or("")
|
||||||
.to_lowercase();
|
.to_lowercase();
|
||||||
|
@ -66,7 +66,7 @@ pub fn print_table_or_error(
|
|||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
mut pipeline_data: PipelineData,
|
mut pipeline_data: PipelineData,
|
||||||
config: &mut Config,
|
config: &mut Config,
|
||||||
) {
|
) -> Option<i64> {
|
||||||
let exit_code = match &mut pipeline_data {
|
let exit_code = match &mut pipeline_data {
|
||||||
PipelineData::ExternalStream { exit_code, .. } => exit_code.take(),
|
PipelineData::ExternalStream { exit_code, .. } => exit_code.take(),
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -130,6 +130,14 @@ pub fn print_table_or_error(
|
|||||||
|
|
||||||
// Make sure everything has finished
|
// Make sure everything has finished
|
||||||
if let Some(exit_code) = exit_code {
|
if let Some(exit_code) = exit_code {
|
||||||
let _: Vec<_> = exit_code.into_iter().collect();
|
let mut exit_code: Vec<_> = exit_code.into_iter().collect();
|
||||||
|
exit_code
|
||||||
|
.pop()
|
||||||
|
.and_then(|last_exit_code| match last_exit_code {
|
||||||
|
Value::Int { val: code, .. } => Some(code),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,11 +21,19 @@ impl Command for Print {
|
|||||||
"print without inserting a newline for the line ending",
|
"print without inserting a newline for the line ending",
|
||||||
Some('n'),
|
Some('n'),
|
||||||
)
|
)
|
||||||
|
.switch("stderr", "print to stderr instead of stdout", Some('e'))
|
||||||
.category(Category::Strings)
|
.category(Category::Strings)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"Prints the values given"
|
"Print the given values to stdout"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
r#"Unlike `echo`, this command does not return any value (`print | describe` will return "nothing").
|
||||||
|
Since this command has no output, there is no point in piping it with other commands.
|
||||||
|
|
||||||
|
`print` may be used inside blocks of code (e.g.: hooks) to display text during execution without interfering with the pipeline."#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
@ -41,11 +49,12 @@ impl Command for Print {
|
|||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let args: Vec<Value> = call.rest(engine_state, stack, 0)?;
|
let args: Vec<Value> = call.rest(engine_state, stack, 0)?;
|
||||||
let no_newline = call.has_flag("no-newline");
|
let no_newline = call.has_flag("no-newline");
|
||||||
|
let to_stderr = call.has_flag("stderr");
|
||||||
let head = call.head;
|
let head = call.head;
|
||||||
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
arg.into_pipeline_data()
|
arg.into_pipeline_data()
|
||||||
.print(engine_state, stack, no_newline)?;
|
.print(engine_state, stack, no_newline, to_stderr)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(PipelineData::new(head))
|
Ok(PipelineData::new(head))
|
||||||
|
@ -875,7 +875,16 @@ fn edit_from_record(
|
|||||||
"moveleft" => EditCommand::MoveLeft,
|
"moveleft" => EditCommand::MoveLeft,
|
||||||
"moveright" => EditCommand::MoveRight,
|
"moveright" => EditCommand::MoveRight,
|
||||||
"movewordleft" => EditCommand::MoveWordLeft,
|
"movewordleft" => EditCommand::MoveWordLeft,
|
||||||
|
"movebigwordleft" => EditCommand::MoveBigWordLeft,
|
||||||
"movewordright" => EditCommand::MoveWordRight,
|
"movewordright" => EditCommand::MoveWordRight,
|
||||||
|
"movewordrightend" => EditCommand::MoveWordRightEnd,
|
||||||
|
"movebigwordrightend" => EditCommand::MoveBigWordRightEnd,
|
||||||
|
"movewordrightstart" => EditCommand::MoveWordRightStart,
|
||||||
|
"movebigwordrightstart" => EditCommand::MoveBigWordRightStart,
|
||||||
|
"movetoposition" => {
|
||||||
|
let value = extract_value("value", cols, vals, span)?;
|
||||||
|
EditCommand::MoveToPosition(value.as_integer()? as usize)
|
||||||
|
}
|
||||||
"insertchar" => {
|
"insertchar" => {
|
||||||
let value = extract_value("value", cols, vals, span)?;
|
let value = extract_value("value", cols, vals, span)?;
|
||||||
let char = extract_char(value, config)?;
|
let char = extract_char(value, config)?;
|
||||||
@ -888,6 +897,7 @@ fn edit_from_record(
|
|||||||
"insertnewline" => EditCommand::InsertNewline,
|
"insertnewline" => EditCommand::InsertNewline,
|
||||||
"backspace" => EditCommand::Backspace,
|
"backspace" => EditCommand::Backspace,
|
||||||
"delete" => EditCommand::Delete,
|
"delete" => EditCommand::Delete,
|
||||||
|
"cutchar" => EditCommand::CutChar,
|
||||||
"backspaceword" => EditCommand::BackspaceWord,
|
"backspaceword" => EditCommand::BackspaceWord,
|
||||||
"deleteword" => EditCommand::DeleteWord,
|
"deleteword" => EditCommand::DeleteWord,
|
||||||
"clear" => EditCommand::Clear,
|
"clear" => EditCommand::Clear,
|
||||||
@ -898,7 +908,11 @@ fn edit_from_record(
|
|||||||
"cuttoend" => EditCommand::CutToEnd,
|
"cuttoend" => EditCommand::CutToEnd,
|
||||||
"cuttolineend" => EditCommand::CutToLineEnd,
|
"cuttolineend" => EditCommand::CutToLineEnd,
|
||||||
"cutwordleft" => EditCommand::CutWordLeft,
|
"cutwordleft" => EditCommand::CutWordLeft,
|
||||||
|
"cutbigwordleft" => EditCommand::CutBigWordLeft,
|
||||||
"cutwordright" => EditCommand::CutWordRight,
|
"cutwordright" => EditCommand::CutWordRight,
|
||||||
|
"cutbigwordright" => EditCommand::CutBigWordRight,
|
||||||
|
"cutwordrighttonext" => EditCommand::CutWordRightToNext,
|
||||||
|
"cutbigwordrighttonext" => EditCommand::CutBigWordRightToNext,
|
||||||
"pastecutbufferbefore" => EditCommand::PasteCutBufferBefore,
|
"pastecutbufferbefore" => EditCommand::PasteCutBufferBefore,
|
||||||
"pastecutbufferafter" => EditCommand::PasteCutBufferAfter,
|
"pastecutbufferafter" => EditCommand::PasteCutBufferAfter,
|
||||||
"uppercaseword" => EditCommand::UppercaseWord,
|
"uppercaseword" => EditCommand::UppercaseWord,
|
||||||
|
@ -247,7 +247,7 @@ pub fn eval_source(
|
|||||||
set_last_exit_code(stack, 0);
|
set_last_exit_code(stack, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(err) = pipeline_data.print(engine_state, stack, false) {
|
if let Err(err) = pipeline_data.print(engine_state, stack, false, false) {
|
||||||
let working_set = StateWorkingSet::new(engine_state);
|
let working_set = StateWorkingSet::new(engine_state);
|
||||||
|
|
||||||
report_error(&working_set, &err);
|
report_error(&working_set, &err);
|
||||||
|
65
crates/nu-cli/tests/alias.rs
Normal file
65
crates/nu-cli/tests/alias.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
pub mod support;
|
||||||
|
|
||||||
|
use nu_cli::NuCompleter;
|
||||||
|
use reedline::Completer;
|
||||||
|
use support::{match_suggestions, new_engine};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn alias_of_command_and_flags() {
|
||||||
|
let (dir, _, mut engine, mut stack) = new_engine();
|
||||||
|
|
||||||
|
// Create an alias
|
||||||
|
let alias = r#"alias ll = ls -l"#;
|
||||||
|
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let suggestions = completer.complete("ll t", 4);
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec!["test_a\\".to_string(), "test_b\\".to_string()];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn alias_of_basic_command() {
|
||||||
|
let (dir, _, mut engine, mut stack) = new_engine();
|
||||||
|
|
||||||
|
// Create an alias
|
||||||
|
let alias = r#"alias ll = ls "#;
|
||||||
|
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let suggestions = completer.complete("ll t", 4);
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec!["test_a\\".to_string(), "test_b\\".to_string()];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn alias_of_another_alias() {
|
||||||
|
let (dir, _, mut engine, mut stack) = new_engine();
|
||||||
|
|
||||||
|
// Create an alias
|
||||||
|
let alias = r#"alias ll = ls -la"#;
|
||||||
|
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir.clone()).is_ok());
|
||||||
|
// Create the second alias
|
||||||
|
let alias = r#"alias lf = ll -f"#;
|
||||||
|
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let suggestions = completer.complete("lf t", 4);
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec!["test_a\\".to_string(), "test_b\\".to_string()];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
@ -14,7 +14,7 @@ fn variables_completions() {
|
|||||||
def my-command [animal: string@animals] { print $animal }"#;
|
def my-command [animal: string@animals] { print $animal }"#;
|
||||||
assert!(support::merge_input(record.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
assert!(support::merge_input(record.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
||||||
|
|
||||||
// Instatiate a new completer
|
// Instantiate a new completer
|
||||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
// Test completions for $nu
|
// Test completions for $nu
|
||||||
|
@ -40,3 +40,233 @@ fn file_completions() {
|
|||||||
// Match the results
|
// Match the results
|
||||||
match_suggestions(expected_paths, suggestions);
|
match_suggestions(expected_paths, suggestions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_ls_completion() {
|
||||||
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let target_dir = "ls ";
|
||||||
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a\\".to_string(),
|
||||||
|
"test_b\\".to_string(),
|
||||||
|
"another\\".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder\\".to_string(),
|
||||||
|
];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a/".to_string(),
|
||||||
|
"test_b/".to_string(),
|
||||||
|
"another/".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder/".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn command_open_completion() {
|
||||||
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let target_dir = "open ";
|
||||||
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a\\".to_string(),
|
||||||
|
"test_b\\".to_string(),
|
||||||
|
"another\\".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder\\".to_string(),
|
||||||
|
];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a/".to_string(),
|
||||||
|
"test_b/".to_string(),
|
||||||
|
"another/".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder/".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_rm_completion() {
|
||||||
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let target_dir = "rm ";
|
||||||
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a\\".to_string(),
|
||||||
|
"test_b\\".to_string(),
|
||||||
|
"another\\".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder\\".to_string(),
|
||||||
|
];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a/".to_string(),
|
||||||
|
"test_b/".to_string(),
|
||||||
|
"another/".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder/".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_cp_completion() {
|
||||||
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let target_dir = "cp ";
|
||||||
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a\\".to_string(),
|
||||||
|
"test_b\\".to_string(),
|
||||||
|
"another\\".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder\\".to_string(),
|
||||||
|
];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a/".to_string(),
|
||||||
|
"test_b/".to_string(),
|
||||||
|
"another/".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder/".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_save_completion() {
|
||||||
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let target_dir = "save ";
|
||||||
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a\\".to_string(),
|
||||||
|
"test_b\\".to_string(),
|
||||||
|
"another\\".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder\\".to_string(),
|
||||||
|
];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a/".to_string(),
|
||||||
|
"test_b/".to_string(),
|
||||||
|
"another/".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder/".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_touch_completion() {
|
||||||
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let target_dir = "touch ";
|
||||||
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a\\".to_string(),
|
||||||
|
"test_b\\".to_string(),
|
||||||
|
"another\\".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder\\".to_string(),
|
||||||
|
];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a/".to_string(),
|
||||||
|
"test_b/".to_string(),
|
||||||
|
"another/".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder/".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_watch_completion() {
|
||||||
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let target_dir = "watch ";
|
||||||
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a\\".to_string(),
|
||||||
|
"test_b\\".to_string(),
|
||||||
|
"another\\".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder\\".to_string(),
|
||||||
|
];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a/".to_string(),
|
||||||
|
"test_b/".to_string(),
|
||||||
|
"another/".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder/".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
@ -4,11 +4,11 @@ description = "Color configuration code used by Nushell"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "nu-color-config"
|
name = "nu-color-config"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nu-protocol = { path = "../nu-protocol", version = "0.64.0" }
|
nu-protocol = { path = "../nu-protocol", version = "0.65.0" }
|
||||||
nu-ansi-term = "0.46.0"
|
nu-ansi-term = "0.46.0"
|
||||||
nu-json = { path = "../nu-json", version = "0.64.0" }
|
nu-json = { path = "../nu-json", version = "0.65.0" }
|
||||||
nu-table = { path = "../nu-table", version = "0.64.0" }
|
nu-table = { path = "../nu-table", version = "0.65.0" }
|
||||||
serde = { version="1.0.123", features=["derive"] }
|
serde = { version="1.0.123", features=["derive"] }
|
||||||
|
@ -4,30 +4,31 @@ description = "Nushell's built-in commands"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "nu-command"
|
name = "nu-command"
|
||||||
version = "0.64.0"
|
version = "0.65.0"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nu-color-config = { path = "../nu-color-config", version = "0.64.0" }
|
nu-color-config = { path = "../nu-color-config", version = "0.65.0" }
|
||||||
nu-engine = { path = "../nu-engine", version = "0.64.0" }
|
nu-engine = { path = "../nu-engine", version = "0.65.0" }
|
||||||
nu-glob = { path = "../nu-glob", version = "0.64.0" }
|
nu-glob = { path = "../nu-glob", version = "0.65.0" }
|
||||||
nu-json = { path = "../nu-json", version = "0.64.0" }
|
nu-json = { path = "../nu-json", version = "0.65.0" }
|
||||||
nu-parser = { path = "../nu-parser", version = "0.64.0" }
|
nu-parser = { path = "../nu-parser", version = "0.65.0" }
|
||||||
nu-path = { path = "../nu-path", version = "0.64.0" }
|
nu-path = { path = "../nu-path", version = "0.65.0" }
|
||||||
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.64.0" }
|
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.65.0" }
|
||||||
nu-protocol = { path = "../nu-protocol", version = "0.64.0" }
|
nu-protocol = { path = "../nu-protocol", version = "0.65.0" }
|
||||||
nu-system = { path = "../nu-system", version = "0.64.0" }
|
nu-system = { path = "../nu-system", version = "0.65.0" }
|
||||||
nu-table = { path = "../nu-table", version = "0.64.0" }
|
nu-table = { path = "../nu-table", version = "0.65.0" }
|
||||||
nu-term-grid = { path = "../nu-term-grid", version = "0.64.0" }
|
nu-term-grid = { path = "../nu-term-grid", version = "0.65.0" }
|
||||||
nu-test-support = { path = "../nu-test-support", version = "0.64.0" }
|
nu-test-support = { path = "../nu-test-support", version = "0.65.0" }
|
||||||
nu-utils = { path = "../nu-utils", version = "0.64.0" }
|
nu-utils = { path = "../nu-utils", version = "0.65.0" }
|
||||||
nu-ansi-term = "0.46.0"
|
nu-ansi-term = "0.46.0"
|
||||||
|
|
||||||
# Potential dependencies for extras
|
# Potential dependencies for extras
|
||||||
alphanumeric-sort = "1.4.4"
|
alphanumeric-sort = "1.4.4"
|
||||||
base64 = "0.13.0"
|
base64 = "0.13.0"
|
||||||
|
byteorder = "1.4.3"
|
||||||
bytesize = "1.1.0"
|
bytesize = "1.1.0"
|
||||||
calamine = "0.18.0"
|
calamine = "0.18.0"
|
||||||
chrono = { version = "0.4.19", features = ["serde"] }
|
chrono = { version = "0.4.19", features = ["serde"] }
|
||||||
@ -76,14 +77,14 @@ shadow-rs = { version = "0.11.0", default-features = false }
|
|||||||
strip-ansi-escapes = "0.1.1"
|
strip-ansi-escapes = "0.1.1"
|
||||||
sysinfo = "0.23.5"
|
sysinfo = "0.23.5"
|
||||||
terminal_size = "0.1.17"
|
terminal_size = "0.1.17"
|
||||||
thiserror = "1.0.29"
|
thiserror = "1.0.31"
|
||||||
titlecase = "1.1.0"
|
titlecase = "1.1.0"
|
||||||
toml = "0.5.8"
|
toml = "0.5.8"
|
||||||
unicode-segmentation = "1.8.0"
|
unicode-segmentation = "1.8.0"
|
||||||
url = "2.2.1"
|
url = "2.2.1"
|
||||||
uuid = { version = "0.8.2", features = ["v4"] }
|
uuid = { version = "0.8.2", features = ["v4"] }
|
||||||
which = { version = "4.2.2", optional = true }
|
which = { version = "4.2.2", optional = true }
|
||||||
reedline = { version = "0.7.0", features = ["bashisms", "sqlite"]}
|
reedline = { version = "0.8.0", features = ["bashisms", "sqlite"]}
|
||||||
wax = { version = "0.4.0", features = ["diagnostics"] }
|
wax = { version = "0.4.0", features = ["diagnostics"] }
|
||||||
rusqlite = { version = "0.27.0", features = ["bundled"], optional = true }
|
rusqlite = { version = "0.27.0", features = ["bundled"], optional = true }
|
||||||
sqlparser = { version = "0.16.0", features = ["serde"], optional = true }
|
sqlparser = { version = "0.16.0", features = ["serde"], optional = true }
|
||||||
@ -91,13 +92,14 @@ sqlparser = { version = "0.16.0", features = ["serde"], optional = true }
|
|||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
umask = "2.0.0"
|
umask = "2.0.0"
|
||||||
users = "0.11.0"
|
users = "0.11.0"
|
||||||
|
signal-hook = { version = "0.3.14", default-features = false }
|
||||||
|
|
||||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies.trash]
|
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies.trash]
|
||||||
version = "2.1.3"
|
version = "2.1.3"
|
||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[dependencies.polars]
|
[dependencies.polars]
|
||||||
version = "0.21.1"
|
version = "0.22.8"
|
||||||
# path = "../../../../polars/polars"
|
# path = "../../../../polars/polars"
|
||||||
optional = true
|
optional = true
|
||||||
features = [
|
features = [
|
||||||
@ -105,7 +107,7 @@ features = [
|
|||||||
"object", "checked_arithmetic", "strings", "cum_agg", "is_in",
|
"object", "checked_arithmetic", "strings", "cum_agg", "is_in",
|
||||||
"rolling_window", "strings", "rows", "random",
|
"rolling_window", "strings", "rows", "random",
|
||||||
"dtype-datetime", "dtype-struct", "lazy", "cross_join",
|
"dtype-datetime", "dtype-struct", "lazy", "cross_join",
|
||||||
"dynamic_groupby"
|
"dynamic_groupby", "dtype-categorical"
|
||||||
]
|
]
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies.windows]
|
[target.'cfg(windows)'.dependencies.windows]
|
||||||
@ -132,3 +134,4 @@ hamcrest2 = "0.3.0"
|
|||||||
dirs-next = "2.0.0"
|
dirs-next = "2.0.0"
|
||||||
quickcheck = "1.0.3"
|
quickcheck = "1.0.3"
|
||||||
quickcheck_macros = "1.0.0"
|
quickcheck_macros = "1.0.0"
|
||||||
|
rstest = "0.12.0"
|
||||||
|
98
crates/nu-command/src/bytes/length.rs
Normal file
98
crates/nu-command/src/bytes/length.rs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
use super::{operate, BytesArgument};
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::ast::CellPath;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::Category;
|
||||||
|
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct BytesLen;
|
||||||
|
|
||||||
|
struct Arguments {
|
||||||
|
column_paths: Option<Vec<CellPath>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BytesArgument for Arguments {
|
||||||
|
fn take_column_paths(&mut self) -> Option<Vec<CellPath>> {
|
||||||
|
self.column_paths.take()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command for BytesLen {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"bytes length"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("bytes length")
|
||||||
|
.rest(
|
||||||
|
"rest",
|
||||||
|
SyntaxShape::CellPath,
|
||||||
|
"optionally find length of binary by column paths",
|
||||||
|
)
|
||||||
|
.category(Category::Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Output the length of any bytes in the pipeline"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["len", "size", "count"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
|
||||||
|
let column_paths = if column_paths.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(column_paths)
|
||||||
|
};
|
||||||
|
let arg = Arguments { column_paths };
|
||||||
|
operate(length, arg, input, call.head, engine_state.ctrlc.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Return the lengths of multiple strings",
|
||||||
|
example: "0x[1F FF AA AB] | bytes length",
|
||||||
|
result: Some(Value::test_int(4)),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Return the lengths of multiple strings",
|
||||||
|
example: "[0x[1F FF AA AB] 0x[1F]] | bytes length",
|
||||||
|
result: Some(Value::List {
|
||||||
|
vals: vec![Value::test_int(4), Value::test_int(1)],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn length(input: &[u8], _arg: &Arguments, span: Span) -> Value {
|
||||||
|
Value::Int {
|
||||||
|
val: input.len() as i64,
|
||||||
|
span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(BytesLen {})
|
||||||
|
}
|
||||||
|
}
|
77
crates/nu-command/src/bytes/mod.rs
Normal file
77
crates/nu-command/src/bytes/mod.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
mod length;
|
||||||
|
mod starts_with;
|
||||||
|
use nu_protocol::ast::CellPath;
|
||||||
|
use nu_protocol::{PipelineData, ShellError, Span, Value};
|
||||||
|
use std::sync::atomic::AtomicBool;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub use length::BytesLen;
|
||||||
|
pub use starts_with::BytesStartsWith;
|
||||||
|
|
||||||
|
trait BytesArgument {
|
||||||
|
fn take_column_paths(&mut self) -> Option<Vec<CellPath>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// map input pipeline data, for each elements, if it's Binary, invoke relative `cmd` with `arg`.
|
||||||
|
fn operate<C, A>(
|
||||||
|
cmd: C,
|
||||||
|
mut arg: A,
|
||||||
|
input: PipelineData,
|
||||||
|
span: Span,
|
||||||
|
ctrlc: Option<Arc<AtomicBool>>,
|
||||||
|
) -> Result<PipelineData, ShellError>
|
||||||
|
where
|
||||||
|
A: BytesArgument + Send + Sync + 'static,
|
||||||
|
C: Fn(&[u8], &A, Span) -> Value + Send + Sync + 'static + Clone + Copy,
|
||||||
|
{
|
||||||
|
match arg.take_column_paths() {
|
||||||
|
None => input.map(
|
||||||
|
move |v| match v {
|
||||||
|
Value::Binary {
|
||||||
|
val,
|
||||||
|
span: val_span,
|
||||||
|
} => cmd(&val, &arg, val_span),
|
||||||
|
other => Value::Error {
|
||||||
|
error: ShellError::UnsupportedInput(
|
||||||
|
format!(
|
||||||
|
"Input's type is {}. This command only works with bytes.",
|
||||||
|
other.get_type()
|
||||||
|
),
|
||||||
|
span,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ctrlc,
|
||||||
|
),
|
||||||
|
Some(column_paths) => {
|
||||||
|
let arg = Arc::new(arg);
|
||||||
|
input.map(
|
||||||
|
move |mut v| {
|
||||||
|
for path in &column_paths {
|
||||||
|
let opt = arg.clone();
|
||||||
|
let r = v.update_cell_path(
|
||||||
|
&path.members,
|
||||||
|
Box::new(move |old| {
|
||||||
|
match old {
|
||||||
|
Value::Binary {val, span: val_span} => cmd(val, &opt, *val_span),
|
||||||
|
other => Value::Error {
|
||||||
|
error: ShellError::UnsupportedInput(
|
||||||
|
format!(
|
||||||
|
"Input's type is {}. This command only works with bytes.",
|
||||||
|
other.get_type()
|
||||||
|
),
|
||||||
|
span,
|
||||||
|
),
|
||||||
|
}}}),
|
||||||
|
);
|
||||||
|
if let Err(error) = r {
|
||||||
|
return Value::Error { error };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v
|
||||||
|
},
|
||||||
|
ctrlc,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
122
crates/nu-command/src/bytes/starts_with.rs
Normal file
122
crates/nu-command/src/bytes/starts_with.rs
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
use super::{operate, BytesArgument};
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::ast::CellPath;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::Category;
|
||||||
|
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value};
|
||||||
|
|
||||||
|
struct Arguments {
|
||||||
|
pattern: Vec<u8>,
|
||||||
|
column_paths: Option<Vec<CellPath>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BytesArgument for Arguments {
|
||||||
|
fn take_column_paths(&mut self) -> Option<Vec<CellPath>> {
|
||||||
|
self.column_paths.take()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
|
||||||
|
pub struct BytesStartsWith;
|
||||||
|
|
||||||
|
impl Command for BytesStartsWith {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"bytes starts-with"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("bytes starts-with")
|
||||||
|
.required("pattern", SyntaxShape::Binary, "the pattern to match")
|
||||||
|
.rest(
|
||||||
|
"rest",
|
||||||
|
SyntaxShape::CellPath,
|
||||||
|
"optionally matches prefix of text by column paths",
|
||||||
|
)
|
||||||
|
.category(Category::Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Check if bytes starts with a pattern"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["pattern", "match", "find", "search"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let pattern: Vec<u8> = call.req(engine_state, stack, 0)?;
|
||||||
|
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
|
||||||
|
let column_paths = if column_paths.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(column_paths)
|
||||||
|
};
|
||||||
|
let arg = Arguments {
|
||||||
|
pattern,
|
||||||
|
column_paths,
|
||||||
|
};
|
||||||
|
operate(
|
||||||
|
starts_with,
|
||||||
|
arg,
|
||||||
|
input,
|
||||||
|
call.head,
|
||||||
|
engine_state.ctrlc.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Checks if binary starts with `0x[1F FF AA]`",
|
||||||
|
example: "0x[1F FF AA AA] | bytes starts-with 0x[1F FF AA]",
|
||||||
|
result: Some(Value::Bool {
|
||||||
|
val: true,
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Checks if binary starts with `0x[1F]`",
|
||||||
|
example: "0x[1F FF AA AA] | bytes starts-with 0x[1F]",
|
||||||
|
result: Some(Value::Bool {
|
||||||
|
val: true,
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Checks if binary starts with `0x[1F]`",
|
||||||
|
example: "0x[1F FF AA AA] | bytes starts-with 0x[11]",
|
||||||
|
result: Some(Value::Bool {
|
||||||
|
val: false,
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn starts_with(input: &[u8], Arguments { pattern, .. }: &Arguments, span: Span) -> Value {
|
||||||
|
Value::Bool {
|
||||||
|
val: input.starts_with(pattern),
|
||||||
|
span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(BytesStartsWith {})
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::{generate_strftime_list, parse_date_from_string};
|
||||||
use chrono::{DateTime, FixedOffset, Local, TimeZone, Utc};
|
use chrono::{DateTime, FixedOffset, Local, TimeZone, Utc};
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
@ -7,9 +8,6 @@ use nu_protocol::{
|
|||||||
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
|
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::generate_strftime_list;
|
|
||||||
use crate::parse_date_from_string;
|
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
timezone: Option<Spanned<String>>,
|
timezone: Option<Spanned<String>>,
|
||||||
offset: Option<Spanned<i64>>,
|
offset: Option<Spanned<i64>>,
|
||||||
@ -148,6 +146,15 @@ impl Command for SubCommand {
|
|||||||
example: "1614434140 | into datetime -o +9",
|
example: "1614434140 | into datetime -o +9",
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
|
Example {
|
||||||
|
description:
|
||||||
|
"Convert timestamps like the sqlite history t",
|
||||||
|
example: "1656165681720 | into datetime",
|
||||||
|
result: Some(Value::Date {
|
||||||
|
val: Utc.timestamp_millis(1656165681720).into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -251,10 +258,19 @@ fn action(
|
|||||||
|
|
||||||
return match timezone {
|
return match timezone {
|
||||||
// default to UTC
|
// default to UTC
|
||||||
None => Value::Date {
|
None => {
|
||||||
val: Utc.timestamp(ts, 0).into(),
|
// be able to convert chrono::Utc::now()
|
||||||
span: head,
|
let dt = match ts.to_string().len() {
|
||||||
},
|
x if x > 13 => Utc.timestamp_nanos(ts).into(),
|
||||||
|
x if x > 10 => Utc.timestamp_millis(ts).into(),
|
||||||
|
_ => Utc.timestamp(ts, 0).into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Value::Date {
|
||||||
|
val: dt,
|
||||||
|
span: head,
|
||||||
|
}
|
||||||
|
}
|
||||||
Some(Spanned { item, span }) => match item {
|
Some(Spanned { item, span }) => match item {
|
||||||
Zone::Utc => Value::Date {
|
Zone::Utc => Value::Date {
|
||||||
val: Utc.timestamp(ts, 0).into(),
|
val: Utc.timestamp(ts, 0).into(),
|
||||||
|
@ -8,6 +8,7 @@ use nu_protocol::{
|
|||||||
struct Arguments {
|
struct Arguments {
|
||||||
radix: Option<Value>,
|
radix: Option<Value>,
|
||||||
column_paths: Vec<CellPath>,
|
column_paths: Vec<CellPath>,
|
||||||
|
little_endian: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -21,6 +22,7 @@ impl Command for SubCommand {
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("into int")
|
Signature::build("into int")
|
||||||
.named("radix", SyntaxShape::Number, "radix of integer", Some('r'))
|
.named("radix", SyntaxShape::Number, "radix of integer", Some('r'))
|
||||||
|
.switch("little-endian", "use little-endian byte decoding", None)
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
SyntaxShape::CellPath,
|
SyntaxShape::CellPath,
|
||||||
@ -114,6 +116,7 @@ fn into_int(
|
|||||||
|
|
||||||
let options = Arguments {
|
let options = Arguments {
|
||||||
radix: call.get_flag(engine_state, stack, "radix")?,
|
radix: call.get_flag(engine_state, stack, "radix")?,
|
||||||
|
little_endian: call.has_flag("little-endian"),
|
||||||
column_paths: call.rest(engine_state, stack, 0)?,
|
column_paths: call.rest(engine_state, stack, 0)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -135,13 +138,13 @@ fn into_int(
|
|||||||
input.map(
|
input.map(
|
||||||
move |v| {
|
move |v| {
|
||||||
if options.column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
action(&v, head, radix)
|
action(&v, head, radix, options.little_endian)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
for path in &options.column_paths {
|
for path in &options.column_paths {
|
||||||
let r = ret.update_cell_path(
|
let r = ret.update_cell_path(
|
||||||
&path.members,
|
&path.members,
|
||||||
Box::new(move |old| action(old, head, radix)),
|
Box::new(move |old| action(old, head, radix, options.little_endian)),
|
||||||
);
|
);
|
||||||
if let Err(error) = r {
|
if let Err(error) = r {
|
||||||
return Value::Error { error };
|
return Value::Error { error };
|
||||||
@ -155,7 +158,7 @@ fn into_int(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn action(input: &Value, span: Span, radix: u32) -> Value {
|
pub fn action(input: &Value, span: Span, radix: u32, little_endian: bool) -> Value {
|
||||||
match input {
|
match input {
|
||||||
Value::Int { val: _, .. } => {
|
Value::Int { val: _, .. } => {
|
||||||
if radix == 10 {
|
if radix == 10 {
|
||||||
@ -190,6 +193,33 @@ pub fn action(input: &Value, span: Span, radix: u32) -> Value {
|
|||||||
val: val.timestamp(),
|
val: val.timestamp(),
|
||||||
span,
|
span,
|
||||||
},
|
},
|
||||||
|
Value::Binary { val, span } => {
|
||||||
|
use byteorder::{BigEndian, ByteOrder, LittleEndian};
|
||||||
|
|
||||||
|
let mut val = val.to_vec();
|
||||||
|
|
||||||
|
if little_endian {
|
||||||
|
while val.len() < 8 {
|
||||||
|
val.push(0);
|
||||||
|
}
|
||||||
|
val.resize(8, 0);
|
||||||
|
|
||||||
|
Value::Int {
|
||||||
|
val: LittleEndian::read_i64(&val),
|
||||||
|
span: *span,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while val.len() < 8 {
|
||||||
|
val.insert(0, 0);
|
||||||
|
}
|
||||||
|
val.resize(8, 0);
|
||||||
|
|
||||||
|
Value::Int {
|
||||||
|
val: BigEndian::read_i64(&val),
|
||||||
|
span: *span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => Value::Error {
|
_ => Value::Error {
|
||||||
error: ShellError::UnsupportedInput(
|
error: ShellError::UnsupportedInput(
|
||||||
format!("'into int' for unsupported type '{}'", input.get_type()),
|
format!("'into int' for unsupported type '{}'", input.get_type()),
|
||||||
@ -294,21 +324,21 @@ mod test {
|
|||||||
let word = Value::test_string("10");
|
let word = Value::test_string("10");
|
||||||
let expected = Value::test_int(10);
|
let expected = Value::test_int(10);
|
||||||
|
|
||||||
let actual = action(&word, Span::test_data(), 10);
|
let actual = action(&word, Span::test_data(), 10, false);
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn turns_binary_to_integer() {
|
fn turns_binary_to_integer() {
|
||||||
let s = Value::test_string("0b101");
|
let s = Value::test_string("0b101");
|
||||||
let actual = action(&s, Span::test_data(), 10);
|
let actual = action(&s, Span::test_data(), 10, false);
|
||||||
assert_eq!(actual, Value::test_int(5));
|
assert_eq!(actual, Value::test_int(5));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn turns_hex_to_integer() {
|
fn turns_hex_to_integer() {
|
||||||
let s = Value::test_string("0xFF");
|
let s = Value::test_string("0xFF");
|
||||||
let actual = action(&s, Span::test_data(), 16);
|
let actual = action(&s, Span::test_data(), 16, false);
|
||||||
assert_eq!(actual, Value::test_int(255));
|
assert_eq!(actual, Value::test_int(255));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,7 +346,7 @@ mod test {
|
|||||||
fn communicates_parsing_error_given_an_invalid_integerlike_string() {
|
fn communicates_parsing_error_given_an_invalid_integerlike_string() {
|
||||||
let integer_str = Value::test_string("36anra");
|
let integer_str = Value::test_string("36anra");
|
||||||
|
|
||||||
let actual = action(&integer_str, Span::test_data(), 10);
|
let actual = action(&integer_str, Span::test_data(), 10, false);
|
||||||
|
|
||||||
assert_eq!(actual.get_type(), Error)
|
assert_eq!(actual.get_type(), Error)
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@ use nu_engine::CallExt;
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Call, CellPath},
|
ast::{Call, CellPath},
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Config, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span,
|
into_code, Category, Config, Example, IntoPipelineData, PipelineData, ShellError, Signature,
|
||||||
SyntaxShape, Value,
|
Span, SyntaxShape, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO num_format::SystemLocale once platform-specific dependencies are stable (see Cargo.toml)
|
// TODO num_format::SystemLocale once platform-specific dependencies are stable (see Cargo.toml)
|
||||||
@ -247,6 +247,15 @@ pub fn action(
|
|||||||
val: input.into_string(", ", config),
|
val: input.into_string(", ", config),
|
||||||
span,
|
span,
|
||||||
},
|
},
|
||||||
|
Value::Error { error } => Value::String {
|
||||||
|
val: {
|
||||||
|
match into_code(error) {
|
||||||
|
Some(code) => code,
|
||||||
|
None => "".to_string(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
span,
|
||||||
|
},
|
||||||
Value::Nothing { .. } => Value::String {
|
Value::Nothing { .. } => Value::String {
|
||||||
val: "".to_string(),
|
val: "".to_string(),
|
||||||
span,
|
span,
|
||||||
|
@ -28,7 +28,33 @@ impl Command for DefEnv {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nushell.html
|
||||||
|
|
||||||
|
=== EXTRA NOTE ===
|
||||||
|
All blocks are scoped, including variable definition and environment variable changes.
|
||||||
|
|
||||||
|
Because of this, the following doesn't work:
|
||||||
|
|
||||||
|
def-env cd_with_fallback [arg = ""] {
|
||||||
|
let fall_back_path = "/tmp"
|
||||||
|
if $arg != "" {
|
||||||
|
cd $arg
|
||||||
|
} else {
|
||||||
|
cd $fall_back_path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Instead, you have to use cd in the top level scope:
|
||||||
|
|
||||||
|
def-env cd_with_fallback [arg = ""] {
|
||||||
|
let fall_back_path = "/tmp"
|
||||||
|
let path = if $arg != "" {
|
||||||
|
$arg
|
||||||
|
} else {
|
||||||
|
$fall_back_path
|
||||||
|
}
|
||||||
|
cd $path
|
||||||
|
}"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use nu_engine::{eval_block, CallExt};
|
use nu_engine::{eval_block, CallExt};
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
||||||
use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape, Value};
|
use nu_protocol::{
|
||||||
|
Category, Example, IntoPipelineData, PipelineData, Signature, SyntaxShape, Value,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Do;
|
pub struct Do;
|
||||||
@ -23,6 +25,11 @@ impl Command for Do {
|
|||||||
"ignore errors as the block runs",
|
"ignore errors as the block runs",
|
||||||
Some('i'),
|
Some('i'),
|
||||||
)
|
)
|
||||||
|
.switch(
|
||||||
|
"capture-errors",
|
||||||
|
"capture errors as the block runs and return it",
|
||||||
|
Some('c'),
|
||||||
|
)
|
||||||
.rest("rest", SyntaxShape::Any, "the parameter(s) for the block")
|
.rest("rest", SyntaxShape::Any, "the parameter(s) for the block")
|
||||||
.category(Category::Core)
|
.category(Category::Core)
|
||||||
}
|
}
|
||||||
@ -37,6 +44,7 @@ impl Command for Do {
|
|||||||
let block: CaptureBlock = call.req(engine_state, stack, 0)?;
|
let block: CaptureBlock = call.req(engine_state, stack, 0)?;
|
||||||
let rest: Vec<Value> = call.rest(engine_state, stack, 1)?;
|
let rest: Vec<Value> = call.rest(engine_state, stack, 1)?;
|
||||||
let ignore_errors = call.has_flag("ignore-errors");
|
let ignore_errors = call.has_flag("ignore-errors");
|
||||||
|
let capture_errors = call.has_flag("capture-errors");
|
||||||
|
|
||||||
let mut stack = stack.captures_to_stack(&block.captures);
|
let mut stack = stack.captures_to_stack(&block.captures);
|
||||||
let block = engine_state.get_block(block.block_id);
|
let block = engine_state.get_block(block.block_id);
|
||||||
@ -85,7 +93,7 @@ impl Command for Do {
|
|||||||
block,
|
block,
|
||||||
input,
|
input,
|
||||||
call.redirect_stdout,
|
call.redirect_stdout,
|
||||||
ignore_errors,
|
ignore_errors || capture_errors,
|
||||||
);
|
);
|
||||||
|
|
||||||
if ignore_errors {
|
if ignore_errors {
|
||||||
@ -93,6 +101,11 @@ impl Command for Do {
|
|||||||
Ok(x) => Ok(x),
|
Ok(x) => Ok(x),
|
||||||
Err(_) => Ok(PipelineData::new(call.head)),
|
Err(_) => Ok(PipelineData::new(call.head)),
|
||||||
}
|
}
|
||||||
|
} else if capture_errors {
|
||||||
|
match result {
|
||||||
|
Ok(x) => Ok(x),
|
||||||
|
Err(err) => Ok((Value::Error { error: err }).into_pipeline_data()),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,10 @@ impl Command for Echo {
|
|||||||
.category(Category::Core)
|
.category(Category::Core)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
"Unlike `print`, this command returns an actual value that will be passed to the next command of the pipeline."
|
||||||
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -2,8 +2,7 @@ use nu_engine::CallExt;
|
|||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
|
||||||
Value,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -16,7 +15,7 @@ impl Command for ErrorMake {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("error make")
|
Signature::build("error make")
|
||||||
.optional("error_struct", SyntaxShape::Record, "the error to create")
|
.required("error_struct", SyntaxShape::Record, "the error to create")
|
||||||
.category(Category::Core)
|
.category(Category::Core)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,43 +32,20 @@ impl Command for ErrorMake {
|
|||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
let span = call.head;
|
let span = call.head;
|
||||||
let ctrlc = engine_state.ctrlc.clone();
|
let arg: Value = call.req(engine_state, stack, 0)?;
|
||||||
let arg: Option<Value> = call.opt(engine_state, stack, 0)?;
|
|
||||||
|
|
||||||
if let Some(arg) = arg {
|
Err(make_error(&arg, span).unwrap_or_else(|| {
|
||||||
Ok(make_error(&arg, span)
|
ShellError::GenericError(
|
||||||
.map(|err| Value::Error { error: err })
|
"Creating error value not supported.".into(),
|
||||||
.unwrap_or_else(|| Value::Error {
|
"unsupported error format".into(),
|
||||||
error: ShellError::GenericError(
|
Some(span),
|
||||||
"Creating error value not supported.".into(),
|
None,
|
||||||
"unsupported error format".into(),
|
Vec::new(),
|
||||||
Some(span),
|
|
||||||
None,
|
|
||||||
Vec::new(),
|
|
||||||
),
|
|
||||||
})
|
|
||||||
.into_pipeline_data())
|
|
||||||
} else {
|
|
||||||
input.map(
|
|
||||||
move |value| {
|
|
||||||
make_error(&value, span)
|
|
||||||
.map(|err| Value::Error { error: err })
|
|
||||||
.unwrap_or_else(|| Value::Error {
|
|
||||||
error: ShellError::GenericError(
|
|
||||||
"Creating error value not supported.".into(),
|
|
||||||
"unsupported error format".into(),
|
|
||||||
Some(span),
|
|
||||||
None,
|
|
||||||
Vec::new(),
|
|
||||||
),
|
|
||||||
})
|
|
||||||
},
|
|
||||||
ctrlc,
|
|
||||||
)
|
)
|
||||||
}
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -28,7 +28,33 @@ impl Command for ExportDefEnv {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nushell.html
|
||||||
|
|
||||||
|
=== EXTRA NOTE ===
|
||||||
|
All blocks are scoped, including variable definition and environment variable changes.
|
||||||
|
|
||||||
|
Because of this, the following doesn't work:
|
||||||
|
|
||||||
|
export def-env cd_with_fallback [arg = ""] {
|
||||||
|
let fall_back_path = "/tmp"
|
||||||
|
if $arg != "" {
|
||||||
|
cd $arg
|
||||||
|
} else {
|
||||||
|
cd $fall_back_path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Instead, you have to use cd in the top level scope:
|
||||||
|
|
||||||
|
export def-env cd_with_fallback [arg = ""] {
|
||||||
|
let fall_back_path = "/tmp"
|
||||||
|
let path = if $arg != "" {
|
||||||
|
$arg
|
||||||
|
} else {
|
||||||
|
$fall_back_path
|
||||||
|
}
|
||||||
|
cd $path
|
||||||
|
}"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
@ -1,131 +0,0 @@
|
|||||||
use nu_protocol::ast::Call;
|
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
|
||||||
use nu_protocol::{
|
|
||||||
Category, Example, HistoryFileFormat, IntoInterruptiblePipelineData, PipelineData, ShellError,
|
|
||||||
Signature, Value,
|
|
||||||
};
|
|
||||||
use reedline::{
|
|
||||||
FileBackedHistory, History as ReedlineHistory, SearchDirection, SearchQuery,
|
|
||||||
SqliteBackedHistory,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct History;
|
|
||||||
|
|
||||||
impl Command for History {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"history"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Get the command history"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> nu_protocol::Signature {
|
|
||||||
Signature::build("history")
|
|
||||||
.switch("clear", "Clears out the history entries", Some('c'))
|
|
||||||
.category(Category::Core)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
engine_state: &EngineState,
|
|
||||||
_stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
|
||||||
let head = call.head;
|
|
||||||
// todo for sqlite history this command should be an alias to `open ~/.config/nushell/history.sqlite3 | get history`
|
|
||||||
if let Some(config_path) = nu_path::config_dir() {
|
|
||||||
let clear = call.has_flag("clear");
|
|
||||||
let ctrlc = engine_state.ctrlc.clone();
|
|
||||||
|
|
||||||
let mut history_path = config_path;
|
|
||||||
history_path.push("nushell");
|
|
||||||
match engine_state.config.history_file_format {
|
|
||||||
HistoryFileFormat::Sqlite => {
|
|
||||||
history_path.push("history.sqlite3");
|
|
||||||
}
|
|
||||||
HistoryFileFormat::PlainText => {
|
|
||||||
history_path.push("history.txt");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if clear {
|
|
||||||
let _ = std::fs::remove_file(history_path);
|
|
||||||
// TODO: FIXME also clear the auxiliary files when using sqlite
|
|
||||||
Ok(PipelineData::new(head))
|
|
||||||
} else {
|
|
||||||
let history_reader: Option<Box<dyn ReedlineHistory>> =
|
|
||||||
match engine_state.config.history_file_format {
|
|
||||||
HistoryFileFormat::Sqlite => SqliteBackedHistory::with_file(history_path)
|
|
||||||
.map(|inner| {
|
|
||||||
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
|
|
||||||
boxed
|
|
||||||
})
|
|
||||||
.ok(),
|
|
||||||
|
|
||||||
HistoryFileFormat::PlainText => FileBackedHistory::with_file(
|
|
||||||
engine_state.config.max_history_size as usize,
|
|
||||||
history_path,
|
|
||||||
)
|
|
||||||
.map(|inner| {
|
|
||||||
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
|
|
||||||
boxed
|
|
||||||
})
|
|
||||||
.ok(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let data = history_reader
|
|
||||||
.and_then(|h| {
|
|
||||||
h.search(SearchQuery::everything(SearchDirection::Forward))
|
|
||||||
.ok()
|
|
||||||
})
|
|
||||||
.map(move |entries| {
|
|
||||||
entries
|
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(move |(idx, entry)| Value::Record {
|
|
||||||
cols: vec!["command".to_string(), "index".to_string()],
|
|
||||||
vals: vec![
|
|
||||||
Value::String {
|
|
||||||
val: entry.command_line,
|
|
||||||
span: head,
|
|
||||||
},
|
|
||||||
Value::Int {
|
|
||||||
val: idx as i64,
|
|
||||||
span: head,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
span: head,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.ok_or(ShellError::FileNotFound(head))?
|
|
||||||
.into_pipeline_data(ctrlc);
|
|
||||||
Ok(data)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(ShellError::FileNotFound(head))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![
|
|
||||||
Example {
|
|
||||||
example: "history | length",
|
|
||||||
description: "Get current history length",
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
example: "history | last 5",
|
|
||||||
description: "Show last 5 commands you have ran",
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
example: "history | wrap cmd | where cmd =~ cargo",
|
|
||||||
description: "Search all the commands from history that contains 'cargo'",
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,7 +16,6 @@ mod extern_;
|
|||||||
mod for_;
|
mod for_;
|
||||||
mod help;
|
mod help;
|
||||||
mod hide;
|
mod hide;
|
||||||
mod history;
|
|
||||||
mod if_;
|
mod if_;
|
||||||
mod ignore;
|
mod ignore;
|
||||||
mod let_;
|
mod let_;
|
||||||
@ -24,7 +23,6 @@ mod metadata;
|
|||||||
mod module;
|
mod module;
|
||||||
pub(crate) mod overlay;
|
pub(crate) mod overlay;
|
||||||
mod source;
|
mod source;
|
||||||
mod tutor;
|
|
||||||
mod use_;
|
mod use_;
|
||||||
mod version;
|
mod version;
|
||||||
|
|
||||||
@ -46,7 +44,6 @@ pub use extern_::Extern;
|
|||||||
pub use for_::For;
|
pub use for_::For;
|
||||||
pub use help::Help;
|
pub use help::Help;
|
||||||
pub use hide::Hide;
|
pub use hide::Hide;
|
||||||
pub use history::History;
|
|
||||||
pub use if_::If;
|
pub use if_::If;
|
||||||
pub use ignore::Ignore;
|
pub use ignore::Ignore;
|
||||||
pub use let_::Let;
|
pub use let_::Let;
|
||||||
@ -54,7 +51,6 @@ pub use metadata::Metadata;
|
|||||||
pub use module::Module;
|
pub use module::Module;
|
||||||
pub use overlay::*;
|
pub use overlay::*;
|
||||||
pub use source::Source;
|
pub use source::Source;
|
||||||
pub use tutor::Tutor;
|
|
||||||
pub use use_::Use;
|
pub use use_::Use;
|
||||||
pub use version::Version;
|
pub use version::Version;
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
use crate::{
|
use crate::SQLiteDatabase;
|
||||||
database::values::dsl::{ExprDb, SelectDb},
|
|
||||||
SQLiteDatabase,
|
|
||||||
};
|
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape,
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||||
|
Type, Value,
|
||||||
};
|
};
|
||||||
use sqlparser::ast::{Ident, SelectItem, SetExpr, Statement, TableAlias, TableFactor};
|
use sqlparser::ast::{Ident, SetExpr, Statement, TableAlias, TableFactor};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AliasExpr;
|
pub struct AliasDb;
|
||||||
|
|
||||||
impl Command for AliasExpr {
|
impl Command for AliasDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"db as"
|
"as"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name())
|
Signature::build(self.name())
|
||||||
.required("alias", SyntaxShape::String, "alias name")
|
.required("alias", SyntaxShape::String, "alias name")
|
||||||
|
.input_type(Type::Custom("database".into()))
|
||||||
|
.output_type(Type::Custom("database".into()))
|
||||||
.category(Category::Custom("database".into()))
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,11 +29,59 @@ impl Command for AliasExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![
|
||||||
description: "Creates an alias for a column selection",
|
Example {
|
||||||
example: "db col name_a | db as new_a",
|
description: "Creates an alias for a selected table",
|
||||||
result: None,
|
example: r#"open db.mysql
|
||||||
}]
|
| into db
|
||||||
|
| select a
|
||||||
|
| from table_1
|
||||||
|
| as t1
|
||||||
|
| describe"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT a FROM table_1 AS t1".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Creates an alias for a derived table",
|
||||||
|
example: r#"open db.mysql
|
||||||
|
| into db
|
||||||
|
| select a
|
||||||
|
| from (
|
||||||
|
open db.mysql
|
||||||
|
| into db
|
||||||
|
| select a b
|
||||||
|
| from table_a
|
||||||
|
)
|
||||||
|
| as t1
|
||||||
|
| describe"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT a FROM (SELECT a, b FROM table_a) AS t1".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
@ -48,52 +96,12 @@ impl Command for AliasExpr {
|
|||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let alias: String = call.req(engine_state, stack, 0)?;
|
let alias: String = call.req(engine_state, stack, 0)?;
|
||||||
let value = input.into_value(call.head);
|
|
||||||
|
|
||||||
if let Ok(expr) = ExprDb::try_from_value(&value) {
|
let db = SQLiteDatabase::try_from_pipeline(input, call.head)?;
|
||||||
alias_selection(expr.into_native().into(), alias, call)
|
alias_db(db, alias, call)
|
||||||
} else if let Ok(select) = SelectDb::try_from_value(&value) {
|
|
||||||
alias_selection(select, alias, call)
|
|
||||||
} else if let Ok(db) = SQLiteDatabase::try_from_value(value.clone()) {
|
|
||||||
alias_db(db, alias, call)
|
|
||||||
} else {
|
|
||||||
Err(ShellError::CantConvert(
|
|
||||||
"expression or query".into(),
|
|
||||||
value.get_type().to_string(),
|
|
||||||
value.span()?,
|
|
||||||
None,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alias_selection(
|
|
||||||
select: SelectDb,
|
|
||||||
alias: String,
|
|
||||||
call: &Call,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
let select = match select.into_native() {
|
|
||||||
SelectItem::UnnamedExpr(expr) => SelectItem::ExprWithAlias {
|
|
||||||
expr,
|
|
||||||
alias: Ident {
|
|
||||||
value: alias,
|
|
||||||
quote_style: None,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
SelectItem::ExprWithAlias { expr, .. } => SelectItem::ExprWithAlias {
|
|
||||||
expr,
|
|
||||||
alias: Ident {
|
|
||||||
value: alias,
|
|
||||||
quote_style: None,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
select => select,
|
|
||||||
};
|
|
||||||
|
|
||||||
let select: SelectDb = select.into();
|
|
||||||
Ok(select.into_value(call.head).into_pipeline_data())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn alias_db(
|
fn alias_db(
|
||||||
mut db: SQLiteDatabase,
|
mut db: SQLiteDatabase,
|
||||||
new_alias: String,
|
new_alias: String,
|
||||||
@ -142,7 +150,7 @@ fn alias_db(
|
|||||||
},
|
},
|
||||||
s => {
|
s => {
|
||||||
return Err(ShellError::GenericError(
|
return Err(ShellError::GenericError(
|
||||||
"Connection doesnt define a query".into(),
|
"Connection doesn't define a query".into(),
|
||||||
format!("Expected a connection with query. Got {}", s),
|
format!("Expected a connection with query. Got {}", s),
|
||||||
Some(call.head),
|
Some(call.head),
|
||||||
None,
|
None,
|
||||||
@ -152,3 +160,19 @@ fn alias_db(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::{FromDb, ProjectionDb};
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![
|
||||||
|
Box::new(AliasDb {}),
|
||||||
|
Box::new(ProjectionDb {}),
|
||||||
|
Box::new(FromDb {}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,7 +6,7 @@ use nu_protocol::{
|
|||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||||
Value,
|
Type, Value,
|
||||||
};
|
};
|
||||||
use sqlparser::ast::{BinaryOperator, Expr, Query, Select, SetExpr, Statement};
|
use sqlparser::ast::{BinaryOperator, Expr, Query, Select, SetExpr, Statement};
|
||||||
|
|
||||||
@ -15,16 +15,18 @@ pub struct AndDb;
|
|||||||
|
|
||||||
impl Command for AndDb {
|
impl Command for AndDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"db and"
|
"and"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"Includes an AND clause for a query or expression"
|
"Includes an AND clause for a query"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name())
|
Signature::build(self.name())
|
||||||
.required("where", SyntaxShape::Any, "Where expression on the table")
|
.required("where", SyntaxShape::Any, "Where expression on the table")
|
||||||
|
.input_type(Type::Custom("database".into()))
|
||||||
|
.output_type(Type::Custom("database".into()))
|
||||||
.category(Category::Custom("database".into()))
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,23 +37,52 @@ impl Command for AndDb {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "selects a column from a database with a where clause",
|
description: "Selects a column from a database with an AND clause",
|
||||||
example: r#"db open db.mysql
|
example: r#"open db.mysql
|
||||||
| db select a
|
| into db
|
||||||
| db from table_1
|
| select a
|
||||||
| db where ((db col a) > 1)
|
| from table_1
|
||||||
| db and ((db col b) == 1)
|
| where ((field a) > 1)
|
||||||
| db describe"#,
|
| and ((field b) == 1)
|
||||||
result: None,
|
| describe"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT a FROM table_1 WHERE a > 1 AND b = 1".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Creates a nested where clause",
|
description: "Creates a AND clause combined with an expression AND",
|
||||||
example: r#"db open db.mysql
|
example: r#"open db.mysql
|
||||||
| db select a
|
| into db
|
||||||
| db from table_1
|
| select a
|
||||||
| db where ((db col a) > 1 | db and ((db col a) < 10))
|
| from table_1
|
||||||
| db describe"#,
|
| where ((field a) > 1 | and ((field a) < 10))
|
||||||
result: None,
|
| and ((field b) == 1)
|
||||||
|
| describe"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT a FROM table_1 WHERE (a > 1 AND a < 10) AND b = 1".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -66,51 +97,32 @@ impl Command for AndDb {
|
|||||||
let value: Value = call.req(engine_state, stack, 0)?;
|
let value: Value = call.req(engine_state, stack, 0)?;
|
||||||
let expr = ExprDb::try_from_value(&value)?.into_native();
|
let expr = ExprDb::try_from_value(&value)?.into_native();
|
||||||
|
|
||||||
let value = input.into_value(call.head);
|
let mut db = SQLiteDatabase::try_from_pipeline(input, call.head)?;
|
||||||
if let Ok(expression) = ExprDb::try_from_value(&value) {
|
match db.statement.as_mut() {
|
||||||
let expression = Expr::BinaryOp {
|
Some(statement) => match statement {
|
||||||
left: Box::new(expression.into_native()),
|
Statement::Query(query) => modify_query(query, expr, call.head)?,
|
||||||
op: BinaryOperator::And,
|
s => {
|
||||||
right: Box::new(expr),
|
|
||||||
};
|
|
||||||
|
|
||||||
let expression: ExprDb = Expr::Nested(Box::new(expression)).into();
|
|
||||||
|
|
||||||
Ok(expression.into_value(call.head).into_pipeline_data())
|
|
||||||
} else if let Ok(mut db) = SQLiteDatabase::try_from_value(value.clone()) {
|
|
||||||
match db.statement.as_mut() {
|
|
||||||
Some(statement) => match statement {
|
|
||||||
Statement::Query(query) => modify_query(query, expr, call.head)?,
|
|
||||||
s => {
|
|
||||||
return Err(ShellError::GenericError(
|
|
||||||
"Connection doesnt define a query".into(),
|
|
||||||
format!("Expected a connection with query. Got {}", s),
|
|
||||||
Some(call.head),
|
|
||||||
None,
|
|
||||||
Vec::new(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
return Err(ShellError::GenericError(
|
return Err(ShellError::GenericError(
|
||||||
"Connection without statement".into(),
|
"Connection doesn't define a query".into(),
|
||||||
"The connection needs a statement defined".into(),
|
format!("Expected a connection with query. Got {}", s),
|
||||||
Some(call.head),
|
Some(call.head),
|
||||||
None,
|
None,
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
None => {
|
||||||
|
return Err(ShellError::GenericError(
|
||||||
|
"Connection without statement".into(),
|
||||||
|
"The connection needs a statement defined".into(),
|
||||||
|
Some(call.head),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(db.into_value(call.head).into_pipeline_data())
|
Ok(db.into_value(call.head).into_pipeline_data())
|
||||||
} else {
|
|
||||||
Err(ShellError::CantConvert(
|
|
||||||
"expression or query".into(),
|
|
||||||
value.get_type().to_string(),
|
|
||||||
value.span()?,
|
|
||||||
None,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,3 +162,23 @@ fn modify_select(select: &mut Box<Select>, expression: Expr, span: Span) -> Resu
|
|||||||
select.as_mut().selection = Some(new_expression);
|
select.as_mut().selection = Some(new_expression);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::super::expressions::{AndExpr, FieldExpr};
|
||||||
|
use super::super::{FromDb, ProjectionDb, WhereDb};
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![
|
||||||
|
Box::new(AndDb {}),
|
||||||
|
Box::new(ProjectionDb {}),
|
||||||
|
Box::new(FromDb {}),
|
||||||
|
Box::new(WhereDb {}),
|
||||||
|
Box::new(FieldExpr {}),
|
||||||
|
Box::new(AndExpr {}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
use crate::database::values::dsl::ExprDb;
|
|
||||||
use nu_engine::CallExt;
|
|
||||||
use nu_protocol::{
|
|
||||||
ast::Call,
|
|
||||||
engine::{Command, EngineState, Stack},
|
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ColExpr;
|
|
||||||
|
|
||||||
impl Command for ColExpr {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"db col"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build(self.name())
|
|
||||||
.required("name", SyntaxShape::String, "column name")
|
|
||||||
.category(Category::Custom("database".into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Creates column expression for database"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![Example {
|
|
||||||
description: "Creates a named column expression",
|
|
||||||
example: "db col name_1",
|
|
||||||
result: None,
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
|
||||||
vec!["database", "column", "expression"]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
let value: Value = call.req(engine_state, stack, 0)?;
|
|
||||||
let expression = ExprDb::try_from_value(&value)?;
|
|
||||||
|
|
||||||
Ok(expression.into_value(call.head).into_pipeline_data())
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature,
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::super::SQLiteDatabase;
|
use super::super::SQLiteDatabase;
|
||||||
@ -11,21 +11,24 @@ pub struct CollectDb;
|
|||||||
|
|
||||||
impl Command for CollectDb {
|
impl Command for CollectDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"db collect"
|
"collect"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name()).category(Category::Custom("database".into()))
|
Signature::build(self.name())
|
||||||
|
.input_type(Type::Custom("database".into()))
|
||||||
|
.output_type(Type::Any)
|
||||||
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"Query a database using SQL."
|
"Collects a query from a database database connection"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Collect from a select query",
|
description: "Collect from a select query",
|
||||||
example: "open foo.db | db select a | db from table_1 | db collect",
|
example: "open foo.db | into db | select a | from table_1 | collect",
|
||||||
result: None,
|
result: None,
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
use nu_engine::get_full_help;
|
|
||||||
use nu_protocol::{
|
|
||||||
ast::Call,
|
|
||||||
engine::{Command, EngineState, Stack},
|
|
||||||
Category, IntoPipelineData, PipelineData, ShellError, Signature, Value,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Database;
|
|
||||||
|
|
||||||
impl Command for Database {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"db"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Database commands"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build(self.name()).category(Category::Custom("database".into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
Ok(Value::String {
|
|
||||||
val: get_full_help(
|
|
||||||
&Database.signature(),
|
|
||||||
&Database.examples(),
|
|
||||||
engine_state,
|
|
||||||
stack,
|
|
||||||
),
|
|
||||||
span: call.head,
|
|
||||||
}
|
|
||||||
.into_pipeline_data())
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature,
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::super::SQLiteDatabase;
|
use super::super::SQLiteDatabase;
|
||||||
@ -11,11 +11,14 @@ pub struct DescribeDb;
|
|||||||
|
|
||||||
impl Command for DescribeDb {
|
impl Command for DescribeDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"db describe"
|
"describe"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name()).category(Category::Custom("database".into()))
|
Signature::build(self.name())
|
||||||
|
.input_type(Type::Custom("database".into()))
|
||||||
|
.output_type(Type::Any)
|
||||||
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -25,13 +28,26 @@ impl Command for DescribeDb {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Describe SQLite database constructed query",
|
description: "Describe SQLite database constructed query",
|
||||||
example: "db open foo.db | db select table_1 | db describe",
|
example: "open foo.db | into db | select col_1 | from table_1 | describe",
|
||||||
result: None,
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "foo.db".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT col_1 FROM table_1".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["database", "SQLite"]
|
vec!["database", "SQLite", "describe"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
@ -45,3 +61,19 @@ impl Command for DescribeDb {
|
|||||||
Ok(db.describe(call.head).into_pipeline_data())
|
Ok(db.describe(call.head).into_pipeline_data())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::{FromDb, ProjectionDb};
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![
|
||||||
|
Box::new(DescribeDb {}),
|
||||||
|
Box::new(ProjectionDb {}),
|
||||||
|
Box::new(FromDb {}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,7 +5,8 @@ use nu_engine::CallExt;
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||||
|
Type, Value,
|
||||||
};
|
};
|
||||||
use sqlparser::ast::{Ident, Query, Select, SetExpr, Statement, TableAlias, TableWithJoins};
|
use sqlparser::ast::{Ident, Query, Select, SetExpr, Statement, TableAlias, TableWithJoins};
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ pub struct FromDb;
|
|||||||
|
|
||||||
impl Command for FromDb {
|
impl Command for FromDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"db from"
|
"from"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -34,6 +35,8 @@ impl Command for FromDb {
|
|||||||
"Alias for the selected table",
|
"Alias for the selected table",
|
||||||
Some('a'),
|
Some('a'),
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("database".into()))
|
||||||
|
.output_type(Type::Custom("database".into()))
|
||||||
.category(Category::Custom("database".into()))
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,9 +46,22 @@ impl Command for FromDb {
|
|||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Selects table from database",
|
description: "Selects a table from database",
|
||||||
example: "db open db.mysql | db from table_a",
|
example: "open db.mysql | into db | from table_a | describe",
|
||||||
result: None,
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT FROM table_a".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,3 +196,14 @@ fn create_table(
|
|||||||
|
|
||||||
Ok(table)
|
Ok(table)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![Box::new(FromDb {})])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
use crate::database::values::dsl::ExprDb;
|
|
||||||
use nu_engine::CallExt;
|
|
||||||
use nu_protocol::{
|
|
||||||
ast::Call,
|
|
||||||
engine::{Command, EngineState, Stack},
|
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
|
|
||||||
};
|
|
||||||
use sqlparser::ast::{Expr, Function, FunctionArg, FunctionArgExpr, Ident, ObjectName};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct FunctionExpr;
|
|
||||||
|
|
||||||
impl Command for FunctionExpr {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"db fn"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build(self.name())
|
|
||||||
.required("name", SyntaxShape::String, "function name")
|
|
||||||
.switch("distinct", "distict values", Some('d'))
|
|
||||||
.rest("arguments", SyntaxShape::Any, "function arguments")
|
|
||||||
.category(Category::Custom("database".into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Creates function expression for a select operation"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![Example {
|
|
||||||
description: "Creates a function expression",
|
|
||||||
example: "db fn count name_1",
|
|
||||||
result: None,
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
|
||||||
vec!["database", "function", "expression"]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
let name: String = call.req(engine_state, stack, 0)?;
|
|
||||||
let vals: Vec<Value> = call.rest(engine_state, stack, 1)?;
|
|
||||||
let value = Value::List {
|
|
||||||
vals,
|
|
||||||
span: call.head,
|
|
||||||
};
|
|
||||||
let expressions = ExprDb::extract_exprs(value)?;
|
|
||||||
|
|
||||||
let name: Vec<Ident> = name
|
|
||||||
.split('.')
|
|
||||||
.map(|part| Ident {
|
|
||||||
value: part.to_string(),
|
|
||||||
quote_style: None,
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let name = ObjectName(name);
|
|
||||||
|
|
||||||
let args: Vec<FunctionArg> = expressions
|
|
||||||
.into_iter()
|
|
||||||
.map(|expr| {
|
|
||||||
let arg = FunctionArgExpr::Expr(expr);
|
|
||||||
|
|
||||||
FunctionArg::Unnamed(arg)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let expression: ExprDb = Expr::Function(Function {
|
|
||||||
name,
|
|
||||||
args,
|
|
||||||
over: None,
|
|
||||||
distinct: call.has_flag("distinct"),
|
|
||||||
})
|
|
||||||
.into();
|
|
||||||
|
|
||||||
Ok(expression.into_value(call.head).into_pipeline_data())
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,7 +5,8 @@ use nu_engine::CallExt;
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||||
|
Type, Value,
|
||||||
};
|
};
|
||||||
use sqlparser::ast::{SetExpr, Statement};
|
use sqlparser::ast::{SetExpr, Statement};
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ pub struct GroupByDb;
|
|||||||
|
|
||||||
impl Command for GroupByDb {
|
impl Command for GroupByDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"db group-by"
|
"group-by"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -28,6 +29,8 @@ impl Command for GroupByDb {
|
|||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
"Select expression(s) on the table",
|
"Select expression(s) on the table",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("database".into()))
|
||||||
|
.output_type(Type::Custom("database".into()))
|
||||||
.category(Category::Custom("database".into()))
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,15 +39,54 @@ impl Command for GroupByDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![
|
||||||
description: "orders query by a column",
|
Example {
|
||||||
example: r#"db open db.mysql
|
description: "groups by column a and calculates the max",
|
||||||
| db from table_a
|
example: r#"open db.mysql
|
||||||
| db select a
|
| into db
|
||||||
| db group-by a
|
| from table_a
|
||||||
| db describe"#,
|
| select (fn max a)
|
||||||
result: None,
|
| group-by a
|
||||||
}]
|
| describe"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT max(a) FROM table_a GROUP BY a".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "groups by column column a and counts records",
|
||||||
|
example: r#"open db.mysql
|
||||||
|
| into db
|
||||||
|
| from table_a
|
||||||
|
| select (fn count *)
|
||||||
|
| group-by a
|
||||||
|
| describe"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT count(*) FROM table_a GROUP BY a".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
@ -100,3 +142,24 @@ impl Command for GroupByDb {
|
|||||||
Ok(db.into_value(call.head).into_pipeline_data())
|
Ok(db.into_value(call.head).into_pipeline_data())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::super::expressions::{FieldExpr, FunctionExpr, OrExpr};
|
||||||
|
use super::super::{FromDb, ProjectionDb, WhereDb};
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![
|
||||||
|
Box::new(GroupByDb {}),
|
||||||
|
Box::new(ProjectionDb {}),
|
||||||
|
Box::new(FunctionExpr {}),
|
||||||
|
Box::new(FromDb {}),
|
||||||
|
Box::new(WhereDb {}),
|
||||||
|
Box::new(FieldExpr {}),
|
||||||
|
Box::new(OrExpr {}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,7 +4,8 @@ use nu_engine::CallExt;
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||||
|
Type, Value,
|
||||||
};
|
};
|
||||||
use sqlparser::ast::{
|
use sqlparser::ast::{
|
||||||
Ident, Join, JoinConstraint, JoinOperator, Select, SetExpr, Statement, TableAlias,
|
Ident, Join, JoinConstraint, JoinOperator, Select, SetExpr, Statement, TableAlias,
|
||||||
@ -15,7 +16,7 @@ pub struct JoinDb;
|
|||||||
|
|
||||||
impl Command for JoinDb {
|
impl Command for JoinDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"db join"
|
"join"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -40,6 +41,8 @@ impl Command for JoinDb {
|
|||||||
.switch("right", "right outer join", Some('r'))
|
.switch("right", "right outer join", Some('r'))
|
||||||
.switch("outer", "full outer join", Some('o'))
|
.switch("outer", "full outer join", Some('o'))
|
||||||
.switch("cross", "cross join", Some('c'))
|
.switch("cross", "cross join", Some('c'))
|
||||||
|
.input_type(Type::Custom("database".into()))
|
||||||
|
.output_type(Type::Custom("database".into()))
|
||||||
.category(Category::Custom("database".into()))
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,11 +51,61 @@ impl Command for JoinDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![
|
||||||
description: "",
|
Example {
|
||||||
example: "",
|
description: "joins two tables on col_b",
|
||||||
result: None,
|
example: r#"open db.mysql
|
||||||
}]
|
| into db
|
||||||
|
| select col_a
|
||||||
|
| from table_1 --as t1
|
||||||
|
| join table_2 col_b --as t2
|
||||||
|
| describe"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT col_a FROM table_1 AS t1 JOIN table_2 AS t2 ON col_b"
|
||||||
|
.into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "joins a table with a derived table using aliases",
|
||||||
|
example: r#"open db.mysql
|
||||||
|
| into db
|
||||||
|
| select col_a
|
||||||
|
| from table_1 --as t1
|
||||||
|
| join (
|
||||||
|
open db.mysql
|
||||||
|
| into db
|
||||||
|
| select col_c
|
||||||
|
| from table_2
|
||||||
|
) ((field t1.col_a) == (field t2.col_c)) --as t2 --right
|
||||||
|
| describe"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT col_a FROM table_1 AS t1 RIGHT JOIN (SELECT col_c FROM table_2) AS t2 ON t1.col_a = t2.col_c"
|
||||||
|
.into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
@ -176,3 +229,23 @@ fn modify_from(
|
|||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::super::expressions::{FieldExpr, OrExpr};
|
||||||
|
use super::super::{FromDb, ProjectionDb, WhereDb};
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![
|
||||||
|
Box::new(JoinDb {}),
|
||||||
|
Box::new(ProjectionDb {}),
|
||||||
|
Box::new(FromDb {}),
|
||||||
|
Box::new(WhereDb {}),
|
||||||
|
Box::new(FieldExpr {}),
|
||||||
|
Box::new(OrExpr {}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,7 +4,8 @@ use nu_engine::CallExt;
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||||
|
Type, Value,
|
||||||
};
|
};
|
||||||
use sqlparser::ast::Statement;
|
use sqlparser::ast::Statement;
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ pub struct LimitDb;
|
|||||||
|
|
||||||
impl Command for LimitDb {
|
impl Command for LimitDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"db limit"
|
"limit"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -27,6 +28,8 @@ impl Command for LimitDb {
|
|||||||
SyntaxShape::Int,
|
SyntaxShape::Int,
|
||||||
"Number of rows to extract for query",
|
"Number of rows to extract for query",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("database".into()))
|
||||||
|
.output_type(Type::Custom("database".into()))
|
||||||
.category(Category::Custom("database".into()))
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,12 +40,26 @@ impl Command for LimitDb {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Limits selection from table",
|
description: "Limits selection from table",
|
||||||
example: r#"db open db.mysql
|
example: r#"open db.mysql
|
||||||
| db from table_a
|
| into db
|
||||||
| db select a
|
| from table_a
|
||||||
| db limit 10
|
| select a
|
||||||
| db describe"#,
|
| limit 10
|
||||||
result: None,
|
| describe"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT a FROM table_a LIMIT 10".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,3 +101,23 @@ impl Command for LimitDb {
|
|||||||
Ok(db.into_value(call.head).into_pipeline_data())
|
Ok(db.into_value(call.head).into_pipeline_data())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::super::expressions::{FieldExpr, OrExpr};
|
||||||
|
use super::super::{FromDb, ProjectionDb, WhereDb};
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![
|
||||||
|
Box::new(LimitDb {}),
|
||||||
|
Box::new(ProjectionDb {}),
|
||||||
|
Box::new(FromDb {}),
|
||||||
|
Box::new(WhereDb {}),
|
||||||
|
Box::new(FieldExpr {}),
|
||||||
|
Box::new(OrExpr {}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,22 +3,19 @@ pub mod conversions;
|
|||||||
|
|
||||||
mod alias;
|
mod alias;
|
||||||
mod and;
|
mod and;
|
||||||
mod col;
|
|
||||||
mod collect;
|
mod collect;
|
||||||
mod command;
|
|
||||||
mod describe;
|
mod describe;
|
||||||
mod from;
|
mod from;
|
||||||
mod function;
|
|
||||||
mod group_by;
|
mod group_by;
|
||||||
mod join;
|
mod join;
|
||||||
mod limit;
|
mod limit;
|
||||||
mod open;
|
mod open;
|
||||||
mod or;
|
mod or;
|
||||||
mod order_by;
|
mod order_by;
|
||||||
mod over;
|
|
||||||
mod query;
|
mod query;
|
||||||
mod schema;
|
mod schema;
|
||||||
mod select;
|
mod select;
|
||||||
|
mod to_db;
|
||||||
mod where_;
|
mod where_;
|
||||||
|
|
||||||
// Temporal module to create Query objects
|
// Temporal module to create Query objects
|
||||||
@ -27,27 +24,24 @@ use testing::TestingDb;
|
|||||||
|
|
||||||
use nu_protocol::engine::StateWorkingSet;
|
use nu_protocol::engine::StateWorkingSet;
|
||||||
|
|
||||||
use alias::AliasExpr;
|
use alias::AliasDb;
|
||||||
use and::AndDb;
|
use and::AndDb;
|
||||||
use col::ColExpr;
|
|
||||||
use collect::CollectDb;
|
use collect::CollectDb;
|
||||||
use command::Database;
|
pub(crate) use describe::DescribeDb;
|
||||||
use describe::DescribeDb;
|
pub(crate) use from::FromDb;
|
||||||
use from::FromDb;
|
|
||||||
use function::FunctionExpr;
|
|
||||||
use group_by::GroupByDb;
|
use group_by::GroupByDb;
|
||||||
use join::JoinDb;
|
use join::JoinDb;
|
||||||
use limit::LimitDb;
|
use limit::LimitDb;
|
||||||
use open::OpenDb;
|
use open::OpenDb;
|
||||||
use or::OrDb;
|
use or::OrDb;
|
||||||
use order_by::OrderByDb;
|
use order_by::OrderByDb;
|
||||||
use over::OverExpr;
|
|
||||||
use query::QueryDb;
|
use query::QueryDb;
|
||||||
use schema::SchemaDb;
|
use schema::SchemaDb;
|
||||||
use select::ProjectionDb;
|
pub(crate) use select::ProjectionDb;
|
||||||
|
pub(crate) use to_db::ToDataBase;
|
||||||
use where_::WhereDb;
|
use where_::WhereDb;
|
||||||
|
|
||||||
pub fn add_database_decls(working_set: &mut StateWorkingSet) {
|
pub fn add_commands_decls(working_set: &mut StateWorkingSet) {
|
||||||
macro_rules! bind_command {
|
macro_rules! bind_command {
|
||||||
( $command:expr ) => {
|
( $command:expr ) => {
|
||||||
working_set.add_decl(Box::new($command));
|
working_set.add_decl(Box::new($command));
|
||||||
@ -59,21 +53,18 @@ pub fn add_database_decls(working_set: &mut StateWorkingSet) {
|
|||||||
|
|
||||||
// Series commands
|
// Series commands
|
||||||
bind_command!(
|
bind_command!(
|
||||||
AliasExpr,
|
ToDataBase,
|
||||||
|
AliasDb,
|
||||||
AndDb,
|
AndDb,
|
||||||
ColExpr,
|
|
||||||
CollectDb,
|
CollectDb,
|
||||||
Database,
|
|
||||||
DescribeDb,
|
DescribeDb,
|
||||||
FromDb,
|
FromDb,
|
||||||
FunctionExpr,
|
|
||||||
GroupByDb,
|
GroupByDb,
|
||||||
JoinDb,
|
JoinDb,
|
||||||
LimitDb,
|
LimitDb,
|
||||||
OpenDb,
|
OpenDb,
|
||||||
OrderByDb,
|
OrderByDb,
|
||||||
OrDb,
|
OrDb,
|
||||||
OverExpr,
|
|
||||||
QueryDb,
|
QueryDb,
|
||||||
ProjectionDb,
|
ProjectionDb,
|
||||||
SchemaDb,
|
SchemaDb,
|
||||||
|
@ -4,6 +4,7 @@ use nu_protocol::{
|
|||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Spanned, SyntaxShape,
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Spanned, SyntaxShape,
|
||||||
|
Type,
|
||||||
};
|
};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
@ -12,12 +13,14 @@ pub struct OpenDb;
|
|||||||
|
|
||||||
impl Command for OpenDb {
|
impl Command for OpenDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"db open"
|
"open-db"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name())
|
Signature::build(self.name())
|
||||||
.required("query", SyntaxShape::Filepath, "SQLite file to be opened")
|
.required("query", SyntaxShape::Filepath, "SQLite file to be opened")
|
||||||
|
.input_type(Type::Any)
|
||||||
|
.output_type(Type::Custom("database".into()))
|
||||||
.category(Category::Custom("database".into()))
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,8 +34,8 @@ impl Command for OpenDb {
|
|||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Open a sqlite file",
|
description: "Creates a connection to a sqlite database based on the file name",
|
||||||
example: r#"db open file.sqlite"#,
|
example: r#"open-db file.sqlite"#,
|
||||||
result: None,
|
result: None,
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use nu_protocol::{
|
|||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||||
Value,
|
Type, Value,
|
||||||
};
|
};
|
||||||
use sqlparser::ast::{BinaryOperator, Expr, Query, Select, SetExpr, Statement};
|
use sqlparser::ast::{BinaryOperator, Expr, Query, Select, SetExpr, Statement};
|
||||||
|
|
||||||
@ -15,16 +15,18 @@ pub struct OrDb;
|
|||||||
|
|
||||||
impl Command for OrDb {
|
impl Command for OrDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"db or"
|
"or"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"Includes an OR clause for a query or expression"
|
"Includes an OR clause for a query"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name())
|
Signature::build(self.name())
|
||||||
.required("where", SyntaxShape::Any, "Where expression on the table")
|
.required("where", SyntaxShape::Any, "Where expression on the table")
|
||||||
|
.input_type(Type::Custom("database".into()))
|
||||||
|
.output_type(Type::Custom("database".into()))
|
||||||
.category(Category::Custom("database".into()))
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,23 +37,52 @@ impl Command for OrDb {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "selects a column from a database with a where clause",
|
description: "selects a column from a database with an OR clause",
|
||||||
example: r#"db open db.mysql
|
example: r#"open db.mysql
|
||||||
| db select a
|
| into db
|
||||||
| db from table_1
|
| select a
|
||||||
| db where ((db col a) > 1)
|
| from table_1
|
||||||
| db or ((db col b) == 1)
|
| where ((field a) > 1)
|
||||||
| db describe"#,
|
| or ((field b) == 1)
|
||||||
result: None,
|
| describe"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT a FROM table_1 WHERE a > 1 OR b = 1".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Creates a nested where clause",
|
description: "Creates an OR clause in the column names and a column",
|
||||||
example: r#"db open db.mysql
|
example: r#"open db.mysql
|
||||||
| db select a
|
| into db
|
||||||
| db from table_1
|
| select a
|
||||||
| db where ((db col a) > 1 | db or ((db col a) < 10))
|
| from table_1
|
||||||
| db describe"#,
|
| where ((field a) > 1 | or ((field a) < 10))
|
||||||
result: None,
|
| or ((field b) == 1)
|
||||||
|
| describe"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT a FROM table_1 WHERE (a > 1 OR a < 10) OR b = 1".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -66,51 +97,32 @@ impl Command for OrDb {
|
|||||||
let value: Value = call.req(engine_state, stack, 0)?;
|
let value: Value = call.req(engine_state, stack, 0)?;
|
||||||
let expr = ExprDb::try_from_value(&value)?.into_native();
|
let expr = ExprDb::try_from_value(&value)?.into_native();
|
||||||
|
|
||||||
let value = input.into_value(call.head);
|
let mut db = SQLiteDatabase::try_from_pipeline(input, call.head)?;
|
||||||
if let Ok(expression) = ExprDb::try_from_value(&value) {
|
match db.statement {
|
||||||
let expression = Expr::BinaryOp {
|
Some(ref mut statement) => match statement {
|
||||||
left: Box::new(expression.into_native()),
|
Statement::Query(query) => modify_query(query, expr, call.head)?,
|
||||||
op: BinaryOperator::Or,
|
s => {
|
||||||
right: Box::new(expr),
|
|
||||||
};
|
|
||||||
|
|
||||||
let expression: ExprDb = Expr::Nested(Box::new(expression)).into();
|
|
||||||
|
|
||||||
Ok(expression.into_value(call.head).into_pipeline_data())
|
|
||||||
} else if let Ok(mut db) = SQLiteDatabase::try_from_value(value.clone()) {
|
|
||||||
match db.statement {
|
|
||||||
Some(ref mut statement) => match statement {
|
|
||||||
Statement::Query(query) => modify_query(query, expr, call.head)?,
|
|
||||||
s => {
|
|
||||||
return Err(ShellError::GenericError(
|
|
||||||
"Connection doesnt define a query".into(),
|
|
||||||
format!("Expected a connection with query. Got {}", s),
|
|
||||||
Some(call.head),
|
|
||||||
None,
|
|
||||||
Vec::new(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
return Err(ShellError::GenericError(
|
return Err(ShellError::GenericError(
|
||||||
"Connection without statement".into(),
|
"Connection doesnt define a query".into(),
|
||||||
"The connection needs a statement defined".into(),
|
format!("Expected a connection with query. Got {}", s),
|
||||||
Some(call.head),
|
Some(call.head),
|
||||||
None,
|
None,
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
None => {
|
||||||
|
return Err(ShellError::GenericError(
|
||||||
|
"Connection without statement".into(),
|
||||||
|
"The connection needs a statement defined".into(),
|
||||||
|
Some(call.head),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(db.into_value(call.head).into_pipeline_data())
|
Ok(db.into_value(call.head).into_pipeline_data())
|
||||||
} else {
|
|
||||||
Err(ShellError::CantConvert(
|
|
||||||
"expression or query".into(),
|
|
||||||
value.get_type().to_string(),
|
|
||||||
value.span()?,
|
|
||||||
None,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,3 +162,23 @@ fn modify_select(select: &mut Box<Select>, expression: Expr, span: Span) -> Resu
|
|||||||
select.as_mut().selection = Some(new_expression);
|
select.as_mut().selection = Some(new_expression);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::super::expressions::{FieldExpr, OrExpr};
|
||||||
|
use super::super::{FromDb, ProjectionDb, WhereDb};
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![
|
||||||
|
Box::new(OrDb {}),
|
||||||
|
Box::new(ProjectionDb {}),
|
||||||
|
Box::new(FromDb {}),
|
||||||
|
Box::new(WhereDb {}),
|
||||||
|
Box::new(FieldExpr {}),
|
||||||
|
Box::new(OrExpr {}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,7 +5,8 @@ use nu_engine::CallExt;
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||||
|
Type, Value,
|
||||||
};
|
};
|
||||||
use sqlparser::ast::{Expr, OrderByExpr, Statement};
|
use sqlparser::ast::{Expr, OrderByExpr, Statement};
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ pub struct OrderByDb;
|
|||||||
|
|
||||||
impl Command for OrderByDb {
|
impl Command for OrderByDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"db order-by"
|
"order-by"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -30,23 +31,65 @@ impl Command for OrderByDb {
|
|||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
"Select expression(s) on the table",
|
"Select expression(s) on the table",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("database".into()))
|
||||||
|
.output_type(Type::Custom("database".into()))
|
||||||
.category(Category::Custom("database".into()))
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["database", "select"]
|
vec!["database", "order-by"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![
|
||||||
description: "orders query by a column",
|
Example {
|
||||||
example: r#"db open db.mysql
|
description: "orders query by a column",
|
||||||
| db from table_a
|
example: r#"open db.mysql
|
||||||
| db select a
|
| into db
|
||||||
| db order-by a
|
| from table_a
|
||||||
| db describe"#,
|
| select a
|
||||||
result: None,
|
| order-by a
|
||||||
}]
|
| describe"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT a FROM table_a ORDER BY a".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "orders query by column a ascending and by column b",
|
||||||
|
example: r#"open db.mysql
|
||||||
|
| into db
|
||||||
|
| from table_a
|
||||||
|
| select a
|
||||||
|
| order-by a --ascending
|
||||||
|
| order-by b
|
||||||
|
| describe"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT a FROM table_a ORDER BY a ASC, b".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
@ -155,3 +198,23 @@ fn update_connection(
|
|||||||
|
|
||||||
Ok(db.into_value(call.head).into_pipeline_data())
|
Ok(db.into_value(call.head).into_pipeline_data())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::super::expressions::{FieldExpr, OrExpr};
|
||||||
|
use super::super::{FromDb, ProjectionDb, WhereDb};
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![
|
||||||
|
Box::new(OrderByDb {}),
|
||||||
|
Box::new(ProjectionDb {}),
|
||||||
|
Box::new(FromDb {}),
|
||||||
|
Box::new(WhereDb {}),
|
||||||
|
Box::new(FieldExpr {}),
|
||||||
|
Box::new(OrExpr {}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
use crate::database::values::dsl::ExprDb;
|
|
||||||
use nu_engine::CallExt;
|
|
||||||
use nu_protocol::{
|
|
||||||
ast::Call,
|
|
||||||
engine::{Command, EngineState, Stack},
|
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
|
|
||||||
};
|
|
||||||
use sqlparser::ast::{Expr, WindowSpec};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct OverExpr;
|
|
||||||
|
|
||||||
impl Command for OverExpr {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"db over"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build(self.name())
|
|
||||||
.rest(
|
|
||||||
"partition-by",
|
|
||||||
SyntaxShape::Any,
|
|
||||||
"columns to partition the window function",
|
|
||||||
)
|
|
||||||
.category(Category::Custom("database".into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Adds a partition to an expression function"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![Example {
|
|
||||||
description: "Adds a partition to a function expresssion",
|
|
||||||
example: "db function avg col_a | db over col_b",
|
|
||||||
result: None,
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
|
||||||
vec!["database", "column", "expression"]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
|
|
||||||
let value = Value::List {
|
|
||||||
vals,
|
|
||||||
span: call.head,
|
|
||||||
};
|
|
||||||
let partitions = ExprDb::extract_exprs(value)?;
|
|
||||||
|
|
||||||
let mut expression = ExprDb::try_from_pipeline(input, call.head)?;
|
|
||||||
match expression.as_mut() {
|
|
||||||
Expr::Function(function) => {
|
|
||||||
function.over = Some(WindowSpec {
|
|
||||||
partition_by: partitions,
|
|
||||||
order_by: Vec::new(),
|
|
||||||
window_frame: None,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
s => {
|
|
||||||
return Err(ShellError::GenericError(
|
|
||||||
"Expression doesnt define a function".into(),
|
|
||||||
format!("Expected an expression with a function. Got {}", s),
|
|
||||||
Some(call.head),
|
|
||||||
None,
|
|
||||||
Vec::new(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(expression.into_value(call.head).into_pipeline_data())
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,6 +3,7 @@ use nu_protocol::{
|
|||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Spanned, SyntaxShape,
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Spanned, SyntaxShape,
|
||||||
|
Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::super::SQLiteDatabase;
|
use super::super::SQLiteDatabase;
|
||||||
@ -12,7 +13,7 @@ pub struct QueryDb;
|
|||||||
|
|
||||||
impl Command for QueryDb {
|
impl Command for QueryDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"db query"
|
"query"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
@ -22,6 +23,8 @@ impl Command for QueryDb {
|
|||||||
SyntaxShape::String,
|
SyntaxShape::String,
|
||||||
"SQL to execute against the database",
|
"SQL to execute against the database",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("database".into()))
|
||||||
|
.output_type(Type::Any)
|
||||||
.category(Category::Custom("database".into()))
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,8 +34,8 @@ impl Command for QueryDb {
|
|||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Get 1 table out of a SQLite database",
|
description: "Execute a query statement using the database connection",
|
||||||
example: r#"db open foo.db | db query "SELECT * FROM Bar""#,
|
example: r#"open foo.db | into db | query "SELECT * FROM Bar""#,
|
||||||
result: None,
|
result: None,
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use crate::database::values::definitions::{db::Db, db_row::DbRow, db_table::DbTa
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, PipelineData, ShellError, Signature, Span, Value,
|
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
|
||||||
};
|
};
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -11,21 +11,24 @@ pub struct SchemaDb;
|
|||||||
|
|
||||||
impl Command for SchemaDb {
|
impl Command for SchemaDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"db schema"
|
"schema"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name()).category(Category::Custom("database".into()))
|
Signature::build(self.name())
|
||||||
|
.input_type(Type::Custom("database".into()))
|
||||||
|
.output_type(Type::Any)
|
||||||
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"Show database information, including its schema."
|
"Show sqlite database information, including its schema."
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Show the schema of a SQLite database",
|
description: "Show the schema of a SQLite database",
|
||||||
example: r#"open foo.db | db schema"#,
|
example: r#"open foo.db | into db | schema"#,
|
||||||
result: None,
|
result: None,
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use nu_protocol::{
|
|||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||||
Value,
|
Type, Value,
|
||||||
};
|
};
|
||||||
use sqlparser::ast::{Query, Select, SelectItem, SetExpr, Statement};
|
use sqlparser::ast::{Query, Select, SelectItem, SetExpr, Statement};
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ pub struct ProjectionDb;
|
|||||||
|
|
||||||
impl Command for ProjectionDb {
|
impl Command for ProjectionDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"db select"
|
"select"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -27,6 +27,8 @@ impl Command for ProjectionDb {
|
|||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
"Select expression(s) on the table",
|
"Select expression(s) on the table",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("database".into()))
|
||||||
|
.output_type(Type::Custom("database".into()))
|
||||||
.category(Category::Custom("database".into()))
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,13 +40,43 @@ impl Command for ProjectionDb {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "selects a column from a database",
|
description: "selects a column from a database",
|
||||||
example: "db open db.mysql | db select a | db describe",
|
example: "open db.mysql | into db | select a | describe",
|
||||||
result: None,
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT a".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "selects columns from a database",
|
description: "selects columns from a database using alias",
|
||||||
example: "db open db.mysql | db select a b c | db describe",
|
example: r#"open db.mysql
|
||||||
result: None,
|
| into db
|
||||||
|
| select (field a | as new_a) b c
|
||||||
|
| from table_1
|
||||||
|
| describe"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT a AS new_a, b, c FROM table_1".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -104,7 +136,7 @@ fn modify_statement(
|
|||||||
Ok(statement)
|
Ok(statement)
|
||||||
}
|
}
|
||||||
s => Err(ShellError::GenericError(
|
s => Err(ShellError::GenericError(
|
||||||
"Connection doesnt define a statement".into(),
|
"Connection doesn't define a statement".into(),
|
||||||
format!("Expected a connection with query. Got {}", s),
|
format!("Expected a connection with query. Got {}", s),
|
||||||
Some(span),
|
Some(span),
|
||||||
None,
|
None,
|
||||||
@ -129,3 +161,21 @@ fn create_select(projection: Vec<SelectItem>) -> Select {
|
|||||||
having: None,
|
having: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::super::expressions::{AliasExpr, FieldExpr};
|
||||||
|
use super::super::FromDb;
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![
|
||||||
|
Box::new(ProjectionDb {}),
|
||||||
|
Box::new(FromDb {}),
|
||||||
|
Box::new(FieldExpr {}),
|
||||||
|
Box::new(AliasExpr {}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,7 +13,7 @@ pub struct TestingDb;
|
|||||||
|
|
||||||
impl Command for TestingDb {
|
impl Command for TestingDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"db testing"
|
"testing-db"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
@ -27,7 +27,7 @@ impl Command for TestingDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"Create query object"
|
"Temporal Command: Create query object"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
50
crates/nu-command/src/database/commands/to_db.rs
Normal file
50
crates/nu-command/src/database/commands/to_db.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
use super::super::SQLiteDatabase;
|
||||||
|
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{Command, EngineState, Stack},
|
||||||
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Type,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ToDataBase;
|
||||||
|
|
||||||
|
impl Command for ToDataBase {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"into db"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Converts into an open db connection"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
|
.input_type(Type::Any)
|
||||||
|
.output_type(Type::Custom("database".into()))
|
||||||
|
.category(Category::Custom("database".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["database", "into", "db"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Converts an open file into a db object",
|
||||||
|
example: "open db.mysql | into db",
|
||||||
|
result: None,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
_engine_state: &EngineState,
|
||||||
|
_stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let db = SQLiteDatabase::try_from_pipeline(input, call.head)?;
|
||||||
|
Ok(db.into_value(call.head).into_pipeline_data())
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,8 @@ use nu_engine::CallExt;
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||||
|
Type, Value,
|
||||||
};
|
};
|
||||||
use sqlparser::ast::{Expr, Query, Select, SetExpr, Statement};
|
use sqlparser::ast::{Expr, Query, Select, SetExpr, Statement};
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ pub struct WhereDb;
|
|||||||
|
|
||||||
impl Command for WhereDb {
|
impl Command for WhereDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"db where"
|
"where"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -24,6 +25,8 @@ impl Command for WhereDb {
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name())
|
Signature::build(self.name())
|
||||||
.required("where", SyntaxShape::Any, "Where expression on the table")
|
.required("where", SyntaxShape::Any, "Where expression on the table")
|
||||||
|
.input_type(Type::Custom("database".into()))
|
||||||
|
.output_type(Type::Custom("database".into()))
|
||||||
.category(Category::Custom("database".into()))
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,12 +37,26 @@ impl Command for WhereDb {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "selects a column from a database with a where clause",
|
description: "selects a column from a database with a where clause",
|
||||||
example: r#"db open db.mysql
|
example: r#"open db.mysql
|
||||||
| db select a
|
| into db
|
||||||
| db from table_1
|
| select a
|
||||||
| db where ((db col a) > 1)
|
| from table_1
|
||||||
| db describe"#,
|
| where ((field a) > 1)
|
||||||
result: None,
|
| describe"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT a FROM table_1 WHERE a > 1".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,3 +128,23 @@ fn create_select(expression: Expr) -> Select {
|
|||||||
having: None,
|
having: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::super::expressions::{FieldExpr, OrExpr};
|
||||||
|
use super::super::{FromDb, ProjectionDb};
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![
|
||||||
|
Box::new(WhereDb {}),
|
||||||
|
Box::new(ProjectionDb {}),
|
||||||
|
Box::new(FromDb {}),
|
||||||
|
Box::new(WhereDb {}),
|
||||||
|
Box::new(FieldExpr {}),
|
||||||
|
Box::new(OrExpr {}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
132
crates/nu-command/src/database/expressions/alias.rs
Normal file
132
crates/nu-command/src/database/expressions/alias.rs
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
use crate::database::values::dsl::{ExprDb, SelectDb};
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{Command, EngineState, Stack},
|
||||||
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||||
|
Type, Value,
|
||||||
|
};
|
||||||
|
use sqlparser::ast::{Ident, SelectItem};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AliasExpr;
|
||||||
|
|
||||||
|
impl Command for AliasExpr {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"as"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
|
.required("alias", SyntaxShape::String, "alias name")
|
||||||
|
.input_type(Type::Custom("db-expression".into()))
|
||||||
|
.output_type(Type::Custom("db-expression".into()))
|
||||||
|
.category(Category::Custom("db-expression".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Creates an alias for a column selection"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Creates an alias for a column selection",
|
||||||
|
example: "field name_a | as new_a | into nu",
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["expression".into(), "alias".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::Record {
|
||||||
|
cols: vec!["value".into(), "quoted_style".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "name_a".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "None".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::Record {
|
||||||
|
cols: vec!["value".into(), "quoted_style".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "new_a".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "None".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["database", "alias", "column"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let alias: String = call.req(engine_state, stack, 0)?;
|
||||||
|
|
||||||
|
let value = input.into_value(call.head);
|
||||||
|
if let Ok(expr) = ExprDb::try_from_value(&value) {
|
||||||
|
alias_selection(expr.into_native().into(), alias, call)
|
||||||
|
} else {
|
||||||
|
let select = SelectDb::try_from_value(&value)?;
|
||||||
|
alias_selection(select, alias, call)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alias_selection(
|
||||||
|
select: SelectDb,
|
||||||
|
alias: String,
|
||||||
|
call: &Call,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let select = match select.into_native() {
|
||||||
|
SelectItem::UnnamedExpr(expr) => SelectItem::ExprWithAlias {
|
||||||
|
expr,
|
||||||
|
alias: Ident {
|
||||||
|
value: alias,
|
||||||
|
quote_style: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SelectItem::ExprWithAlias { expr, .. } => SelectItem::ExprWithAlias {
|
||||||
|
expr,
|
||||||
|
alias: Ident {
|
||||||
|
value: alias,
|
||||||
|
quote_style: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
select => select,
|
||||||
|
};
|
||||||
|
|
||||||
|
let select: SelectDb = select.into();
|
||||||
|
Ok(select.into_value(call.head).into_pipeline_data())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::FieldExpr;
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![Box::new(AliasExpr {}), Box::new(FieldExpr {})])
|
||||||
|
}
|
||||||
|
}
|
141
crates/nu-command/src/database/expressions/and.rs
Normal file
141
crates/nu-command/src/database/expressions/and.rs
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
use crate::database::values::dsl::ExprDb;
|
||||||
|
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{Command, EngineState, Stack},
|
||||||
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||||
|
Type, Value,
|
||||||
|
};
|
||||||
|
use sqlparser::ast::{BinaryOperator, Expr};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AndExpr;
|
||||||
|
|
||||||
|
impl Command for AndExpr {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"and"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Includes an AND clause for an expression"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
|
.required("and", SyntaxShape::Any, "AND expression")
|
||||||
|
.input_type(Type::Custom("db-expression".into()))
|
||||||
|
.output_type(Type::Custom("db-expression".into()))
|
||||||
|
.category(Category::Custom("db-expression".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["database", "and", "expression"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Creates an AND expression",
|
||||||
|
example: r#"(field a) > 1 | and ((field a) < 10) | into nu"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["left".into(), "op".into(), "right".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::Record {
|
||||||
|
cols: vec!["left".into(), "op".into(), "right".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::Record {
|
||||||
|
cols: vec!["value".into(), "quoted_style".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "a".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "None".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: ">".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "1".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "AND".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::Record {
|
||||||
|
cols: vec!["left".into(), "op".into(), "right".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::Record {
|
||||||
|
cols: vec!["value".into(), "quoted_style".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "a".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "None".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "<".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "10".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let value: Value = call.req(engine_state, stack, 0)?;
|
||||||
|
let expr = ExprDb::try_from_value(&value)?.into_native();
|
||||||
|
|
||||||
|
let expression = ExprDb::try_from_pipeline(input, call.head)?;
|
||||||
|
let expression = Expr::BinaryOp {
|
||||||
|
left: Box::new(expression.into_native()),
|
||||||
|
op: BinaryOperator::And,
|
||||||
|
right: Box::new(expr),
|
||||||
|
};
|
||||||
|
|
||||||
|
let expression: ExprDb = Expr::Nested(Box::new(expression)).into();
|
||||||
|
Ok(expression.into_value(call.head).into_pipeline_data())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::FieldExpr;
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![Box::new(AndExpr {}), Box::new(FieldExpr {})])
|
||||||
|
}
|
||||||
|
}
|
76
crates/nu-command/src/database/expressions/as_nu.rs
Normal file
76
crates/nu-command/src/database/expressions/as_nu.rs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
use crate::database::values::dsl::{ExprDb, SelectDb};
|
||||||
|
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{Command, EngineState, Stack},
|
||||||
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ExprAsNu;
|
||||||
|
|
||||||
|
impl Command for ExprAsNu {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"into nu"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Convert a db expression into a nu value for access and exploration"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
|
.input_type(Type::Custom("db-expression".into()))
|
||||||
|
.output_type(Type::Any)
|
||||||
|
.category(Category::Custom("db-expression".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Convert a col expression into a nushell value",
|
||||||
|
example: "field name_1 | into nu",
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["value".into(), "quoted_style".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "name_1".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "None".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
_engine_state: &EngineState,
|
||||||
|
_stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let value = input.into_value(call.head);
|
||||||
|
if let Ok(expr) = ExprDb::try_from_value(&value) {
|
||||||
|
Ok(expr.to_value(call.head).into_pipeline_data())
|
||||||
|
} else {
|
||||||
|
let select = SelectDb::try_from_value(&value)?;
|
||||||
|
Ok(select.to_value(call.head).into_pipeline_data())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::FieldExpr;
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![Box::new(ExprAsNu {}), Box::new(FieldExpr {})])
|
||||||
|
}
|
||||||
|
}
|
78
crates/nu-command/src/database/expressions/field.rs
Normal file
78
crates/nu-command/src/database/expressions/field.rs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
use crate::database::values::dsl::ExprDb;
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{Command, EngineState, Stack},
|
||||||
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||||
|
Type, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct FieldExpr;
|
||||||
|
|
||||||
|
impl Command for FieldExpr {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"field"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
|
.required("name", SyntaxShape::String, "column name")
|
||||||
|
.input_type(Type::Any)
|
||||||
|
.output_type(Type::Custom("db-expression".into()))
|
||||||
|
.category(Category::Custom("db-expression".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Creates column expression for database"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["database", "column", "expression"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Creates a named field expression",
|
||||||
|
example: "field name_1 | into nu",
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["value".into(), "quoted_style".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "name_1".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "None".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
_input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let value: Value = call.req(engine_state, stack, 0)?;
|
||||||
|
let expression = ExprDb::try_from_value(&value)?;
|
||||||
|
|
||||||
|
Ok(expression.into_value(call.head).into_pipeline_data())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![Box::new(FieldExpr {})])
|
||||||
|
}
|
||||||
|
}
|
157
crates/nu-command/src/database/expressions/function.rs
Normal file
157
crates/nu-command/src/database/expressions/function.rs
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
use crate::database::values::dsl::ExprDb;
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{Command, EngineState, Stack},
|
||||||
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||||
|
Type, Value,
|
||||||
|
};
|
||||||
|
use sqlparser::ast::{Expr, Function, FunctionArg, FunctionArgExpr, Ident, ObjectName};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct FunctionExpr;
|
||||||
|
|
||||||
|
impl Command for FunctionExpr {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"fn"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
|
.required("name", SyntaxShape::String, "function name")
|
||||||
|
.switch("distinct", "distict values", Some('d'))
|
||||||
|
.rest("arguments", SyntaxShape::Any, "function arguments")
|
||||||
|
.input_type(Type::Any)
|
||||||
|
.output_type(Type::Custom("db-expression".into()))
|
||||||
|
.category(Category::Custom("db-expression".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Creates function expression for a select operation"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Creates a function expression",
|
||||||
|
example: "fn count name_1 | into nu",
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec![
|
||||||
|
"name".into(),
|
||||||
|
"args".into(),
|
||||||
|
"over".into(),
|
||||||
|
"distinct".into(),
|
||||||
|
],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "count".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::List {
|
||||||
|
vals: vec![Value::String {
|
||||||
|
val: "name_1".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
}],
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "None".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::Bool {
|
||||||
|
val: false,
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "orders query by a column",
|
||||||
|
example: r#"open db.mysql
|
||||||
|
| into db
|
||||||
|
| select (fn lead col_a)
|
||||||
|
| from table_a
|
||||||
|
| describe"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT lead(col_a) FROM table_a".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["database", "function", "expression"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
_input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let name: String = call.req(engine_state, stack, 0)?;
|
||||||
|
let vals: Vec<Value> = call.rest(engine_state, stack, 1)?;
|
||||||
|
let value = Value::List {
|
||||||
|
vals,
|
||||||
|
span: call.head,
|
||||||
|
};
|
||||||
|
let expressions = ExprDb::extract_exprs(value)?;
|
||||||
|
|
||||||
|
let name: Vec<Ident> = name
|
||||||
|
.split('.')
|
||||||
|
.map(|part| Ident {
|
||||||
|
value: part.to_string(),
|
||||||
|
quote_style: None,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let name = ObjectName(name);
|
||||||
|
|
||||||
|
let args: Vec<FunctionArg> = expressions
|
||||||
|
.into_iter()
|
||||||
|
.map(|expr| {
|
||||||
|
let arg = FunctionArgExpr::Expr(expr);
|
||||||
|
|
||||||
|
FunctionArg::Unnamed(arg)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let expression: ExprDb = Expr::Function(Function {
|
||||||
|
name,
|
||||||
|
args,
|
||||||
|
over: None,
|
||||||
|
distinct: call.has_flag("distinct"),
|
||||||
|
})
|
||||||
|
.into();
|
||||||
|
|
||||||
|
Ok(expression.into_value(call.head).into_pipeline_data())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::super::commands::{FromDb, ProjectionDb};
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![
|
||||||
|
Box::new(FunctionExpr {}),
|
||||||
|
Box::new(ProjectionDb {}),
|
||||||
|
Box::new(FromDb {}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
40
crates/nu-command/src/database/expressions/mod.rs
Normal file
40
crates/nu-command/src/database/expressions/mod.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Conversions between value and sqlparser objects
|
||||||
|
mod alias;
|
||||||
|
mod and;
|
||||||
|
mod as_nu;
|
||||||
|
mod field;
|
||||||
|
mod function;
|
||||||
|
mod or;
|
||||||
|
mod over;
|
||||||
|
|
||||||
|
use nu_protocol::engine::StateWorkingSet;
|
||||||
|
|
||||||
|
pub(crate) use alias::AliasExpr;
|
||||||
|
pub(crate) use and::AndExpr;
|
||||||
|
pub(crate) use as_nu::ExprAsNu;
|
||||||
|
pub(crate) use field::FieldExpr;
|
||||||
|
pub(crate) use function::FunctionExpr;
|
||||||
|
pub(crate) use or::OrExpr;
|
||||||
|
pub(crate) use over::OverExpr;
|
||||||
|
|
||||||
|
pub fn add_expressions_decls(working_set: &mut StateWorkingSet) {
|
||||||
|
macro_rules! bind_command {
|
||||||
|
( $command:expr ) => {
|
||||||
|
working_set.add_decl(Box::new($command));
|
||||||
|
};
|
||||||
|
( $( $command:expr ),* ) => {
|
||||||
|
$( working_set.add_decl(Box::new($command)); )*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Series commands
|
||||||
|
bind_command!(
|
||||||
|
ExprAsNu,
|
||||||
|
AliasExpr,
|
||||||
|
AndExpr,
|
||||||
|
FieldExpr,
|
||||||
|
FunctionExpr,
|
||||||
|
OrExpr,
|
||||||
|
OverExpr
|
||||||
|
);
|
||||||
|
}
|
141
crates/nu-command/src/database/expressions/or.rs
Normal file
141
crates/nu-command/src/database/expressions/or.rs
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
use crate::database::values::dsl::ExprDb;
|
||||||
|
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{Command, EngineState, Stack},
|
||||||
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||||
|
Type, Value,
|
||||||
|
};
|
||||||
|
use sqlparser::ast::{BinaryOperator, Expr};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct OrExpr;
|
||||||
|
|
||||||
|
impl Command for OrExpr {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"or"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Includes an OR clause for an expression"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
|
.required("or", SyntaxShape::Any, "OR expression")
|
||||||
|
.input_type(Type::Custom("db-expression".into()))
|
||||||
|
.output_type(Type::Custom("db-expression".into()))
|
||||||
|
.category(Category::Custom("db-expression".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["database", "or", "expression"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Creates an AND expression",
|
||||||
|
example: r#"(field a) > 1 | or ((field a) < 10) | into nu"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["left".into(), "op".into(), "right".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::Record {
|
||||||
|
cols: vec!["left".into(), "op".into(), "right".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::Record {
|
||||||
|
cols: vec!["value".into(), "quoted_style".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "a".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "None".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: ">".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "1".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "OR".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::Record {
|
||||||
|
cols: vec!["left".into(), "op".into(), "right".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::Record {
|
||||||
|
cols: vec!["value".into(), "quoted_style".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "a".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "None".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "<".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "10".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let value: Value = call.req(engine_state, stack, 0)?;
|
||||||
|
let expr = ExprDb::try_from_value(&value)?.into_native();
|
||||||
|
|
||||||
|
let expression = ExprDb::try_from_pipeline(input, call.head)?;
|
||||||
|
let expression = Expr::BinaryOp {
|
||||||
|
left: Box::new(expression.into_native()),
|
||||||
|
op: BinaryOperator::Or,
|
||||||
|
right: Box::new(expr),
|
||||||
|
};
|
||||||
|
|
||||||
|
let expression: ExprDb = Expr::Nested(Box::new(expression)).into();
|
||||||
|
Ok(expression.into_value(call.head).into_pipeline_data())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::FieldExpr;
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![Box::new(OrExpr {}), Box::new(FieldExpr {})])
|
||||||
|
}
|
||||||
|
}
|
153
crates/nu-command/src/database/expressions/over.rs
Normal file
153
crates/nu-command/src/database/expressions/over.rs
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
use crate::database::values::dsl::ExprDb;
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{Command, EngineState, Stack},
|
||||||
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||||
|
Type, Value,
|
||||||
|
};
|
||||||
|
use sqlparser::ast::{Expr, WindowSpec};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct OverExpr;
|
||||||
|
|
||||||
|
impl Command for OverExpr {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"over"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
|
.rest(
|
||||||
|
"partition-by",
|
||||||
|
SyntaxShape::Any,
|
||||||
|
"columns to partition the window function",
|
||||||
|
)
|
||||||
|
.input_type(Type::Custom("db-expression".into()))
|
||||||
|
.output_type(Type::Custom("db-expression".into()))
|
||||||
|
.category(Category::Custom("db-expression".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Adds a partition to an expression function"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Adds a partition to a function expression",
|
||||||
|
example: "fn avg col_a | over col_b | into nu",
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec![
|
||||||
|
"name".into(),
|
||||||
|
"args".into(),
|
||||||
|
"over".into(),
|
||||||
|
"distinct".into(),
|
||||||
|
],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "avg".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::List {
|
||||||
|
vals: vec![Value::String {
|
||||||
|
val: "col_a".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
}],
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "Some(WindowSpec { partition_by: [Identifier(Ident { value: \"col_b\", quote_style: None })], order_by: [], window_frame: None })".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::Bool {
|
||||||
|
val: false,
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "orders query by a column",
|
||||||
|
example: r#"open db.mysql
|
||||||
|
| into db
|
||||||
|
| select (fn lead col_a | over col_b)
|
||||||
|
| from table_a
|
||||||
|
| describe"#,
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["connection".into(), "query".into()],
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "db.mysql".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "SELECT lead(col_a) OVER (PARTITION BY col_b) FROM table_a".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["database", "over", "expression"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
|
||||||
|
let value = Value::List {
|
||||||
|
vals,
|
||||||
|
span: call.head,
|
||||||
|
};
|
||||||
|
let partitions = ExprDb::extract_exprs(value)?;
|
||||||
|
|
||||||
|
let mut expression = ExprDb::try_from_pipeline(input, call.head)?;
|
||||||
|
match expression.as_mut() {
|
||||||
|
Expr::Function(function) => {
|
||||||
|
function.over = Some(WindowSpec {
|
||||||
|
partition_by: partitions,
|
||||||
|
order_by: Vec::new(),
|
||||||
|
window_frame: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
s => {
|
||||||
|
return Err(ShellError::GenericError(
|
||||||
|
"Expression doesnt define a function".into(),
|
||||||
|
format!("Expected an expression with a function. Got {}", s),
|
||||||
|
Some(call.head),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(expression.into_value(call.head).into_pipeline_data())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::super::commands::{FromDb, ProjectionDb};
|
||||||
|
use super::super::FunctionExpr;
|
||||||
|
use super::*;
|
||||||
|
use crate::database::test_database::test_database;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_database(vec![
|
||||||
|
Box::new(OverExpr {}),
|
||||||
|
Box::new(FunctionExpr {}),
|
||||||
|
Box::new(ProjectionDb {}),
|
||||||
|
Box::new(FromDb {}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,21 @@
|
|||||||
mod commands;
|
mod commands;
|
||||||
|
mod expressions;
|
||||||
mod values;
|
mod values;
|
||||||
|
|
||||||
pub use commands::add_database_decls;
|
use commands::add_commands_decls;
|
||||||
|
use expressions::add_expressions_decls;
|
||||||
|
|
||||||
pub use values::{
|
pub use values::{
|
||||||
convert_sqlite_row_to_nu_value, convert_sqlite_value_to_nu_value, open_connection_in_memory,
|
convert_sqlite_row_to_nu_value, convert_sqlite_value_to_nu_value, open_connection_in_memory,
|
||||||
SQLiteDatabase,
|
SQLiteDatabase,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use nu_protocol::engine::StateWorkingSet;
|
||||||
|
|
||||||
|
pub fn add_database_decls(working_set: &mut StateWorkingSet) {
|
||||||
|
add_commands_decls(working_set);
|
||||||
|
add_expressions_decls(working_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_database;
|
||||||
|
138
crates/nu-command/src/database/test_database.rs
Normal file
138
crates/nu-command/src/database/test_database.rs
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use super::commands::{DescribeDb, ToDataBase};
|
||||||
|
use super::expressions::ExprAsNu;
|
||||||
|
use crate::SQLiteDatabase;
|
||||||
|
use nu_engine::{eval_block, CallExt};
|
||||||
|
use nu_parser::parse;
|
||||||
|
use nu_protocol::{
|
||||||
|
engine::{Command, EngineState, Stack, StateWorkingSet},
|
||||||
|
Category, IntoPipelineData, PipelineData, Signature, Span, Type,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct CustomOpen;
|
||||||
|
|
||||||
|
impl Command for CustomOpen {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"open"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Mock open file command"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
|
.required(
|
||||||
|
"filename",
|
||||||
|
nu_protocol::SyntaxShape::String,
|
||||||
|
"the filename to use",
|
||||||
|
)
|
||||||
|
.input_type(Type::Any)
|
||||||
|
.output_type(Type::Custom("database".into()))
|
||||||
|
.category(Category::Custom("database".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &nu_protocol::ast::Call,
|
||||||
|
_input: nu_protocol::PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
let path: String = call.req(engine_state, stack, 0)?;
|
||||||
|
let path = Path::new(&path);
|
||||||
|
|
||||||
|
let db = SQLiteDatabase::new(path);
|
||||||
|
Ok(db.into_value(call.head).into_pipeline_data())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn test_database(cmds: Vec<Box<dyn Command + 'static>>) {
|
||||||
|
if cmds.is_empty() {
|
||||||
|
panic!("Empty commands vector")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The first element in the cmds vector must be the one tested
|
||||||
|
let examples = cmds[0].examples();
|
||||||
|
let mut engine_state = Box::new(EngineState::new());
|
||||||
|
|
||||||
|
let delta = {
|
||||||
|
// Base functions that are needed for testing
|
||||||
|
// Try to keep this working set small to keep tests running as fast as possible
|
||||||
|
let mut working_set = StateWorkingSet::new(&*engine_state);
|
||||||
|
working_set.add_decl(Box::new(DescribeDb {}));
|
||||||
|
working_set.add_decl(Box::new(ToDataBase {}));
|
||||||
|
working_set.add_decl(Box::new(CustomOpen {}));
|
||||||
|
working_set.add_decl(Box::new(ExprAsNu {}));
|
||||||
|
|
||||||
|
// Adding the command that is being tested to the working set
|
||||||
|
for cmd in cmds {
|
||||||
|
working_set.add_decl(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
working_set.render()
|
||||||
|
};
|
||||||
|
|
||||||
|
let cwd = std::env::current_dir().expect("Could not get current working directory.");
|
||||||
|
let _ = engine_state.merge_delta(delta, None, &cwd);
|
||||||
|
|
||||||
|
for example in examples {
|
||||||
|
// Skip tests that don't have results to compare to
|
||||||
|
if example.result.is_none() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let start = std::time::Instant::now();
|
||||||
|
|
||||||
|
let (block, delta) = {
|
||||||
|
let mut working_set = StateWorkingSet::new(&*engine_state);
|
||||||
|
let (output, err) = parse(
|
||||||
|
&mut working_set,
|
||||||
|
None,
|
||||||
|
example.example.as_bytes(),
|
||||||
|
false,
|
||||||
|
&[],
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(err) = err {
|
||||||
|
panic!("test parse error in `{}`: {:?}", example.example, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
(output, working_set.render())
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = engine_state.merge_delta(delta, None, &cwd);
|
||||||
|
|
||||||
|
let mut stack = Stack::new();
|
||||||
|
|
||||||
|
match eval_block(
|
||||||
|
&engine_state,
|
||||||
|
&mut stack,
|
||||||
|
&block,
|
||||||
|
PipelineData::new(Span::test_data()),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
) {
|
||||||
|
Err(err) => panic!("test eval error in `{}`: {:?}", example.example, err),
|
||||||
|
Ok(result) => {
|
||||||
|
let result = result.into_value(Span::test_data());
|
||||||
|
println!("input: {}", example.example);
|
||||||
|
println!("result: {:?}", result);
|
||||||
|
println!("done: {:?}", start.elapsed());
|
||||||
|
|
||||||
|
// Note. Value implements PartialEq for Bool, Int, Float, String and Block
|
||||||
|
// If the command you are testing requires to compare another case, then
|
||||||
|
// you need to define its equality in the Value struct
|
||||||
|
if let Some(expected) = example.result {
|
||||||
|
if result != expected {
|
||||||
|
panic!(
|
||||||
|
"the example result is different to expected value: {:?} != {:?}",
|
||||||
|
result, expected
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -118,6 +118,11 @@ impl CustomValue for ExprDb {
|
|||||||
Operator::In
|
Operator::In
|
||||||
| Operator::NotIn
|
| Operator::NotIn
|
||||||
| Operator::Pow
|
| Operator::Pow
|
||||||
|
| Operator::BitOr
|
||||||
|
| Operator::BitXor
|
||||||
|
| Operator::BitAnd
|
||||||
|
| Operator::ShiftLeft
|
||||||
|
| Operator::ShiftRight
|
||||||
| Operator::StartsWith
|
| Operator::StartsWith
|
||||||
| Operator::EndsWith => Err(ShellError::UnsupportedOperator(operator, op)),
|
| Operator::EndsWith => Err(ShellError::UnsupportedOperator(operator, op)),
|
||||||
}?;
|
}?;
|
||||||
|
@ -23,6 +23,8 @@ impl Command for AppendDF {
|
|||||||
Signature::build(self.name())
|
Signature::build(self.name())
|
||||||
.required("other", SyntaxShape::Any, "dataframe to be appended")
|
.required("other", SyntaxShape::Any, "dataframe to be appended")
|
||||||
.switch("col", "appends in col orientation", Some('c'))
|
.switch("col", "appends in col orientation", Some('c'))
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("dataframe".into()))
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,7 +32,7 @@ impl Command for AppendDF {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Appends a dataframe as new columns",
|
description: "Appends a dataframe as new columns",
|
||||||
example: r#"let a = ([[a b]; [1 2] [3 4]] | to-df);
|
example: r#"let a = ([[a b]; [1 2] [3 4]] | into df);
|
||||||
$a | append $a"#,
|
$a | append $a"#,
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
@ -57,7 +59,7 @@ impl Command for AppendDF {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Appends a dataframe merging at the end of columns",
|
description: "Appends a dataframe merging at the end of columns",
|
||||||
example: r#"let a = ([[a b]; [1 2] [3 4]] | to-df);
|
example: r#"let a = ([[a b]; [1 2] [3 4]] | into df);
|
||||||
$a | append $a --col"#,
|
$a | append $a --col"#,
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
@ -87,14 +89,6 @@ impl Command for AppendDF {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -29,6 +29,8 @@ impl Command for DescribeDF {
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name())
|
Signature::build(self.name())
|
||||||
.category(Category::Custom("dataframe".into()))
|
.category(Category::Custom("dataframe".into()))
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.named(
|
.named(
|
||||||
"quantiles",
|
"quantiles",
|
||||||
SyntaxShape::Table,
|
SyntaxShape::Table,
|
||||||
@ -40,7 +42,7 @@ impl Command for DescribeDF {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "dataframe description",
|
description: "dataframe description",
|
||||||
example: "[[a b]; [1 1] [1 1]] | to-df | describe",
|
example: "[[a b]; [1 1] [1 1]] | into df | describe",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new(
|
Column::new(
|
||||||
@ -95,14 +97,6 @@ impl Command for DescribeDF {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -23,13 +23,15 @@ impl Command for DropDF {
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name())
|
Signature::build(self.name())
|
||||||
.rest("rest", SyntaxShape::Any, "column names to be dropped")
|
.rest("rest", SyntaxShape::Any, "column names to be dropped")
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("dataframe".into()))
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "drop column a",
|
description: "drop column a",
|
||||||
example: "[[a b]; [1 2] [3 4]] | to-df | drop a",
|
example: "[[a b]; [1 2] [3 4]] | into df | drop a",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![Column::new(
|
NuDataFrame::try_from_columns(vec![Column::new(
|
||||||
"b".to_string(),
|
"b".to_string(),
|
||||||
@ -41,14 +43,6 @@ impl Command for DropDF {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -34,13 +34,15 @@ impl Command for DropDuplicates {
|
|||||||
"keeps last duplicate value (by default keeps first)",
|
"keeps last duplicate value (by default keeps first)",
|
||||||
Some('l'),
|
Some('l'),
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("dataframe".into()))
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "drop duplicates",
|
description: "drop duplicates",
|
||||||
example: "[[a b]; [1 2] [3 4] [1 2]] | to-df | drop-duplicates",
|
example: "[[a b]; [1 2] [3 4] [1 2]] | into df | drop-duplicates",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new(
|
Column::new(
|
||||||
@ -58,14 +60,6 @@ impl Command for DropDuplicates {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -27,6 +27,8 @@ impl Command for DropNulls {
|
|||||||
SyntaxShape::Table,
|
SyntaxShape::Table,
|
||||||
"subset of columns to drop nulls",
|
"subset of columns to drop nulls",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("dataframe".into()))
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +36,7 @@ impl Command for DropNulls {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "drop null values in dataframe",
|
description: "drop null values in dataframe",
|
||||||
example: r#"let df = ([[a b]; [1 2] [3 0] [1 2]] | to-df);
|
example: r#"let df = ([[a b]; [1 2] [3 0] [1 2]] | into df);
|
||||||
let res = ($df.b / $df.b);
|
let res = ($df.b / $df.b);
|
||||||
let a = ($df | with-column $res --name res);
|
let a = ($df | with-column $res --name res);
|
||||||
$a | drop-nulls"#,
|
$a | drop-nulls"#,
|
||||||
@ -59,7 +61,7 @@ impl Command for DropNulls {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "drop null values in dataframe",
|
description: "drop null values in dataframe",
|
||||||
example: r#"let s = ([1 2 0 0 3 4] | to-df);
|
example: r#"let s = ([1 2 0 0 3 4] | into df);
|
||||||
($s / $s) | drop-nulls"#,
|
($s / $s) | drop-nulls"#,
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![Column::new(
|
NuDataFrame::try_from_columns(vec![Column::new(
|
||||||
@ -78,14 +80,6 @@ impl Command for DropNulls {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -18,13 +18,16 @@ impl Command for DataTypes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name()).category(Category::Custom("dataframe".into()))
|
Signature::build(self.name())
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Dataframe dtypes",
|
description: "Dataframe dtypes",
|
||||||
example: "[[a b]; [1 2] [3 4]] | to-df | dtypes",
|
example: "[[a b]; [1 2] [3 4]] | into df | dtypes",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new(
|
Column::new(
|
||||||
@ -42,14 +45,6 @@ impl Command for DataTypes {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -11,7 +11,7 @@ pub struct Dummies;
|
|||||||
|
|
||||||
impl Command for Dummies {
|
impl Command for Dummies {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"to-dummies"
|
"dummies"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -19,14 +19,17 @@ impl Command for Dummies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name()).category(Category::Custom("dataframe".into()))
|
Signature::build(self.name())
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Create new dataframe with dummy variables from a dataframe",
|
description: "Create new dataframe with dummy variables from a dataframe",
|
||||||
example: "[[a b]; [1 2] [3 4]] | to-df | to-dummies",
|
example: "[[a b]; [1 2] [3 4]] | into df | dummies",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new(
|
Column::new(
|
||||||
@ -52,7 +55,7 @@ impl Command for Dummies {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Create new dataframe with dummy variables from a series",
|
description: "Create new dataframe with dummy variables from a series",
|
||||||
example: "[1 2 2 3 3] | to-df | to-dummies",
|
example: "[1 2 2 3 3] | into df | dummies",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new(
|
Column::new(
|
||||||
@ -93,14 +96,6 @@ impl Command for Dummies {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -29,6 +29,8 @@ impl Command for FilterWith {
|
|||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
"boolean mask used to filter data",
|
"boolean mask used to filter data",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("dataframe or lazyframe".into()))
|
.category(Category::Custom("dataframe or lazyframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,8 +38,8 @@ impl Command for FilterWith {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Filter dataframe using a bool mask",
|
description: "Filter dataframe using a bool mask",
|
||||||
example: r#"let mask = ([true false] | to-df);
|
example: r#"let mask = ([true false] | into df);
|
||||||
[[a b]; [1 2] [3 4]] | to-df | filter-with $mask"#,
|
[[a b]; [1 2] [3 4]] | into df | filter-with $mask"#,
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new("a".to_string(), vec![Value::test_int(1)]),
|
Column::new("a".to_string(), vec![Value::test_int(1)]),
|
||||||
@ -49,7 +51,7 @@ impl Command for FilterWith {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Filter dataframe using an expression",
|
description: "Filter dataframe using an expression",
|
||||||
example: "[[a b]; [1 2] [3 4]] | to-df | filter-with ((col a) > 1)",
|
example: "[[a b]; [1 2] [3 4]] | into df | filter-with ((col a) > 1)",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new("a".to_string(), vec![Value::test_int(3)]),
|
Column::new("a".to_string(), vec![Value::test_int(3)]),
|
||||||
@ -62,14 +64,6 @@ impl Command for FilterWith {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -21,13 +21,15 @@ impl Command for FirstDF {
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name())
|
Signature::build(self.name())
|
||||||
.optional("rows", SyntaxShape::Int, "Number of rows for head")
|
.optional("rows", SyntaxShape::Int, "Number of rows for head")
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("dataframe".into()))
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Create new dataframe with head rows",
|
description: "Create new dataframe with head rows",
|
||||||
example: "[[a b]; [1 2] [3 4]] | to-df | first 1",
|
example: "[[a b]; [1 2] [3 4]] | into df | first 1",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new("a".to_string(), vec![Value::test_int(1)]),
|
Column::new("a".to_string(), vec![Value::test_int(1)]),
|
||||||
@ -39,14 +41,6 @@ impl Command for FirstDF {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -24,13 +24,15 @@ impl Command for GetDF {
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name())
|
Signature::build(self.name())
|
||||||
.rest("rest", SyntaxShape::Any, "column names to sort dataframe")
|
.rest("rest", SyntaxShape::Any, "column names to sort dataframe")
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("dataframe".into()))
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Returns the selected column",
|
description: "Returns the selected column",
|
||||||
example: "[[a b]; [1 2] [3 4]] | to-df | get a",
|
example: "[[a b]; [1 2] [3 4]] | into df | get a",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![Column::new(
|
NuDataFrame::try_from_columns(vec![Column::new(
|
||||||
"a".to_string(),
|
"a".to_string(),
|
||||||
@ -42,14 +44,6 @@ impl Command for GetDF {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -21,13 +21,15 @@ impl Command for LastDF {
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name())
|
Signature::build(self.name())
|
||||||
.optional("rows", SyntaxShape::Int, "Number of rows for tail")
|
.optional("rows", SyntaxShape::Int, "Number of rows for tail")
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("dataframe".into()))
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Create new dataframe with last rows",
|
description: "Create new dataframe with last rows",
|
||||||
example: "[[a b]; [1 2] [3 4]] | to-df | last 1",
|
example: "[[a b]; [1 2] [3 4]] | into df | last 1",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new("a".to_string(), vec![Value::test_int(3)]),
|
Column::new("a".to_string(), vec![Value::test_int(3)]),
|
||||||
@ -39,14 +41,6 @@ impl Command for LastDF {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -25,7 +25,7 @@ impl Command for ListDF {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Creates a new dataframe and shows it in the dataframe list",
|
description: "Creates a new dataframe and shows it in the dataframe list",
|
||||||
example: r#"let test = ([[a b];[1 2] [3 4]] | to-df);
|
example: r#"let test = ([[a b];[1 2] [3 4]] | into df);
|
||||||
ls-df"#,
|
ls-df"#,
|
||||||
result: None,
|
result: None,
|
||||||
}]
|
}]
|
||||||
|
@ -48,13 +48,16 @@ impl Command for MeltDF {
|
|||||||
"optional name for value column",
|
"optional name for value column",
|
||||||
Some('l'),
|
Some('l'),
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("dataframe".into()))
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "melt dataframe",
|
description: "melt dataframe",
|
||||||
example: "[[a b c d]; [x 1 4 a] [y 2 5 b] [z 3 6 c]] | to-df | melt -c [b c] -v [a d]",
|
example:
|
||||||
|
"[[a b c d]; [x 1 4 a] [y 2 5 b] [z 3 6 c]] | into df | melt -c [b c] -v [a d]",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new(
|
Column::new(
|
||||||
@ -108,14 +111,6 @@ impl Command for MeltDF {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -58,6 +58,8 @@ impl Command for OpenDataFrame {
|
|||||||
"Columns to be selected from csv file. CSV and Parquet file",
|
"Columns to be selected from csv file. CSV and Parquet file",
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Any)
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("dataframe".into()))
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,14 +71,6 @@ impl Command for OpenDataFrame {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Any
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
@ -155,7 +149,7 @@ fn from_json(
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
) -> Result<polars::prelude::DataFrame, ShellError> {
|
) -> Result<polars::prelude::DataFrame, ShellError> {
|
||||||
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
|
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
|
||||||
let mut file = File::open(&file.item).map_err(|e| {
|
let file = File::open(&file.item).map_err(|e| {
|
||||||
ShellError::GenericError(
|
ShellError::GenericError(
|
||||||
"Error opening file".into(),
|
"Error opening file".into(),
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
@ -165,7 +159,7 @@ fn from_json(
|
|||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let buf_reader = BufReader::new(&mut file);
|
let buf_reader = BufReader::new(file);
|
||||||
let reader = JsonReader::new(buf_reader);
|
let reader = JsonReader::new(buf_reader);
|
||||||
|
|
||||||
reader.finish().map_err(|e| {
|
reader.finish().map_err(|e| {
|
||||||
|
@ -33,6 +33,8 @@ impl Command for RenameDF {
|
|||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
"New names for the selected column(s). A string or list of strings",
|
"New names for the selected column(s). A string or list of strings",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("dataframe or lazyframe".into()))
|
.category(Category::Custom("dataframe or lazyframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +42,7 @@ impl Command for RenameDF {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Renames a series",
|
description: "Renames a series",
|
||||||
example: "[5 6 7 8] | to-df | rename '0' new_name",
|
example: "[5 6 7 8] | into df | rename '0' new_name",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![Column::new(
|
NuDataFrame::try_from_columns(vec![Column::new(
|
||||||
"new_name".to_string(),
|
"new_name".to_string(),
|
||||||
@ -57,7 +59,7 @@ impl Command for RenameDF {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Renames a dataframe column",
|
description: "Renames a dataframe column",
|
||||||
example: "[[a b]; [1 2] [3 4]] | to-df | rename a a_new",
|
example: "[[a b]; [1 2] [3 4]] | into df | rename a a_new",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new(
|
Column::new(
|
||||||
@ -75,7 +77,7 @@ impl Command for RenameDF {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Renames two dataframe columns",
|
description: "Renames two dataframe columns",
|
||||||
example: "[[a b]; [1 2] [3 4]] | to-df | rename [a b] [a_new b_new]",
|
example: "[[a b]; [1 2] [3 4]] | into df | rename [a b] [a_new b_new]",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new(
|
Column::new(
|
||||||
@ -94,14 +96,6 @@ impl Command for RenameDF {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -40,6 +40,9 @@ impl Command for SampleDF {
|
|||||||
Some('s'),
|
Some('s'),
|
||||||
)
|
)
|
||||||
.switch("replace", "sample with replace", Some('e'))
|
.switch("replace", "sample with replace", Some('e'))
|
||||||
|
.switch("shuffle", "shuffle sample", Some('u'))
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("dataframe".into()))
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,25 +50,17 @@ impl Command for SampleDF {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Sample rows from dataframe",
|
description: "Sample rows from dataframe",
|
||||||
example: "[[a b]; [1 2] [3 4]] | to-df | sample -n 1",
|
example: "[[a b]; [1 2] [3 4]] | into df | sample -n 1",
|
||||||
result: None, // No expected value because sampling is random
|
result: None, // No expected value because sampling is random
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Shows sample row using fraction and replace",
|
description: "Shows sample row using fraction and replace",
|
||||||
example: "[[a b]; [1 2] [3 4] [5 6]] | to-df | sample -f 0.5 -e",
|
example: "[[a b]; [1 2] [3 4] [5 6]] | into df | sample -f 0.5 -e",
|
||||||
result: None, // No expected value because sampling is random
|
result: None, // No expected value because sampling is random
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
@ -89,22 +84,26 @@ fn command(
|
|||||||
.get_flag::<i64>(engine_state, stack, "seed")?
|
.get_flag::<i64>(engine_state, stack, "seed")?
|
||||||
.map(|val| val as u64);
|
.map(|val| val as u64);
|
||||||
let replace: bool = call.has_flag("replace");
|
let replace: bool = call.has_flag("replace");
|
||||||
|
let shuffle: bool = call.has_flag("shuffle");
|
||||||
|
|
||||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||||
|
|
||||||
match (rows, fraction) {
|
match (rows, fraction) {
|
||||||
(Some(rows), None) => df.as_ref().sample_n(rows.item, replace, seed).map_err(|e| {
|
(Some(rows), None) => df
|
||||||
ShellError::GenericError(
|
.as_ref()
|
||||||
"Error creating sample".into(),
|
.sample_n(rows.item, replace, shuffle, seed)
|
||||||
e.to_string(),
|
.map_err(|e| {
|
||||||
Some(rows.span),
|
ShellError::GenericError(
|
||||||
None,
|
"Error creating sample".into(),
|
||||||
Vec::new(),
|
e.to_string(),
|
||||||
)
|
Some(rows.span),
|
||||||
}),
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
)
|
||||||
|
}),
|
||||||
(None, Some(frac)) => df
|
(None, Some(frac)) => df
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.sample_frac(frac.item, replace, seed)
|
.sample_frac(frac.item, replace, shuffle, seed)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
ShellError::GenericError(
|
ShellError::GenericError(
|
||||||
"Error creating sample".into(),
|
"Error creating sample".into(),
|
||||||
|
@ -21,13 +21,16 @@ impl Command for ShapeDF {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name()).category(Category::Custom("dataframe".into()))
|
Signature::build(self.name())
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Shows row and column shape",
|
description: "Shows row and column shape",
|
||||||
example: "[[a b]; [1 2] [3 4]] | to-df | shape",
|
example: "[[a b]; [1 2] [3 4]] | into df | shape",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new("rows".to_string(), vec![Value::test_int(2)]),
|
Column::new("rows".to_string(), vec![Value::test_int(2)]),
|
||||||
@ -39,14 +42,6 @@ impl Command for ShapeDF {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -25,13 +25,15 @@ impl Command for SliceDF {
|
|||||||
Signature::build(self.name())
|
Signature::build(self.name())
|
||||||
.required("offset", SyntaxShape::Int, "start of slice")
|
.required("offset", SyntaxShape::Int, "start of slice")
|
||||||
.required("size", SyntaxShape::Int, "size of slice")
|
.required("size", SyntaxShape::Int, "size of slice")
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("dataframe".into()))
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Create new dataframe from a slice of the rows",
|
description: "Create new dataframe from a slice of the rows",
|
||||||
example: "[[a b]; [1 2] [3 4]] | to-df | slice 0 1",
|
example: "[[a b]; [1 2] [3 4]] | into df | slice 0 1",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new("a".to_string(), vec![Value::test_int(1)]),
|
Column::new("a".to_string(), vec![Value::test_int(1)]),
|
||||||
@ -43,14 +45,6 @@ impl Command for SliceDF {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -29,6 +29,8 @@ impl Command for TakeDF {
|
|||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
"list of indices used to take data",
|
"list of indices used to take data",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("dataframe".into()))
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,8 +38,8 @@ impl Command for TakeDF {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Takes selected rows from dataframe",
|
description: "Takes selected rows from dataframe",
|
||||||
example: r#"let df = ([[a b]; [4 1] [5 2] [4 3]] | to-df);
|
example: r#"let df = ([[a b]; [4 1] [5 2] [4 3]] | into df);
|
||||||
let indices = ([0 2] | to-df);
|
let indices = ([0 2] | into df);
|
||||||
$df | take $indices"#,
|
$df | take $indices"#,
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
@ -56,8 +58,8 @@ impl Command for TakeDF {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Takes selected rows from series",
|
description: "Takes selected rows from series",
|
||||||
example: r#"let series = ([4 1 5 2 4 3] | to-df);
|
example: r#"let series = ([4 1 5 2 4 3] | into df);
|
||||||
let indices = ([0 2] | to-df);
|
let indices = ([0 2] | into df);
|
||||||
$series | take $indices"#,
|
$series | take $indices"#,
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![Column::new(
|
NuDataFrame::try_from_columns(vec![Column::new(
|
||||||
@ -71,14 +73,6 @@ impl Command for TakeDF {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -15,7 +15,7 @@ pub struct ToCSV;
|
|||||||
|
|
||||||
impl Command for ToCSV {
|
impl Command for ToCSV {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"to-csv"
|
"to csv"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -32,6 +32,8 @@ impl Command for ToCSV {
|
|||||||
Some('d'),
|
Some('d'),
|
||||||
)
|
)
|
||||||
.switch("no-header", "Indicates if file doesn't have header", None)
|
.switch("no-header", "Indicates if file doesn't have header", None)
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Any)
|
||||||
.category(Category::Custom("dataframe".into()))
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,25 +41,17 @@ impl Command for ToCSV {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Saves dataframe to csv file",
|
description: "Saves dataframe to csv file",
|
||||||
example: "[[a b]; [1 2] [3 4]] | to-df | to-csv test.csv",
|
example: "[[a b]; [1 2] [3 4]] | into df | to csv test.csv",
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Saves dataframe to csv file using other delimiter",
|
description: "Saves dataframe to csv file using other delimiter",
|
||||||
example: "[[a b]; [1 2] [3 4]] | to-df | to-csv test.csv -d '|'",
|
example: "[[a b]; [1 2] [3 4]] | into df | to csv test.csv -d '|'",
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Any
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
@ -99,7 +93,7 @@ fn command(
|
|||||||
writer.has_header(true)
|
writer.has_header(true)
|
||||||
};
|
};
|
||||||
|
|
||||||
let writer = match delimiter {
|
let mut writer = match delimiter {
|
||||||
None => writer,
|
None => writer,
|
||||||
Some(d) => {
|
Some(d) => {
|
||||||
if d.item.len() != 1 {
|
if d.item.len() != 1 {
|
||||||
|
@ -11,7 +11,7 @@ pub struct ToDataFrame;
|
|||||||
|
|
||||||
impl Command for ToDataFrame {
|
impl Command for ToDataFrame {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"to-df"
|
"into df"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -19,14 +19,17 @@ impl Command for ToDataFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name()).category(Category::Custom("dataframe".into()))
|
Signature::build(self.name())
|
||||||
|
.input_type(Type::Any)
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Takes a dictionary and creates a dataframe",
|
description: "Takes a dictionary and creates a dataframe",
|
||||||
example: "[[a b];[1 2] [3 4]] | to-df",
|
example: "[[a b];[1 2] [3 4]] | into df",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new(
|
Column::new(
|
||||||
@ -44,7 +47,7 @@ impl Command for ToDataFrame {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Takes a list of tables and creates a dataframe",
|
description: "Takes a list of tables and creates a dataframe",
|
||||||
example: "[[1 2 a] [3 4 b] [5 6 c]] | to-df",
|
example: "[[1 2 a] [3 4 b] [5 6 c]] | into df",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new(
|
Column::new(
|
||||||
@ -70,7 +73,7 @@ impl Command for ToDataFrame {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Takes a list and creates a dataframe",
|
description: "Takes a list and creates a dataframe",
|
||||||
example: "[a b c] | to-df",
|
example: "[a b c] | into df",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![Column::new(
|
NuDataFrame::try_from_columns(vec![Column::new(
|
||||||
"0".to_string(),
|
"0".to_string(),
|
||||||
@ -86,7 +89,7 @@ impl Command for ToDataFrame {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Takes a list of booleans and creates a dataframe",
|
description: "Takes a list of booleans and creates a dataframe",
|
||||||
example: "[true true false] | to-df",
|
example: "[true true false] | into df",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![Column::new(
|
NuDataFrame::try_from_columns(vec![Column::new(
|
||||||
"0".to_string(),
|
"0".to_string(),
|
||||||
@ -103,14 +106,6 @@ impl Command for ToDataFrame {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Any
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
|
@ -2,7 +2,7 @@ use nu_engine::CallExt;
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
|
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::super::values::NuDataFrame;
|
use super::super::values::NuDataFrame;
|
||||||
@ -12,11 +12,11 @@ pub struct ToNu;
|
|||||||
|
|
||||||
impl Command for ToNu {
|
impl Command for ToNu {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"to-nu"
|
"into nu"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"Converts a section of the dataframe to Nushell Table"
|
"Converts a section of the dataframe into nushell Table"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
@ -28,32 +28,49 @@ impl Command for ToNu {
|
|||||||
Some('n'),
|
Some('n'),
|
||||||
)
|
)
|
||||||
.switch("tail", "shows tail rows", Some('t'))
|
.switch("tail", "shows tail rows", Some('t'))
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Any)
|
||||||
.category(Category::Custom("dataframe".into()))
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
let cols = vec!["index".into(), "a".into(), "b".into()];
|
||||||
|
let rec_1 = Value::Record {
|
||||||
|
cols: cols.clone(),
|
||||||
|
vals: vec![Value::test_int(0), Value::test_int(1), Value::test_int(2)],
|
||||||
|
span: Span::test_data(),
|
||||||
|
};
|
||||||
|
let rec_2 = Value::Record {
|
||||||
|
cols: cols.clone(),
|
||||||
|
vals: vec![Value::test_int(1), Value::test_int(3), Value::test_int(4)],
|
||||||
|
span: Span::test_data(),
|
||||||
|
};
|
||||||
|
let rec_3 = Value::Record {
|
||||||
|
cols,
|
||||||
|
vals: vec![Value::test_int(2), Value::test_int(3), Value::test_int(4)],
|
||||||
|
span: Span::test_data(),
|
||||||
|
};
|
||||||
|
|
||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Shows head rows from dataframe",
|
description: "Shows head rows from dataframe",
|
||||||
example: "[[a b]; [1 2] [3 4]] | to-df | to nu",
|
example: "[[a b]; [1 2] [3 4]] | into df | into nu",
|
||||||
result: None,
|
result: Some(Value::List {
|
||||||
|
vals: vec![rec_1, rec_2],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Shows tail rows from dataframe",
|
description: "Shows tail rows from dataframe",
|
||||||
example: "[[a b]; [1 2] [3 4] [5 6]] | to-df | to nu -t -n 1",
|
example: "[[a b]; [1 2] [5 6] [3 4]] | into df | into nu -t -n 1",
|
||||||
result: None,
|
result: Some(Value::List {
|
||||||
|
vals: vec![rec_3],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Any
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
@ -71,7 +88,7 @@ fn command(
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let rows: Option<usize> = call.get_flag(engine_state, stack, "n-rows")?;
|
let rows: Option<usize> = call.get_flag(engine_state, stack, "rows")?;
|
||||||
let tail: bool = call.has_flag("tail");
|
let tail: bool = call.has_flag("tail");
|
||||||
|
|
||||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||||
@ -94,3 +111,14 @@ fn command(
|
|||||||
|
|
||||||
Ok(PipelineData::Value(value, None))
|
Ok(PipelineData::Value(value, None))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::super::test_dataframe::test_dataframe;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_dataframe(vec![Box::new(ToNu {})])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -15,7 +15,7 @@ pub struct ToParquet;
|
|||||||
|
|
||||||
impl Command for ToParquet {
|
impl Command for ToParquet {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"to-parquet"
|
"to parquet"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -25,25 +25,19 @@ impl Command for ToParquet {
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name())
|
Signature::build(self.name())
|
||||||
.required("file", SyntaxShape::Filepath, "file path to save dataframe")
|
.required("file", SyntaxShape::Filepath, "file path to save dataframe")
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Any)
|
||||||
.category(Category::Custom("dataframe".into()))
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Saves dataframe to parquet file",
|
description: "Saves dataframe to parquet file",
|
||||||
example: "[[a b]; [1 2] [3 4]] | to-df | to-parquet test.parquet",
|
example: "[[a b]; [1 2] [3 4]] | into df | to parquet test.parquet",
|
||||||
result: None,
|
result: None,
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Any
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -27,6 +27,8 @@ impl Command for WithColumn {
|
|||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
"series to be added or expressions used to define the new columns",
|
"series to be added or expressions used to define the new columns",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("dataframe or lazyframe".into()))
|
.category(Category::Custom("dataframe or lazyframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,8 +37,8 @@ impl Command for WithColumn {
|
|||||||
Example {
|
Example {
|
||||||
description: "Adds a series to the dataframe",
|
description: "Adds a series to the dataframe",
|
||||||
example: r#"[[a b]; [1 2] [3 4]]
|
example: r#"[[a b]; [1 2] [3 4]]
|
||||||
| to-df
|
| into df
|
||||||
| with-column ([5 6] | to-df) --name c"#,
|
| with-column ([5 6] | into df) --name c"#,
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new(
|
Column::new(
|
||||||
@ -59,7 +61,7 @@ impl Command for WithColumn {
|
|||||||
Example {
|
Example {
|
||||||
description: "Adds a series to the dataframe",
|
description: "Adds a series to the dataframe",
|
||||||
example: r#"[[a b]; [1 2] [3 4]]
|
example: r#"[[a b]; [1 2] [3 4]]
|
||||||
| to-lazy
|
| into lazy
|
||||||
| with-column [
|
| with-column [
|
||||||
((col a) * 2 | as "c")
|
((col a) * 2 | as "c")
|
||||||
((col a) * 3 | as "d")
|
((col a) * 3 | as "d")
|
||||||
@ -91,14 +93,6 @@ impl Command for WithColumn {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -26,13 +26,15 @@ impl Command for ExprAlias {
|
|||||||
SyntaxShape::String,
|
SyntaxShape::String,
|
||||||
"Alias name for the expression",
|
"Alias name for the expression",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("expression".into()))
|
||||||
|
.output_type(Type::Custom("expression".into()))
|
||||||
.category(Category::Custom("expression".into()))
|
.category(Category::Custom("expression".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Creates and alias expression",
|
description: "Creates and alias expression",
|
||||||
example: "col a | as new_a | to-nu",
|
example: "col a | as new_a | into nu",
|
||||||
result: {
|
result: {
|
||||||
let cols = vec!["expr".into(), "value".into()];
|
let cols = vec!["expr".into(), "value".into()];
|
||||||
let expr = Value::test_string("column");
|
let expr = Value::test_string("column");
|
||||||
@ -57,14 +59,6 @@ impl Command for ExprAlias {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("expression".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("expression".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -11,21 +11,24 @@ pub struct ExprAsNu;
|
|||||||
|
|
||||||
impl Command for ExprAsNu {
|
impl Command for ExprAsNu {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"to-nu"
|
"into nu"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"Convert expression to a nu value for access and exploration"
|
"Convert expression into a nu value for access and exploration"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name()).category(Category::Custom("expression".into()))
|
Signature::build(self.name())
|
||||||
|
.input_type(Type::Custom("expression".into()))
|
||||||
|
.output_type(Type::Any)
|
||||||
|
.category(Category::Custom("expression".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Convert a col expression into a nushell value",
|
description: "Convert a col expression into a nushell value",
|
||||||
example: "col a | to-nu",
|
example: "col a | into nu",
|
||||||
result: Some(Value::Record {
|
result: Some(Value::Record {
|
||||||
cols: vec!["expr".into(), "value".into()],
|
cols: vec!["expr".into(), "value".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
@ -43,14 +46,6 @@ impl Command for ExprAsNu {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("expression".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Any
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
|
@ -26,13 +26,15 @@ impl Command for ExprCol {
|
|||||||
SyntaxShape::String,
|
SyntaxShape::String,
|
||||||
"Name of column to be used",
|
"Name of column to be used",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Any)
|
||||||
|
.output_type(Type::Custom("expression".into()))
|
||||||
.category(Category::Custom("expression".into()))
|
.category(Category::Custom("expression".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Creates a named column expression and converts it to a nu object",
|
description: "Creates a named column expression and converts it to a nu object",
|
||||||
example: "col a | to-nu",
|
example: "col a | into nu",
|
||||||
result: Some(Value::Record {
|
result: Some(Value::Record {
|
||||||
cols: vec!["expr".into(), "value".into()],
|
cols: vec!["expr".into(), "value".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
@ -50,14 +52,6 @@ impl Command for ExprCol {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Any
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("expression".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -25,21 +25,16 @@ macro_rules! expr_command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name()).category(Category::Custom("expression".into()))
|
Signature::build(self.name())
|
||||||
|
.input_type(Type::Custom("expression".into()))
|
||||||
|
.output_type(Type::Custom("expression".into()))
|
||||||
|
.category(Category::Custom("expression".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
$examples
|
$examples
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("expression".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("expression".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
@ -250,7 +245,7 @@ expr_command!(
|
|||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Max aggregation for a group by",
|
description: "Max aggregation for a group by",
|
||||||
example: r#"[[a b]; [one 2] [one 4] [two 1]]
|
example: r#"[[a b]; [one 2] [one 4] [two 1]]
|
||||||
| to-df
|
| into df
|
||||||
| group-by a
|
| group-by a
|
||||||
| agg (col b | max)"#,
|
| agg (col b | max)"#,
|
||||||
result: Some(
|
result: Some(
|
||||||
@ -281,7 +276,7 @@ expr_command!(
|
|||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Min aggregation for a group by",
|
description: "Min aggregation for a group by",
|
||||||
example: r#"[[a b]; [one 2] [one 4] [two 1]]
|
example: r#"[[a b]; [one 2] [one 4] [two 1]]
|
||||||
| to-df
|
| into df
|
||||||
| group-by a
|
| group-by a
|
||||||
| agg (col b | min)"#,
|
| agg (col b | min)"#,
|
||||||
result: Some(
|
result: Some(
|
||||||
@ -312,7 +307,7 @@ expr_command!(
|
|||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Sum aggregation for a group by",
|
description: "Sum aggregation for a group by",
|
||||||
example: r#"[[a b]; [one 2] [one 4] [two 1]]
|
example: r#"[[a b]; [one 2] [one 4] [two 1]]
|
||||||
| to-df
|
| into df
|
||||||
| group-by a
|
| group-by a
|
||||||
| agg (col b | sum)"#,
|
| agg (col b | sum)"#,
|
||||||
result: Some(
|
result: Some(
|
||||||
@ -343,7 +338,7 @@ expr_command!(
|
|||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Mean aggregation for a group by",
|
description: "Mean aggregation for a group by",
|
||||||
example: r#"[[a b]; [one 2] [one 4] [two 1]]
|
example: r#"[[a b]; [one 2] [one 4] [two 1]]
|
||||||
| to-df
|
| into df
|
||||||
| group-by a
|
| group-by a
|
||||||
| agg (col b | mean)"#,
|
| agg (col b | mean)"#,
|
||||||
result: Some(
|
result: Some(
|
||||||
@ -374,7 +369,7 @@ expr_command!(
|
|||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Median aggregation for a group by",
|
description: "Median aggregation for a group by",
|
||||||
example: r#"[[a b]; [one 2] [one 4] [two 1]]
|
example: r#"[[a b]; [one 2] [one 4] [two 1]]
|
||||||
| to-df
|
| into df
|
||||||
| group-by a
|
| group-by a
|
||||||
| agg (col b | median)"#,
|
| agg (col b | median)"#,
|
||||||
result: Some(
|
result: Some(
|
||||||
@ -405,7 +400,7 @@ expr_command!(
|
|||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Std aggregation for a group by",
|
description: "Std aggregation for a group by",
|
||||||
example: r#"[[a b]; [one 2] [one 2] [two 1] [two 1]]
|
example: r#"[[a b]; [one 2] [one 2] [two 1] [two 1]]
|
||||||
| to-df
|
| into df
|
||||||
| group-by a
|
| group-by a
|
||||||
| agg (col b | std)"#,
|
| agg (col b | std)"#,
|
||||||
result: Some(
|
result: Some(
|
||||||
@ -436,7 +431,7 @@ expr_command!(
|
|||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Var aggregation for a group by",
|
description: "Var aggregation for a group by",
|
||||||
example: r#"[[a b]; [one 2] [one 2] [two 1] [two 1]]
|
example: r#"[[a b]; [one 2] [one 2] [two 1] [two 1]]
|
||||||
| to-df
|
| into df
|
||||||
| group-by a
|
| group-by a
|
||||||
| agg (col b | var)"#,
|
| agg (col b | var)"#,
|
||||||
result: Some(
|
result: Some(
|
||||||
|
@ -25,13 +25,15 @@ impl Command for ExprLit {
|
|||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
"literal to construct the expression",
|
"literal to construct the expression",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Any)
|
||||||
|
.output_type(Type::Custom("expression".into()))
|
||||||
.category(Category::Custom("expression".into()))
|
.category(Category::Custom("expression".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Created a literal expression and converts it to a nu object",
|
description: "Created a literal expression and converts it to a nu object",
|
||||||
example: "lit 2 | to-nu",
|
example: "lit 2 | into nu",
|
||||||
result: Some(Value::Record {
|
result: Some(Value::Record {
|
||||||
cols: vec!["expr".into(), "value".into()],
|
cols: vec!["expr".into(), "value".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
@ -49,14 +51,6 @@ impl Command for ExprLit {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Any
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("expression".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -25,6 +25,8 @@ impl Command for ExprOtherwise {
|
|||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
"expressioini to apply when no when predicate matches",
|
"expressioini to apply when no when predicate matches",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Any)
|
||||||
|
.output_type(Type::Custom("expression".into()))
|
||||||
.category(Category::Custom("expression".into()))
|
.category(Category::Custom("expression".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +45,7 @@ impl Command for ExprOtherwise {
|
|||||||
Example {
|
Example {
|
||||||
description: "Create a new column for the dataframe",
|
description: "Create a new column for the dataframe",
|
||||||
example: r#"[[a b]; [6 2] [1 4] [4 1]]
|
example: r#"[[a b]; [6 2] [1 4] [4 1]]
|
||||||
| to-lazy
|
| into lazy
|
||||||
| with-column (
|
| with-column (
|
||||||
when ((col a) > 2) 4 | otherwise 5 | as c
|
when ((col a) > 2) 4 | otherwise 5 | as c
|
||||||
)
|
)
|
||||||
@ -77,14 +79,6 @@ impl Command for ExprOtherwise {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Any
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("expression".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -26,6 +26,8 @@ impl Command for ExprQuantile {
|
|||||||
SyntaxShape::Number,
|
SyntaxShape::Number,
|
||||||
"quantile value for quantile operation",
|
"quantile value for quantile operation",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("expression".into()))
|
||||||
|
.output_type(Type::Custom("expression".into()))
|
||||||
.category(Category::Custom("expression".into()))
|
.category(Category::Custom("expression".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +35,7 @@ impl Command for ExprQuantile {
|
|||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Quantile aggregation for a group by",
|
description: "Quantile aggregation for a group by",
|
||||||
example: r#"[[a b]; [one 2] [one 4] [two 1]]
|
example: r#"[[a b]; [one 2] [one 4] [two 1]]
|
||||||
| to-df
|
| into df
|
||||||
| group-by a
|
| group-by a
|
||||||
| agg (col b | quantile 0.5)"#,
|
| agg (col b | quantile 0.5)"#,
|
||||||
result: Some(
|
result: Some(
|
||||||
@ -53,14 +55,6 @@ impl Command for ExprQuantile {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("expression".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("expression".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -31,6 +31,8 @@ impl Command for ExprWhen {
|
|||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
"expression that will be applied when predicate is true",
|
"expression that will be applied when predicate is true",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("expression".into()))
|
||||||
|
.output_type(Type::Custom("expression".into()))
|
||||||
.category(Category::Custom("expression".into()))
|
.category(Category::Custom("expression".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +51,7 @@ impl Command for ExprWhen {
|
|||||||
Example {
|
Example {
|
||||||
description: "Create a new column for the dataframe",
|
description: "Create a new column for the dataframe",
|
||||||
example: r#"[[a b]; [6 2] [1 4] [4 1]]
|
example: r#"[[a b]; [6 2] [1 4] [4 1]]
|
||||||
| to-lazy
|
| into lazy
|
||||||
| with-column (
|
| with-column (
|
||||||
when ((col a) > 2) 4 | otherwise 5 | as c
|
when ((col a) > 2) 4 | otherwise 5 | as c
|
||||||
)
|
)
|
||||||
@ -83,14 +85,6 @@ impl Command for ExprWhen {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("expression".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("expression".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -26,6 +26,8 @@ impl Command for LazyAggregate {
|
|||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
"Expression(s) that define the aggregations to be applied",
|
"Expression(s) that define the aggregations to be applied",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("lazyframe".into()))
|
.category(Category::Custom("lazyframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +36,7 @@ impl Command for LazyAggregate {
|
|||||||
Example {
|
Example {
|
||||||
description: "Group by and perform an aggregation",
|
description: "Group by and perform an aggregation",
|
||||||
example: r#"[[a b]; [1 2] [1 4] [2 6] [2 4]]
|
example: r#"[[a b]; [1 2] [1 4] [2 6] [2 4]]
|
||||||
| to-df
|
| into df
|
||||||
| group-by a
|
| group-by a
|
||||||
| agg [
|
| agg [
|
||||||
(col b | min | as "b_min")
|
(col b | min | as "b_min")
|
||||||
@ -67,7 +69,7 @@ impl Command for LazyAggregate {
|
|||||||
Example {
|
Example {
|
||||||
description: "Group by and perform an aggregation",
|
description: "Group by and perform an aggregation",
|
||||||
example: r#"[[a b]; [1 2] [1 4] [2 6] [2 4]]
|
example: r#"[[a b]; [1 2] [1 4] [2 6] [2 4]]
|
||||||
| to-lazy
|
| into lazy
|
||||||
| group-by a
|
| group-by a
|
||||||
| agg [
|
| agg [
|
||||||
(col b | min | as "b_min")
|
(col b | min | as "b_min")
|
||||||
@ -101,14 +103,6 @@ impl Command for LazyAggregate {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -20,13 +20,16 @@ impl Command for LazyCollect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name()).category(Category::Custom("lazyframe".into()))
|
Signature::build(self.name())
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
|
.category(Category::Custom("lazyframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "drop duplicates",
|
description: "drop duplicates",
|
||||||
example: "[[a b]; [1 2] [3 4]] | to-lazy | collect",
|
example: "[[a b]; [1 2] [3 4]] | into lazy | collect",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new(
|
Column::new(
|
||||||
@ -44,14 +47,6 @@ impl Command for LazyCollect {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
|
@ -26,13 +26,15 @@ impl Command for LazyFetch {
|
|||||||
SyntaxShape::Int,
|
SyntaxShape::Int,
|
||||||
"number of rows to be fetched from lazyframe",
|
"number of rows to be fetched from lazyframe",
|
||||||
)
|
)
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("lazyframe".into()))
|
.category(Category::Custom("lazyframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Fetch a rows from the dataframe",
|
description: "Fetch a rows from the dataframe",
|
||||||
example: "[[a b]; [6 2] [4 2] [2 2]] | to-df | fetch 2",
|
example: "[[a b]; [6 2] [4 2] [2 2]] | into df | fetch 2",
|
||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new(
|
Column::new(
|
||||||
@ -50,14 +52,6 @@ impl Command for LazyFetch {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> Type {
|
|
||||||
Type::Custom("dataframe".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user