diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4815491854..3acdfa71d1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,17 +29,6 @@ jobs: # instead of 14 GB) which is too little for us right now. Revisit when `dfr` commands are # removed and we're only building the `polars` plugin instead platform: [windows-latest, macos-13, ubuntu-20.04] - feature: [default, dataframe] - include: - - feature: default - flags: "" - - feature: dataframe - flags: "--features=dataframe" - exclude: - - platform: windows-latest - feature: dataframe - - platform: macos-13 - feature: dataframe runs-on: ${{ matrix.platform }} @@ -48,43 +37,31 @@ jobs: - name: Setup Rust toolchain and cache uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 - with: - rustflags: "" - name: cargo fmt run: cargo fmt --all -- --check # If changing these settings also change toolkit.nu - name: Clippy - run: cargo clippy --workspace ${{ matrix.flags }} --exclude nu_plugin_* -- $CLIPPY_OPTIONS + run: cargo clippy --workspace --exclude nu_plugin_* -- $CLIPPY_OPTIONS # In tests we don't have to deny unwrap - name: Clippy of tests - run: cargo clippy --tests --workspace ${{ matrix.flags }} --exclude nu_plugin_* -- -D warnings + run: cargo clippy --tests --workspace --exclude nu_plugin_* -- -D warnings - name: Clippy of benchmarks - run: cargo clippy --benches --workspace ${{ matrix.flags }} --exclude nu_plugin_* -- -D warnings + run: cargo clippy --benches --workspace --exclude nu_plugin_* -- -D warnings tests: strategy: fail-fast: true matrix: platform: [windows-latest, macos-latest, ubuntu-20.04] - feature: [default, dataframe] include: - # linux CI cannot handle clipboard feature - default-flags: "" - - platform: ubuntu-20.04 + # linux CI cannot handle clipboard feature + - platform: ubuntu-20.04 default-flags: "--no-default-features --features=default-no-clipboard" - - feature: default - flags: "" - - feature: dataframe - flags: "--features=dataframe" - exclude: - - platform: windows-latest - feature: dataframe - - platform: macos-latest - feature: dataframe runs-on: ${{ matrix.platform }} @@ -93,12 +70,9 @@ jobs: - name: Setup Rust toolchain and cache uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 - with: - rustflags: "" - name: Tests - run: cargo test --workspace --profile ci --exclude nu_plugin_* ${{ matrix.default-flags }} ${{ matrix.flags }} - + run: cargo test --workspace --profile ci --exclude nu_plugin_* ${{ matrix.default-flags }} - name: Check for clean repo shell: bash run: | @@ -125,8 +99,6 @@ jobs: - name: Setup Rust toolchain and cache uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 - with: - rustflags: "" - name: Install Nushell run: cargo install --path . --locked --no-default-features @@ -178,8 +150,6 @@ jobs: - name: Setup Rust toolchain and cache uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 - with: - rustflags: "" - name: Clippy run: cargo clippy --package nu_plugin_* -- $CLIPPY_OPTIONS diff --git a/.github/workflows/nightly-build.yml b/.github/workflows/nightly-build.yml index ab9f93d97d..418b392fce 100644 --- a/.github/workflows/nightly-build.yml +++ b/.github/workflows/nightly-build.yml @@ -84,41 +84,30 @@ jobs: include: - target: aarch64-apple-darwin os: macos-latest - target_rustflags: '' - target: x86_64-apple-darwin os: macos-latest - target_rustflags: '' - target: x86_64-pc-windows-msvc extra: 'bin' os: windows-latest - target_rustflags: '' - target: x86_64-pc-windows-msvc extra: msi os: windows-latest - target_rustflags: '' - target: aarch64-pc-windows-msvc extra: 'bin' os: windows-latest - target_rustflags: '' - target: aarch64-pc-windows-msvc extra: msi os: windows-latest - target_rustflags: '' - target: x86_64-unknown-linux-gnu os: ubuntu-20.04 - target_rustflags: '' - target: x86_64-unknown-linux-musl os: ubuntu-20.04 - target_rustflags: '' - target: aarch64-unknown-linux-gnu os: ubuntu-20.04 - target_rustflags: '' - target: armv7-unknown-linux-gnueabihf os: ubuntu-20.04 - target_rustflags: '' - target: riscv64gc-unknown-linux-gnu os: ubuntu-latest - target_rustflags: '' runs-on: ${{matrix.os}} @@ -134,7 +123,7 @@ jobs: - name: Setup Rust toolchain and cache uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 - # WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135` + # WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135` with: rustflags: '' @@ -147,12 +136,10 @@ jobs: id: nu run: nu .github/workflows/release-pkg.nu env: - RELEASE_TYPE: standard OS: ${{ matrix.os }} REF: ${{ github.ref }} TARGET: ${{ matrix.target }} _EXTRA_: ${{ matrix.extra }} - TARGET_RUSTFLAGS: ${{ matrix.target_rustflags }} - name: Create an Issue for Release Failure if: ${{ failure() }} @@ -184,122 +171,6 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - full: - name: Full - needs: prepare - strategy: - fail-fast: false - matrix: - target: - - aarch64-apple-darwin - - x86_64-apple-darwin - - x86_64-pc-windows-msvc - - aarch64-pc-windows-msvc - - x86_64-unknown-linux-gnu - - x86_64-unknown-linux-musl - - aarch64-unknown-linux-gnu - extra: ['bin'] - include: - - target: aarch64-apple-darwin - os: macos-latest - target_rustflags: '--features=dataframe' - - target: x86_64-apple-darwin - os: macos-latest - target_rustflags: '--features=dataframe' - - target: x86_64-pc-windows-msvc - extra: 'bin' - os: windows-latest - target_rustflags: '--features=dataframe' - - target: x86_64-pc-windows-msvc - extra: msi - os: windows-latest - target_rustflags: '--features=dataframe' - - target: aarch64-pc-windows-msvc - extra: 'bin' - os: windows-latest - target_rustflags: '--features=dataframe' - - target: aarch64-pc-windows-msvc - extra: msi - os: windows-latest - target_rustflags: '--features=dataframe' - - target: x86_64-unknown-linux-gnu - os: ubuntu-20.04 - target_rustflags: '--features=dataframe' - - target: x86_64-unknown-linux-musl - os: ubuntu-20.04 - target_rustflags: '--features=dataframe' - - target: aarch64-unknown-linux-gnu - os: ubuntu-20.04 - target_rustflags: '--features=dataframe' - - runs-on: ${{matrix.os}} - - steps: - - uses: actions/checkout@v4.1.5 - with: - ref: main - fetch-depth: 0 - - - name: Update Rust Toolchain Target - run: | - echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml - - - name: Setup Rust toolchain and cache - uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 - # WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135` - with: - rustflags: '' - - - name: Setup Nushell - uses: hustcer/setup-nu@v3.10 - with: - version: 0.93.0 - - - name: Release Nu Binary - id: nu - run: nu .github/workflows/release-pkg.nu - env: - RELEASE_TYPE: full - OS: ${{ matrix.os }} - REF: ${{ github.ref }} - TARGET: ${{ matrix.target }} - _EXTRA_: ${{ matrix.extra }} - TARGET_RUSTFLAGS: ${{ matrix.target_rustflags }} - - - name: Create an Issue for Release Failure - if: ${{ failure() }} - uses: JasonEtco/create-an-issue@v2.9.2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - update_existing: true - search_existing: open - filename: .github/AUTO_ISSUE_TEMPLATE/nightly-build-fail.md - - - name: Set Outputs of Short SHA - id: vars - run: | - echo "date=$(date -u +'%Y-%m-%d')" >> $GITHUB_OUTPUT - sha_short=$(git rev-parse --short HEAD) - echo "sha_short=${sha_short:0:7}" >> $GITHUB_OUTPUT - - # REF: https://github.com/marketplace/actions/gh-release - # Create a release only in nushell/nightly repo - - name: Publish Archive - uses: softprops/action-gh-release@v2.0.5 - if: ${{ startsWith(github.repository, 'nushell/nightly') }} - with: - draft: false - prerelease: true - name: Nu-nightly-${{ steps.vars.outputs.date }}-${{ steps.vars.outputs.sha_short }} - tag_name: nightly-${{ steps.vars.outputs.sha_short }} - body: | - This is a NIGHTLY build of Nushell. - It is NOT recommended for production use. - files: ${{ steps.nu.outputs.archive }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - cleanup: name: Cleanup # Should only run in nushell/nightly repo diff --git a/.github/workflows/release-pkg.nu b/.github/workflows/release-pkg.nu index 046ea2475e..da2779f6d1 100755 --- a/.github/workflows/release-pkg.nu +++ b/.github/workflows/release-pkg.nu @@ -9,7 +9,6 @@ # Instructions for manually creating an MSI for Winget Releases when they fail # Added 2022-11-29 when Windows packaging wouldn't work # Updated again on 2023-02-23 because msis are still failing validation -# Update on 2023-10-18 to use RELEASE_TYPE env var to determine if full or not # To run this manual for windows here are the steps I take # checkout the release you want to publish # 1. git checkout 0.86.0 @@ -17,28 +16,26 @@ # 2. $env:CARGO_TARGET_DIR = "" # 2. hide-env CARGO_TARGET_DIR # 3. $env.TARGET = 'x86_64-pc-windows-msvc' -# 4. $env.TARGET_RUSTFLAGS = '' -# 5. $env.GITHUB_WORKSPACE = 'D:\nushell' -# 6. $env.GITHUB_OUTPUT = 'D:\nushell\output\out.txt' -# 7. $env.OS = 'windows-latest' -# 8. $env.RELEASE_TYPE = '' # There is full and '' for normal releases +# 4. $env.GITHUB_WORKSPACE = 'D:\nushell' +# 5. $env.GITHUB_OUTPUT = 'D:\nushell\output\out.txt' +# 6. $env.OS = 'windows-latest' # make sure 7z.exe is in your path https://www.7-zip.org/download.html -# 9. $env.Path = ($env.Path | append 'c:\apps\7-zip') +# 7. $env.Path = ($env.Path | append 'c:\apps\7-zip') # make sure aria2c.exe is in your path https://github.com/aria2/aria2 -# 10. $env.Path = ($env.Path | append 'c:\path\to\aria2c') +# 8. $env.Path = ($env.Path | append 'c:\path\to\aria2c') # make sure you have the wixtools installed https://wixtoolset.org/ -# 11. $env.Path = ($env.Path | append 'C:\Users\dschroeder\AppData\Local\tauri\WixTools') +# 9. $env.Path = ($env.Path | append 'C:\Users\dschroeder\AppData\Local\tauri\WixTools') # You need to run the release-pkg twice. The first pass, with _EXTRA_ as 'bin', makes the output # folder and builds everything. The second pass, that generates the msi file, with _EXTRA_ as 'msi' -# 12. $env._EXTRA_ = 'bin' -# 13. source .github\workflows\release-pkg.nu -# 14. cd .. -# 15. $env._EXTRA_ = 'msi' -# 16. source .github\workflows\release-pkg.nu +# 10. $env._EXTRA_ = 'bin' +# 11. source .github\workflows\release-pkg.nu +# 12. cd .. +# 13. $env._EXTRA_ = 'msi' +# 14. source .github\workflows\release-pkg.nu # After msi is generated, you have to update winget-pkgs repo, you'll need to patch the release # by deleting the existing msi and uploading this new msi. Then you'll need to update the hash # on the winget-pkgs PR. To generate the hash, run this command -# 17. open target\wix\nu-0.74.0-x86_64-pc-windows-msvc.msi | hash sha256 +# 15. open target\wix\nu-0.74.0-x86_64-pc-windows-msvc.msi | hash sha256 # Then, just take the output and put it in the winget-pkgs PR for the hash on the msi @@ -48,31 +45,15 @@ let os = $env.OS let target = $env.TARGET # Repo source dir like `/home/runner/work/nushell/nushell` let src = $env.GITHUB_WORKSPACE -let flags = $env.TARGET_RUSTFLAGS let dist = $'($env.GITHUB_WORKSPACE)/output' let version = (open Cargo.toml | get package.version) print $'Debugging info:' -print { version: $version, bin: $bin, os: $os, releaseType: $env.RELEASE_TYPE, target: $target, src: $src, flags: $flags, dist: $dist }; hr-line -b - -# Rename the full release name so that we won't break the existing scripts for standard release downloading, such as: -# curl -s https://api.github.com/repos/chmln/sd/releases/latest | grep browser_download_url | cut -d '"' -f 4 | grep x86_64-unknown-linux-musl -const FULL_RLS_NAMING = { - x86_64-apple-darwin: 'x86_64-darwin-full', - aarch64-apple-darwin: 'aarch64-darwin-full', - x86_64-unknown-linux-gnu: 'x86_64-linux-gnu-full', - x86_64-pc-windows-msvc: 'x86_64-windows-msvc-full', - x86_64-unknown-linux-musl: 'x86_64-linux-musl-full', - aarch64-unknown-linux-gnu: 'aarch64-linux-gnu-full', - aarch64-pc-windows-msvc: 'aarch64-windows-msvc-full', - riscv64gc-unknown-linux-gnu: 'riscv64-linux-gnu-full', - armv7-unknown-linux-gnueabihf: 'armv7-linux-gnueabihf-full', -} +print { version: $version, bin: $bin, os: $os, target: $target, src: $src, dist: $dist }; hr-line -b # $env let USE_UBUNTU = $os starts-with ubuntu -let FULL_NAME = $FULL_RLS_NAMING | get -i $target | default 'unknown-target-full' print $'(char nl)Packaging ($bin) v($version) for ($target) in ($src)...'; hr-line -b if not ('Cargo.lock' | path exists) { cargo generate-lockfile } @@ -91,23 +72,23 @@ if $os in ['macos-latest'] or $USE_UBUNTU { 'aarch64-unknown-linux-gnu' => { sudo apt-get install gcc-aarch64-linux-gnu -y $env.CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER = 'aarch64-linux-gnu-gcc' - cargo-build-nu $flags + cargo-build-nu } 'riscv64gc-unknown-linux-gnu' => { sudo apt-get install gcc-riscv64-linux-gnu -y $env.CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER = 'riscv64-linux-gnu-gcc' - cargo-build-nu $flags + cargo-build-nu } 'armv7-unknown-linux-gnueabihf' => { sudo apt-get install pkg-config gcc-arm-linux-gnueabihf -y $env.CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER = 'arm-linux-gnueabihf-gcc' - cargo-build-nu $flags + cargo-build-nu } _ => { # musl-tools to fix 'Failed to find tool. Is `musl-gcc` installed?' # Actually just for x86_64-unknown-linux-musl target if $USE_UBUNTU { sudo apt install musl-tools -y } - cargo-build-nu $flags + cargo-build-nu } } } @@ -116,7 +97,7 @@ if $os in ['macos-latest'] or $USE_UBUNTU { # Build for Windows without static-link-openssl feature # ---------------------------------------------------------------------------- if $os in ['windows-latest'] { - cargo-build-nu $flags + cargo-build-nu } # ---------------------------------------------------------------------------- @@ -162,7 +143,7 @@ cd $dist; print $'(char nl)Creating release archive...'; hr-line if $os in ['macos-latest'] or $USE_UBUNTU { let files = (ls | get name) - let dest = if $env.RELEASE_TYPE == 'full' { $'($bin)-($version)-($FULL_NAME)' } else { $'($bin)-($version)-($target)' } + let dest = $'($bin)-($version)-($target)' let archive = $'($dist)/($dest).tar.gz' mkdir $dest @@ -177,7 +158,7 @@ if $os in ['macos-latest'] or $USE_UBUNTU { } else if $os == 'windows-latest' { - let releaseStem = if $env.RELEASE_TYPE == 'full' { $'($bin)-($version)-($FULL_NAME)' } else { $'($bin)-($version)-($target)' } + let releaseStem = $'($bin)-($version)-($target)' print $'(char nl)Download less related stuffs...'; hr-line aria2c https://github.com/jftuga/less-Windows/releases/download/less-v608/less.exe -o less.exe @@ -214,19 +195,11 @@ if $os in ['macos-latest'] or $USE_UBUNTU { } } -def 'cargo-build-nu' [ options: string ] { - if ($options | str trim | is-empty) { - if $os == 'windows-latest' { - cargo build --release --all --target $target - } else { - cargo build --release --all --target $target --features=static-link-openssl - } +def 'cargo-build-nu' [] { + if $os == 'windows-latest' { + cargo build --release --all --target $target } else { - if $os == 'windows-latest' { - cargo build --release --all --target $target $options - } else { - cargo build --release --all --target $target --features=static-link-openssl $options - } + cargo build --release --all --target $target --features=static-link-openssl } } diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ffe653bd22..fb1b384d54 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,41 +34,30 @@ jobs: include: - target: aarch64-apple-darwin os: macos-latest - target_rustflags: '' - target: x86_64-apple-darwin os: macos-latest - target_rustflags: '' - target: x86_64-pc-windows-msvc extra: 'bin' os: windows-latest - target_rustflags: '' - target: x86_64-pc-windows-msvc extra: msi os: windows-latest - target_rustflags: '' - target: aarch64-pc-windows-msvc extra: 'bin' os: windows-latest - target_rustflags: '' - target: aarch64-pc-windows-msvc extra: msi os: windows-latest - target_rustflags: '' - target: x86_64-unknown-linux-gnu os: ubuntu-20.04 - target_rustflags: '' - target: x86_64-unknown-linux-musl os: ubuntu-20.04 - target_rustflags: '' - target: aarch64-unknown-linux-gnu os: ubuntu-20.04 - target_rustflags: '' - target: armv7-unknown-linux-gnueabihf os: ubuntu-20.04 - target_rustflags: '' - target: riscv64gc-unknown-linux-gnu os: ubuntu-latest - target_rustflags: '' runs-on: ${{matrix.os}} @@ -81,7 +70,7 @@ jobs: - name: Setup Rust toolchain uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 - # WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135` + # WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135` with: cache: false rustflags: '' @@ -95,102 +84,10 @@ jobs: id: nu run: nu .github/workflows/release-pkg.nu env: - RELEASE_TYPE: standard OS: ${{ matrix.os }} REF: ${{ github.ref }} TARGET: ${{ matrix.target }} _EXTRA_: ${{ matrix.extra }} - TARGET_RUSTFLAGS: ${{ matrix.target_rustflags }} - - # REF: https://github.com/marketplace/actions/gh-release - - name: Publish Archive - uses: softprops/action-gh-release@v2.0.5 - if: ${{ startsWith(github.ref, 'refs/tags/') }} - with: - draft: true - files: ${{ steps.nu.outputs.archive }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - full: - name: Full - - strategy: - fail-fast: false - matrix: - target: - - aarch64-apple-darwin - - x86_64-apple-darwin - - x86_64-pc-windows-msvc - - aarch64-pc-windows-msvc - - x86_64-unknown-linux-gnu - - x86_64-unknown-linux-musl - - aarch64-unknown-linux-gnu - extra: ['bin'] - include: - - target: aarch64-apple-darwin - os: macos-latest - target_rustflags: '--features=dataframe' - - target: x86_64-apple-darwin - os: macos-latest - target_rustflags: '--features=dataframe' - - target: x86_64-pc-windows-msvc - extra: 'bin' - os: windows-latest - target_rustflags: '--features=dataframe' - - target: x86_64-pc-windows-msvc - extra: msi - os: windows-latest - target_rustflags: '--features=dataframe' - - target: aarch64-pc-windows-msvc - extra: 'bin' - os: windows-latest - target_rustflags: '--features=dataframe' - - target: aarch64-pc-windows-msvc - extra: msi - os: windows-latest - target_rustflags: '--features=dataframe' - - target: x86_64-unknown-linux-gnu - os: ubuntu-20.04 - target_rustflags: '--features=dataframe' - - target: x86_64-unknown-linux-musl - os: ubuntu-20.04 - target_rustflags: '--features=dataframe' - - target: aarch64-unknown-linux-gnu - os: ubuntu-20.04 - target_rustflags: '--features=dataframe' - - runs-on: ${{matrix.os}} - - steps: - - uses: actions/checkout@v4.1.5 - - - name: Update Rust Toolchain Target - run: | - echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml - - - name: Setup Rust toolchain - uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 - # WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135` - with: - cache: false - rustflags: '' - - - name: Setup Nushell - uses: hustcer/setup-nu@v3.10 - with: - version: 0.93.0 - - - name: Release Nu Binary - id: nu - run: nu .github/workflows/release-pkg.nu - env: - RELEASE_TYPE: full - OS: ${{ matrix.os }} - REF: ${{ github.ref }} - TARGET: ${{ matrix.target }} - _EXTRA_: ${{ matrix.extra }} - TARGET_RUSTFLAGS: ${{ matrix.target_rustflags }} # REF: https://github.com/marketplace/actions/gh-release - name: Publish Archive diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d5cf758b56..6d7c256d4c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -71,11 +71,6 @@ Read cargo's documentation for more details: https://doc.rust-lang.org/cargo/ref cargo run ``` -- Build and run with dataframe support. - ```nushell - cargo run --features=dataframe - ``` - - Run Clippy on Nushell: ```nushell @@ -93,11 +88,6 @@ Read cargo's documentation for more details: https://doc.rust-lang.org/cargo/ref cargo test --workspace ``` - along with dataframe tests - - ```nushell - cargo test --workspace --features=dataframe - ``` or via the `toolkit.nu` command: ```nushell use toolkit.nu test @@ -240,7 +230,7 @@ You can help us to make the review process a smooth experience: - Choose what simplifies having confidence in the conflict resolution and the review. **Merge commits in your branch are OK** in the squash model. - Feel free to notify your reviewers or affected PR authors if your change might cause larger conflicts with another change. - During the rollup of multiple PRs, we may choose to resolve merge conflicts and CI failures ourselves. (Allow maintainers to push to your branch to enable us to do this quickly.) - + ## License We use the [MIT License](https://github.com/nushell/nushell/blob/main/LICENSE) in all of our Nushell projects. If you are including or referencing a crate that uses the [GPL License](https://www.gnu.org/licenses/gpl-3.0.en.html#license-text) unfortunately we will not be able to accept your PR. diff --git a/Cargo.lock b/Cargo.lock index ad5a1e3a76..fb792cbd2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2782,7 +2782,6 @@ dependencies = [ "nix", "nu-cli", "nu-cmd-base", - "nu-cmd-dataframe", "nu-cmd-extra", "nu-cmd-lang", "nu-cmd-plugin", @@ -2870,29 +2869,6 @@ dependencies = [ "nu-protocol", ] -[[package]] -name = "nu-cmd-dataframe" -version = "0.93.1" -dependencies = [ - "chrono", - "chrono-tz 0.8.6", - "fancy-regex", - "indexmap", - "nu-cmd-lang", - "nu-engine", - "nu-parser", - "nu-protocol", - "num", - "polars", - "polars-arrow", - "polars-io", - "polars-ops", - "polars-plan", - "polars-utils", - "serde", - "sqlparser 0.45.0", -] - [[package]] name = "nu-cmd-extra" version = "0.93.1" diff --git a/Cargo.toml b/Cargo.toml index 2e9c7e0b0f..afc31383f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,6 @@ members = [ "crates/nu-cmd-extra", "crates/nu-cmd-lang", "crates/nu-cmd-plugin", - "crates/nu-cmd-dataframe", "crates/nu-command", "crates/nu-color-config", "crates/nu-explore", @@ -179,9 +178,6 @@ nu-cli = { path = "./crates/nu-cli", version = "0.93.1" } nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.93.1" } nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.93.1" } nu-cmd-plugin = { path = "./crates/nu-cmd-plugin", version = "0.93.1", optional = true } -nu-cmd-dataframe = { path = "./crates/nu-cmd-dataframe", version = "0.93.1", features = [ - "dataframe", -], optional = true } nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.93.1" } nu-command = { path = "./crates/nu-command", version = "0.93.1" } nu-engine = { path = "./crates/nu-engine", version = "0.93.1" } @@ -271,9 +267,6 @@ system-clipboard = [ which-support = ["nu-command/which-support", "nu-cmd-lang/which-support"] trash-support = ["nu-command/trash-support", "nu-cmd-lang/trash-support"] -# Dataframe feature for nushell -dataframe = ["dep:nu-cmd-dataframe", "nu-cmd-lang/dataframe"] - # SQLite commands for nushell sqlite = ["nu-command/sqlite", "nu-cmd-lang/sqlite"] diff --git a/crates/nu-cmd-dataframe/Cargo.toml b/crates/nu-cmd-dataframe/Cargo.toml deleted file mode 100644 index a156435a8d..0000000000 --- a/crates/nu-cmd-dataframe/Cargo.toml +++ /dev/null @@ -1,75 +0,0 @@ -[package] -authors = ["The Nushell Project Developers"] -description = "Nushell's dataframe commands based on polars." -edition = "2021" -license = "MIT" -name = "nu-cmd-dataframe" -repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-dataframe" -version = "0.93.1" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -bench = false - -[dependencies] -nu-engine = { path = "../nu-engine", version = "0.93.1" } -nu-parser = { path = "../nu-parser", version = "0.93.1" } -nu-protocol = { path = "../nu-protocol", version = "0.93.1" } - -# Potential dependencies for extras -chrono = { workspace = true, features = ["std", "unstable-locales"], default-features = false } -chrono-tz = { workspace = true } -fancy-regex = { workspace = true } -indexmap = { workspace = true } -num = { version = "0.4", optional = true } -serde = { workspace = true, features = ["derive"] } -# keep sqlparser at 0.39.0 until we can update polars -sqlparser = { version = "0.45", optional = true } -polars-io = { version = "0.39", features = ["avro"], optional = true } -polars-arrow = { version = "0.39", optional = true } -polars-ops = { version = "0.39", optional = true } -polars-plan = { version = "0.39", features = ["regex"], optional = true } -polars-utils = { version = "0.39", optional = true } - -[dependencies.polars] -features = [ - "arg_where", - "checked_arithmetic", - "concat_str", - "cross_join", - "csv", - "cum_agg", - "dtype-categorical", - "dtype-datetime", - "dtype-struct", - "dtype-i8", - "dtype-i16", - "dtype-u8", - "dtype-u16", - "dynamic_group_by", - "ipc", - "is_in", - "json", - "lazy", - "object", - "parquet", - "random", - "rolling_window", - "rows", - "serde", - "serde-lazy", - "strings", - "temporal", - "to_dummies", -] -default-features = false -optional = true -version = "0.39" - -[features] -dataframe = ["num", "polars", "polars-io", "polars-arrow", "polars-ops", "polars-plan", "polars-utils", "sqlparser"] -default = [] - -[dev-dependencies] -nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.93.1" } diff --git a/crates/nu-cmd-dataframe/LICENSE b/crates/nu-cmd-dataframe/LICENSE deleted file mode 100644 index ae174e8595..0000000000 --- a/crates/nu-cmd-dataframe/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019 - 2023 The Nushell Project Developers - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/crates/nu-cmd-dataframe/src/dataframe/README.md b/crates/nu-cmd-dataframe/src/dataframe/README.md deleted file mode 100644 index 593217ede6..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Dataframe - -This dataframe directory holds all of the definitions of the dataframe data structures and commands. - -There are three sections of commands: - -* [eager](./eager) -* [series](./series) -* [values](./values) - -For more details see the -[Nushell book section on dataframes](https://www.nushell.sh/book/dataframes.html) diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/append.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/append.rs deleted file mode 100644 index c0be67ed6e..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/append.rs +++ /dev/null @@ -1,134 +0,0 @@ -use crate::dataframe::values::{Axis, Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct AppendDF; - -impl Command for AppendDF { - fn name(&self) -> &str { - "dfr append" - } - - fn usage(&self) -> &str { - "Appends a new dataframe." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("other", SyntaxShape::Any, "dataframe to be appended") - .switch("col", "appends in col orientation", Some('c')) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Appends a dataframe as new columns", - example: r#"let a = ([[a b]; [1 2] [3 4]] | dfr into-df); - $a | dfr append $a"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(1), Value::test_int(3)], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(2), Value::test_int(4)], - ), - Column::new( - "a_x".to_string(), - vec![Value::test_int(1), Value::test_int(3)], - ), - Column::new( - "b_x".to_string(), - vec![Value::test_int(2), Value::test_int(4)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Appends a dataframe merging at the end of columns", - example: r#"let a = ([[a b]; [1 2] [3 4]] | dfr into-df); - $a | dfr append $a --col"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![ - Value::test_int(1), - Value::test_int(3), - Value::test_int(1), - Value::test_int(3), - ], - ), - Column::new( - "b".to_string(), - vec![ - Value::test_int(2), - Value::test_int(4), - Value::test_int(2), - Value::test_int(4), - ], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let other: Value = call.req(engine_state, stack, 0)?; - - let axis = if call.has_flag(engine_state, stack, "col")? { - Axis::Column - } else { - Axis::Row - }; - let df_other = NuDataFrame::try_from_value(other)?; - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - df.append_df(&df_other, axis, call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(AppendDF {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/cast.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/cast.rs deleted file mode 100644 index be9c33a229..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/cast.rs +++ /dev/null @@ -1,195 +0,0 @@ -use crate::dataframe::values::{str_to_dtype, NuDataFrame, NuExpression, NuLazyFrame}; -use nu_engine::command_prelude::*; - -use polars::prelude::*; - -#[derive(Clone)] -pub struct CastDF; - -impl Command for CastDF { - fn name(&self) -> &str { - "dfr cast" - } - - fn usage(&self) -> &str { - "Cast a column to a different dtype." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_types(vec![ - ( - Type::Custom("expression".into()), - Type::Custom("expression".into()), - ), - ( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ), - ]) - .required( - "dtype", - SyntaxShape::String, - "The dtype to cast the column to", - ) - .optional( - "column", - SyntaxShape::String, - "The column to cast. Required when used with a dataframe.", - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Cast a column in a dataframe to a different dtype", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr cast u8 a | dfr schema", - result: Some(Value::record( - record! { - "a" => Value::string("u8", Span::test_data()), - "b" => Value::string("i64", Span::test_data()), - }, - Span::test_data(), - )), - }, - Example { - description: "Cast a column in a lazy dataframe to a different dtype", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr into-lazy | dfr cast u8 a | dfr schema", - result: Some(Value::record( - record! { - "a" => Value::string("u8", Span::test_data()), - "b" => Value::string("i64", Span::test_data()), - }, - Span::test_data(), - )), - }, - Example { - description: "Cast a column in a expression to a different dtype", - example: r#"[[a b]; [1 2] [1 4]] | dfr into-df | dfr group-by a | dfr agg [ (dfr col b | dfr cast u8 | dfr min | dfr as "b_min") ] | dfr schema"#, - result: None - } - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let value = input.into_value(call.head)?; - if NuLazyFrame::can_downcast(&value) { - let (dtype, column_nm) = df_args(engine_state, stack, call)?; - let df = NuLazyFrame::try_from_value(value)?; - command_lazy(call, column_nm, dtype, df) - } else if NuDataFrame::can_downcast(&value) { - let (dtype, column_nm) = df_args(engine_state, stack, call)?; - let df = NuDataFrame::try_from_value(value)?; - command_eager(call, column_nm, dtype, df) - } else { - let dtype: String = call.req(engine_state, stack, 0)?; - let dtype = str_to_dtype(&dtype, call.head)?; - - let expr = NuExpression::try_from_value(value)?; - let expr: NuExpression = expr.into_polars().cast(dtype).into(); - - Ok(PipelineData::Value( - NuExpression::into_value(expr, call.head), - None, - )) - } - } -} - -fn df_args( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, -) -> Result<(DataType, String), ShellError> { - let dtype = dtype_arg(engine_state, stack, call)?; - let column_nm: String = - call.opt(engine_state, stack, 1)? - .ok_or(ShellError::MissingParameter { - param_name: "column_name".into(), - span: call.head, - })?; - Ok((dtype, column_nm)) -} - -fn dtype_arg( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, -) -> Result { - let dtype: String = call.req(engine_state, stack, 0)?; - str_to_dtype(&dtype, call.head) -} - -fn command_lazy( - call: &Call, - column_nm: String, - dtype: DataType, - lazy: NuLazyFrame, -) -> Result { - let column = col(&column_nm).cast(dtype); - let lazy = lazy.into_polars().with_columns(&[column]); - let lazy = NuLazyFrame::new(false, lazy); - - Ok(PipelineData::Value( - NuLazyFrame::into_value(lazy, call.head)?, - None, - )) -} - -fn command_eager( - call: &Call, - column_nm: String, - dtype: DataType, - nu_df: NuDataFrame, -) -> Result { - let mut df = nu_df.df; - let column = df - .column(&column_nm) - .map_err(|e| ShellError::GenericError { - error: format!("{e}"), - msg: "".into(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let casted = column.cast(&dtype).map_err(|e| ShellError::GenericError { - error: format!("{e}"), - msg: "".into(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let _ = df - .with_column(casted) - .map_err(|e| ShellError::GenericError { - error: format!("{e}"), - msg: "".into(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let df = NuDataFrame::new(false, df); - Ok(PipelineData::Value(df.into_value(call.head), None)) -} - -#[cfg(test)] -mod test { - - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(CastDF {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/columns.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/columns.rs deleted file mode 100644 index c9167659b5..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/columns.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::dataframe::values::NuDataFrame; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct ColumnsDF; - -impl Command for ColumnsDF { - fn name(&self) -> &str { - "dfr columns" - } - - fn usage(&self) -> &str { - "Show dataframe columns." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type(Type::Custom("dataframe".into()), Type::Any) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Dataframe columns", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr columns", - result: Some(Value::list( - vec![Value::test_string("a"), Value::test_string("b")], - Span::test_data(), - )), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let names: Vec = df - .as_ref() - .get_column_names() - .iter() - .map(|v| Value::string(*v, call.head)) - .collect(); - - let names = Value::list(names, call.head); - - Ok(PipelineData::Value(names, None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(ColumnsDF {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/drop.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/drop.rs deleted file mode 100644 index 8f9d086947..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/drop.rs +++ /dev/null @@ -1,115 +0,0 @@ -use crate::dataframe::values::{utils::convert_columns, Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct DropDF; - -impl Command for DropDF { - fn name(&self) -> &str { - "dfr drop" - } - - fn usage(&self) -> &str { - "Creates a new dataframe by dropping the selected columns." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .rest("rest", SyntaxShape::Any, "column names to be dropped") - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "drop column a", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr drop a", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "b".to_string(), - vec![Value::test_int(2), Value::test_int(4)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let columns: Vec = call.rest(engine_state, stack, 0)?; - let (col_string, col_span) = convert_columns(columns, call.head)?; - - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let new_df = col_string - .first() - .ok_or_else(|| ShellError::GenericError { - error: "Empty names list".into(), - msg: "No column names were found".into(), - span: Some(col_span), - help: None, - inner: vec![], - }) - .and_then(|col| { - df.as_ref() - .drop(&col.item) - .map_err(|e| ShellError::GenericError { - error: "Error dropping column".into(), - msg: e.to_string(), - span: Some(col.span), - help: None, - inner: vec![], - }) - })?; - - // If there are more columns in the drop selection list, these - // are added from the resulting dataframe - col_string - .iter() - .skip(1) - .try_fold(new_df, |new_df, col| { - new_df - .drop(&col.item) - .map_err(|e| ShellError::GenericError { - error: "Error dropping column".into(), - msg: e.to_string(), - span: Some(col.span), - help: None, - inner: vec![], - }) - }) - .map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(DropDF {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/drop_duplicates.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/drop_duplicates.rs deleted file mode 100644 index b2ae6f7cfc..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/drop_duplicates.rs +++ /dev/null @@ -1,119 +0,0 @@ -use crate::dataframe::values::{utils::convert_columns_string, Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -use polars::prelude::UniqueKeepStrategy; - -#[derive(Clone)] -pub struct DropDuplicates; - -impl Command for DropDuplicates { - fn name(&self) -> &str { - "dfr drop-duplicates" - } - - fn usage(&self) -> &str { - "Drops duplicate values in dataframe." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .optional( - "subset", - SyntaxShape::Table(vec![]), - "subset of columns to drop duplicates", - ) - .switch("maintain", "maintain order", Some('m')) - .switch( - "last", - "keeps last duplicate value (by default keeps first)", - Some('l'), - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "drop duplicates", - example: "[[a b]; [1 2] [3 4] [1 2]] | dfr into-df | dfr drop-duplicates", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(3), Value::test_int(1)], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(4), Value::test_int(2)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let columns: Option> = call.opt(engine_state, stack, 0)?; - let (subset, col_span) = match columns { - Some(cols) => { - let (agg_string, col_span) = convert_columns_string(cols, call.head)?; - (Some(agg_string), col_span) - } - None => (None, call.head), - }; - - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let subset_slice = subset.as_ref().map(|cols| &cols[..]); - - let keep_strategy = if call.has_flag(engine_state, stack, "last")? { - UniqueKeepStrategy::Last - } else { - UniqueKeepStrategy::First - }; - - df.as_ref() - .unique(subset_slice, keep_strategy, None) - .map_err(|e| ShellError::GenericError { - error: "Error dropping duplicates".into(), - msg: e.to_string(), - span: Some(col_span), - help: None, - inner: vec![], - }) - .map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(DropDuplicates {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/drop_nulls.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/drop_nulls.rs deleted file mode 100644 index 25a3907426..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/drop_nulls.rs +++ /dev/null @@ -1,137 +0,0 @@ -use crate::dataframe::values::{utils::convert_columns_string, Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct DropNulls; - -impl Command for DropNulls { - fn name(&self) -> &str { - "dfr drop-nulls" - } - - fn usage(&self) -> &str { - "Drops null values in dataframe." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .optional( - "subset", - SyntaxShape::Table(vec![]), - "subset of columns to drop nulls", - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "drop null values in dataframe", - example: r#"let df = ([[a b]; [1 2] [3 0] [1 2]] | dfr into-df); - let res = ($df.b / $df.b); - let a = ($df | dfr with-column $res --name res); - $a | dfr drop-nulls"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(1), Value::test_int(1)], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(2), Value::test_int(2)], - ), - Column::new( - "res".to_string(), - vec![Value::test_int(1), Value::test_int(1)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "drop null values in dataframe", - example: r#"let s = ([1 2 0 0 3 4] | dfr into-df); - ($s / $s) | dfr drop-nulls"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "div_0_0".to_string(), - vec![ - Value::test_int(1), - Value::test_int(1), - Value::test_int(1), - Value::test_int(1), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let columns: Option> = call.opt(engine_state, stack, 0)?; - - let (subset, col_span) = match columns { - Some(cols) => { - let (agg_string, col_span) = convert_columns_string(cols, call.head)?; - (Some(agg_string), col_span) - } - None => (None, call.head), - }; - - let subset_slice = subset.as_ref().map(|cols| &cols[..]); - - df.as_ref() - .drop_nulls(subset_slice) - .map_err(|e| ShellError::GenericError { - error: "Error dropping nulls".into(), - msg: e.to_string(), - span: Some(col_span), - help: None, - inner: vec![], - }) - .map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::super::WithColumn; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(DropNulls {}), Box::new(WithColumn {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/dtypes.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/dtypes.rs deleted file mode 100644 index a572a49551..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/dtypes.rs +++ /dev/null @@ -1,104 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct DataTypes; - -impl Command for DataTypes { - fn name(&self) -> &str { - "dfr dtypes" - } - - fn usage(&self) -> &str { - "Show dataframe data types." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Dataframe dtypes", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr dtypes", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "column".to_string(), - vec![Value::test_string("a"), Value::test_string("b")], - ), - Column::new( - "dtype".to_string(), - vec![Value::test_string("i64"), Value::test_string("i64")], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let mut dtypes: Vec = Vec::new(); - let names: Vec = df - .as_ref() - .get_column_names() - .iter() - .map(|v| { - let dtype = df - .as_ref() - .column(v) - .expect("using name from list of names from dataframe") - .dtype(); - - let dtype_str = dtype.to_string(); - - dtypes.push(Value::string(dtype_str, call.head)); - - Value::string(*v, call.head) - }) - .collect(); - - let names_col = Column::new("column".to_string(), names); - let dtypes_col = Column::new("dtype".to_string(), dtypes); - - NuDataFrame::try_from_columns(vec![names_col, dtypes_col], None) - .map(|df| PipelineData::Value(df.into_value(call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(DataTypes {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/dummies.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/dummies.rs deleted file mode 100644 index f47f65a004..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/dummies.rs +++ /dev/null @@ -1,107 +0,0 @@ -use crate::dataframe::values::NuDataFrame; -use nu_engine::command_prelude::*; - -use polars::{prelude::*, series::Series}; - -#[derive(Clone)] -pub struct Dummies; - -impl Command for Dummies { - fn name(&self) -> &str { - "dfr dummies" - } - - fn usage(&self) -> &str { - "Creates a new dataframe with dummy variables." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .switch("drop-first", "Drop first row", Some('d')) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Create new dataframe with dummy variables from a dataframe", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr dummies", - result: Some( - NuDataFrame::try_from_series( - vec![ - Series::new("a_1", &[1_u8, 0]), - Series::new("a_3", &[0_u8, 1]), - Series::new("b_2", &[1_u8, 0]), - Series::new("b_4", &[0_u8, 1]), - ], - Span::test_data(), - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Create new dataframe with dummy variables from a series", - example: "[1 2 2 3 3] | dfr into-df | dfr dummies", - result: Some( - NuDataFrame::try_from_series( - vec![ - Series::new("0_1", &[1_u8, 0, 0, 0, 0]), - Series::new("0_2", &[0_u8, 1, 1, 0, 0]), - Series::new("0_3", &[0_u8, 0, 0, 1, 1]), - ], - Span::test_data(), - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let drop_first: bool = call.has_flag(engine_state, stack, "drop-first")?; - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - df.as_ref() - .to_dummies(None, drop_first) - .map_err(|e| ShellError::GenericError { - error: "Error calculating dummies".into(), - msg: e.to_string(), - span: Some(call.head), - help: Some("The only allowed column types for dummies are String or Int".into()), - inner: vec![], - }) - .map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(Dummies {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/filter_with.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/filter_with.rs deleted file mode 100644 index e0e94d10a0..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/filter_with.rs +++ /dev/null @@ -1,154 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression, NuLazyFrame}; -use nu_engine::command_prelude::*; - -use polars::prelude::LazyFrame; - -#[derive(Clone)] -pub struct FilterWith; - -impl Command for FilterWith { - fn name(&self) -> &str { - "dfr filter-with" - } - - fn usage(&self) -> &str { - "Filters dataframe using a mask or expression as reference." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "mask or expression", - SyntaxShape::Any, - "boolean mask used to filter data", - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe or lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Filter dataframe using a bool mask", - example: r#"let mask = ([true false] | dfr into-df); - [[a b]; [1 2] [3 4]] | dfr into-df | dfr filter-with $mask"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new("a".to_string(), vec![Value::test_int(1)]), - Column::new("b".to_string(), vec![Value::test_int(2)]), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Filter dataframe using an expression", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr filter-with ((dfr col a) > 1)", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new("a".to_string(), vec![Value::test_int(3)]), - Column::new("b".to_string(), vec![Value::test_int(4)]), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let value = input.into_value(call.head)?; - if NuLazyFrame::can_downcast(&value) { - let df = NuLazyFrame::try_from_value(value)?; - command_lazy(engine_state, stack, call, df) - } else { - let df = NuDataFrame::try_from_value(value)?; - command_eager(engine_state, stack, call, df) - } - } -} - -fn command_eager( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - df: NuDataFrame, -) -> Result { - let mask_value: Value = call.req(engine_state, stack, 0)?; - let mask_span = mask_value.span(); - - if NuExpression::can_downcast(&mask_value) { - let expression = NuExpression::try_from_value(mask_value)?; - let lazy = NuLazyFrame::new(true, df.lazy()); - let lazy = lazy.apply_with_expr(expression, LazyFrame::filter); - - Ok(PipelineData::Value( - NuLazyFrame::into_value(lazy, call.head)?, - None, - )) - } else { - let mask = NuDataFrame::try_from_value(mask_value)?.as_series(mask_span)?; - let mask = mask.bool().map_err(|e| ShellError::GenericError { - error: "Error casting to bool".into(), - msg: e.to_string(), - span: Some(mask_span), - help: Some("Perhaps you want to use a series with booleans as mask".into()), - inner: vec![], - })?; - - df.as_ref() - .filter(mask) - .map_err(|e| ShellError::GenericError { - error: "Error filtering dataframe".into(), - msg: e.to_string(), - span: Some(call.head), - help: Some("The only allowed column types for dummies are String or Int".into()), - inner: vec![], - }) - .map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None)) - } -} - -fn command_lazy( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - lazy: NuLazyFrame, -) -> Result { - let expr: Value = call.req(engine_state, stack, 0)?; - let expr = NuExpression::try_from_value(expr)?; - - let lazy = lazy.apply_with_expr(expr, LazyFrame::filter); - - Ok(PipelineData::Value( - NuLazyFrame::into_value(lazy, call.head)?, - None, - )) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - use crate::dataframe::expressions::ExprCol; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(FilterWith {}), Box::new(ExprCol {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/first.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/first.rs deleted file mode 100644 index 14c86e8c40..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/first.rs +++ /dev/null @@ -1,144 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct FirstDF; - -impl Command for FirstDF { - fn name(&self) -> &str { - "dfr first" - } - - fn usage(&self) -> &str { - "Show only the first number of rows or create a first expression" - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .optional( - "rows", - SyntaxShape::Int, - "starting from the front, the number of rows to return", - ) - .input_output_types(vec![ - ( - Type::Custom("expression".into()), - Type::Custom("expression".into()), - ), - ( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ), - ]) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Return the first row of a dataframe", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr first", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new("a".to_string(), vec![Value::test_int(1)]), - Column::new("b".to_string(), vec![Value::test_int(2)]), - ], - None, - ) - .expect("should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Return the first two rows of a dataframe", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr first 2", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(1), Value::test_int(3)], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(2), Value::test_int(4)], - ), - ], - None, - ) - .expect("should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Creates a first expression from a column", - example: "dfr col a | dfr first", - result: None, - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let value = input.into_value(call.head)?; - if NuDataFrame::can_downcast(&value) { - let df = NuDataFrame::try_from_value(value)?; - command(engine_state, stack, call, df) - } else { - let expr = NuExpression::try_from_value(value)?; - let expr: NuExpression = expr.into_polars().first().into(); - - Ok(PipelineData::Value( - NuExpression::into_value(expr, call.head), - None, - )) - } - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - df: NuDataFrame, -) -> Result { - let rows: Option = call.opt(engine_state, stack, 0)?; - let rows = rows.unwrap_or(1); - - let res = df.as_ref().head(Some(rows)); - Ok(PipelineData::Value( - NuDataFrame::dataframe_into_value(res, call.head), - None, - )) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::{build_test_engine_state, test_dataframe_example}; - use super::*; - use crate::dataframe::lazy::aggregate::LazyAggregate; - use crate::dataframe::lazy::groupby::ToLazyGroupBy; - - #[test] - fn test_examples_dataframe() { - let mut engine_state = build_test_engine_state(vec![Box::new(FirstDF {})]); - test_dataframe_example(&mut engine_state, &FirstDF.examples()[0]); - test_dataframe_example(&mut engine_state, &FirstDF.examples()[1]); - } - - #[test] - fn test_examples_expression() { - let mut engine_state = build_test_engine_state(vec![ - Box::new(FirstDF {}), - Box::new(LazyAggregate {}), - Box::new(ToLazyGroupBy {}), - ]); - test_dataframe_example(&mut engine_state, &FirstDF.examples()[2]); - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/get.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/get.rs deleted file mode 100644 index e8cf337864..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/get.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::dataframe::values::{utils::convert_columns_string, Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct GetDF; - -impl Command for GetDF { - fn name(&self) -> &str { - "dfr get" - } - - fn usage(&self) -> &str { - "Creates dataframe with the selected columns." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .rest("rest", SyntaxShape::Any, "column names to sort dataframe") - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Returns the selected column", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr get a", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "a".to_string(), - vec![Value::test_int(1), Value::test_int(3)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let columns: Vec = call.rest(engine_state, stack, 0)?; - let (col_string, col_span) = convert_columns_string(columns, call.head)?; - - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - df.as_ref() - .select(col_string) - .map_err(|e| ShellError::GenericError { - error: "Error selecting columns".into(), - msg: e.to_string(), - span: Some(col_span), - help: None, - inner: vec![], - }) - .map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(GetDF {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/last.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/last.rs deleted file mode 100644 index ff2c4f98a2..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/last.rs +++ /dev/null @@ -1,118 +0,0 @@ -use crate::dataframe::values::{utils::DEFAULT_ROWS, Column, NuDataFrame, NuExpression}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct LastDF; - -impl Command for LastDF { - fn name(&self) -> &str { - "dfr last" - } - - fn usage(&self) -> &str { - "Creates new dataframe with tail rows or creates a last expression." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .optional("rows", SyntaxShape::Int, "Number of rows for tail") - .input_output_types(vec![ - ( - Type::Custom("expression".into()), - Type::Custom("expression".into()), - ), - ( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ), - ]) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Create new dataframe with last rows", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr last 1", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new("a".to_string(), vec![Value::test_int(3)]), - Column::new("b".to_string(), vec![Value::test_int(4)]), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Creates a last expression from a column", - example: "dfr col a | dfr last", - result: None, - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let value = input.into_value(call.head)?; - if NuDataFrame::can_downcast(&value) { - let df = NuDataFrame::try_from_value(value)?; - command(engine_state, stack, call, df) - } else { - let expr = NuExpression::try_from_value(value)?; - let expr: NuExpression = expr.into_polars().last().into(); - - Ok(PipelineData::Value( - NuExpression::into_value(expr, call.head), - None, - )) - } - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - df: NuDataFrame, -) -> Result { - let rows: Option = call.opt(engine_state, stack, 0)?; - let rows = rows.unwrap_or(DEFAULT_ROWS); - - let res = df.as_ref().tail(Some(rows)); - Ok(PipelineData::Value( - NuDataFrame::dataframe_into_value(res, call.head), - None, - )) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::{build_test_engine_state, test_dataframe_example}; - use super::*; - use crate::dataframe::lazy::aggregate::LazyAggregate; - use crate::dataframe::lazy::groupby::ToLazyGroupBy; - - #[test] - fn test_examples_dataframe() { - let mut engine_state = build_test_engine_state(vec![Box::new(LastDF {})]); - test_dataframe_example(&mut engine_state, &LastDF.examples()[0]); - } - - #[test] - fn test_examples_expression() { - let mut engine_state = build_test_engine_state(vec![ - Box::new(LastDF {}), - Box::new(LazyAggregate {}), - Box::new(ToLazyGroupBy {}), - ]); - test_dataframe_example(&mut engine_state, &LastDF.examples()[1]); - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/list.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/list.rs deleted file mode 100644 index 1cee694180..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/list.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::dataframe::values::NuDataFrame; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct ListDF; - -impl Command for ListDF { - fn name(&self) -> &str { - "dfr ls" - } - - fn usage(&self) -> &str { - "Lists stored dataframes." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()).category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Creates a new dataframe and shows it in the dataframe list", - example: r#"let test = ([[a b];[1 2] [3 4]] | dfr into-df); - ls"#, - result: None, - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - _input: PipelineData, - ) -> Result { - let mut vals: Vec<(String, Value)> = vec![]; - - for overlay_frame in engine_state.active_overlays(&[]) { - for var in &overlay_frame.vars { - if let Ok(value) = stack.get_var(*var.1, call.head) { - let name = String::from_utf8_lossy(var.0).to_string(); - vals.push((name, value)); - } - } - } - - let vals = vals - .into_iter() - .filter_map(|(name, value)| { - NuDataFrame::try_from_value(value).ok().map(|df| (name, df)) - }) - .map(|(name, df)| { - Value::record( - record! { - "name" => Value::string(name, call.head), - "columns" => Value::int(df.as_ref().width() as i64, call.head), - "rows" => Value::int(df.as_ref().height() as i64, call.head), - }, - call.head, - ) - }) - .collect::>(); - - let list = Value::list(vals, call.head); - - Ok(list.into_pipeline_data()) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/melt.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/melt.rs deleted file mode 100644 index 6379e9270e..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/melt.rs +++ /dev/null @@ -1,248 +0,0 @@ -use crate::dataframe::values::{utils::convert_columns_string, Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct MeltDF; - -impl Command for MeltDF { - fn name(&self) -> &str { - "dfr melt" - } - - fn usage(&self) -> &str { - "Unpivot a DataFrame from wide to long format." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required_named( - "columns", - SyntaxShape::Table(vec![]), - "column names for melting", - Some('c'), - ) - .required_named( - "values", - SyntaxShape::Table(vec![]), - "column names used as value columns", - Some('v'), - ) - .named( - "variable-name", - SyntaxShape::String, - "optional name for variable column", - Some('r'), - ) - .named( - "value-name", - SyntaxShape::String, - "optional name for value column", - Some('l'), - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "melt dataframe", - example: - "[[a b c d]; [x 1 4 a] [y 2 5 b] [z 3 6 c]] | dfr into-df | dfr melt -c [b c] -v [a d]", - result: Some( - NuDataFrame::try_from_columns(vec![ - Column::new( - "b".to_string(), - vec![ - Value::test_int(1), - Value::test_int(2), - Value::test_int(3), - Value::test_int(1), - Value::test_int(2), - Value::test_int(3), - ], - ), - Column::new( - "c".to_string(), - vec![ - Value::test_int(4), - Value::test_int(5), - Value::test_int(6), - Value::test_int(4), - Value::test_int(5), - Value::test_int(6), - ], - ), - Column::new( - "variable".to_string(), - vec![ - Value::test_string("a"), - Value::test_string("a"), - Value::test_string("a"), - Value::test_string("d"), - Value::test_string("d"), - Value::test_string("d"), - ], - ), - Column::new( - "value".to_string(), - vec![ - Value::test_string("x"), - Value::test_string("y"), - Value::test_string("z"), - Value::test_string("a"), - Value::test_string("b"), - Value::test_string("c"), - ], - ), - ], None) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let id_col: Vec = call - .get_flag(engine_state, stack, "columns")? - .expect("required value"); - let val_col: Vec = call - .get_flag(engine_state, stack, "values")? - .expect("required value"); - - let value_name: Option> = call.get_flag(engine_state, stack, "value-name")?; - let variable_name: Option> = - call.get_flag(engine_state, stack, "variable-name")?; - - let (id_col_string, id_col_span) = convert_columns_string(id_col, call.head)?; - let (val_col_string, val_col_span) = convert_columns_string(val_col, call.head)?; - - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - check_column_datatypes(df.as_ref(), &id_col_string, id_col_span)?; - check_column_datatypes(df.as_ref(), &val_col_string, val_col_span)?; - - let mut res = df - .as_ref() - .melt(&id_col_string, &val_col_string) - .map_err(|e| ShellError::GenericError { - error: "Error calculating melt".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - if let Some(name) = &variable_name { - res.rename("variable", &name.item) - .map_err(|e| ShellError::GenericError { - error: "Error renaming column".into(), - msg: e.to_string(), - span: Some(name.span), - help: None, - inner: vec![], - })?; - } - - if let Some(name) = &value_name { - res.rename("value", &name.item) - .map_err(|e| ShellError::GenericError { - error: "Error renaming column".into(), - msg: e.to_string(), - span: Some(name.span), - help: None, - inner: vec![], - })?; - } - - Ok(PipelineData::Value( - NuDataFrame::dataframe_into_value(res, call.head), - None, - )) -} - -fn check_column_datatypes>( - df: &polars::prelude::DataFrame, - cols: &[T], - col_span: Span, -) -> Result<(), ShellError> { - if cols.is_empty() { - return Err(ShellError::GenericError { - error: "Merge error".into(), - msg: "empty column list".into(), - span: Some(col_span), - help: None, - inner: vec![], - }); - } - - // Checking if they are same type - if cols.len() > 1 { - for w in cols.windows(2) { - let l_series = df - .column(w[0].as_ref()) - .map_err(|e| ShellError::GenericError { - error: "Error selecting columns".into(), - msg: e.to_string(), - span: Some(col_span), - help: None, - inner: vec![], - })?; - - let r_series = df - .column(w[1].as_ref()) - .map_err(|e| ShellError::GenericError { - error: "Error selecting columns".into(), - msg: e.to_string(), - span: Some(col_span), - help: None, - inner: vec![], - })?; - - if l_series.dtype() != r_series.dtype() { - return Err(ShellError::GenericError { - error: "Merge error".into(), - msg: "found different column types in list".into(), - span: Some(col_span), - help: Some(format!( - "datatypes {} and {} are incompatible", - l_series.dtype(), - r_series.dtype() - )), - inner: vec![], - }); - } - } - } - - Ok(()) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(MeltDF {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/mod.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/mod.rs deleted file mode 100644 index db7a5c9312..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/mod.rs +++ /dev/null @@ -1,114 +0,0 @@ -mod append; -mod cast; -mod columns; -mod drop; -mod drop_duplicates; -mod drop_nulls; -mod dtypes; -mod dummies; -mod filter_with; -mod first; -mod get; -mod last; -mod list; -mod melt; -mod open; -mod query_df; -mod rename; -mod sample; -mod schema; -mod shape; -mod slice; -mod sql_context; -mod sql_expr; -mod summary; -mod take; -mod to_arrow; -mod to_avro; -mod to_csv; -mod to_df; -mod to_json_lines; -mod to_nu; -mod to_parquet; -mod with_column; - -use nu_protocol::engine::StateWorkingSet; - -pub use self::open::OpenDataFrame; -pub use append::AppendDF; -pub use cast::CastDF; -pub use columns::ColumnsDF; -pub use drop::DropDF; -pub use drop_duplicates::DropDuplicates; -pub use drop_nulls::DropNulls; -pub use dtypes::DataTypes; -pub use dummies::Dummies; -pub use filter_with::FilterWith; -pub use first::FirstDF; -pub use get::GetDF; -pub use last::LastDF; -pub use list::ListDF; -pub use melt::MeltDF; -pub use query_df::QueryDf; -pub use rename::RenameDF; -pub use sample::SampleDF; -pub use schema::SchemaDF; -pub use shape::ShapeDF; -pub use slice::SliceDF; -pub use sql_context::SQLContext; -pub use summary::Summary; -pub use take::TakeDF; -pub use to_arrow::ToArrow; -pub use to_avro::ToAvro; -pub use to_csv::ToCSV; -pub use to_df::ToDataFrame; -pub use to_json_lines::ToJsonLines; -pub use to_nu::ToNu; -pub use to_parquet::ToParquet; -pub use with_column::WithColumn; - -pub fn add_eager_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)); )* - }; - } - - // Dataframe commands - bind_command!( - AppendDF, - CastDF, - ColumnsDF, - DataTypes, - Summary, - DropDF, - DropDuplicates, - DropNulls, - Dummies, - FilterWith, - FirstDF, - GetDF, - LastDF, - ListDF, - MeltDF, - OpenDataFrame, - QueryDf, - RenameDF, - SampleDF, - SchemaDF, - ShapeDF, - SliceDF, - TakeDF, - ToArrow, - ToAvro, - ToCSV, - ToDataFrame, - ToNu, - ToParquet, - ToJsonLines, - WithColumn - ); -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/open.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/open.rs deleted file mode 100644 index 38d0d0c49f..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/open.rs +++ /dev/null @@ -1,518 +0,0 @@ -use crate::dataframe::values::{NuDataFrame, NuLazyFrame, NuSchema}; -use nu_engine::command_prelude::*; - -use polars::prelude::{ - CsvEncoding, CsvReader, IpcReader, JsonFormat, JsonReader, LazyCsvReader, LazyFileListReader, - LazyFrame, ParallelStrategy, ParquetReader, ScanArgsIpc, ScanArgsParquet, SerReader, -}; -use polars_io::{avro::AvroReader, HiveOptions}; -use std::{fs::File, io::BufReader, path::PathBuf}; - -#[derive(Clone)] -pub struct OpenDataFrame; - -impl Command for OpenDataFrame { - fn name(&self) -> &str { - "dfr open" - } - - fn usage(&self) -> &str { - "Opens CSV, JSON, JSON lines, arrow, avro, or parquet file to create dataframe." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "file", - SyntaxShape::Filepath, - "file path to load values from", - ) - .switch("lazy", "creates a lazy dataframe", Some('l')) - .named( - "type", - SyntaxShape::String, - "File type: csv, tsv, json, parquet, arrow, avro. If omitted, derive from file extension", - Some('t'), - ) - .named( - "delimiter", - SyntaxShape::String, - "file delimiter character. CSV file", - Some('d'), - ) - .switch( - "no-header", - "Indicates if file doesn't have header. CSV file", - None, - ) - .named( - "infer-schema", - SyntaxShape::Number, - "Number of rows to infer the schema of the file. CSV file", - None, - ) - .named( - "skip-rows", - SyntaxShape::Number, - "Number of rows to skip from file. CSV file", - None, - ) - .named( - "columns", - SyntaxShape::List(Box::new(SyntaxShape::String)), - "Columns to be selected from csv file. CSV and Parquet file", - None, - ) - .named( - "schema", - SyntaxShape::Record(vec![]), - r#"Polars Schema in format [{name: str}]. CSV, JSON, and JSONL files"#, - Some('s') - ) - .input_output_type(Type::Any, Type::Custom("dataframe".into())) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Takes a file name and creates a dataframe", - example: "dfr open test.csv", - result: None, - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - _input: PipelineData, - ) -> Result { - command(engine_state, stack, call) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, -) -> Result { - let file: Spanned = call.req(engine_state, stack, 0)?; - - let type_option: Option> = call.get_flag(engine_state, stack, "type")?; - - let type_id = match &type_option { - Some(ref t) => Some((t.item.to_owned(), "Invalid type", t.span)), - None => file.item.extension().map(|e| { - ( - e.to_string_lossy().into_owned(), - "Invalid extension", - file.span, - ) - }), - }; - - match type_id { - Some((e, msg, blamed)) => match e.as_str() { - "csv" | "tsv" => from_csv(engine_state, stack, call), - "parquet" | "parq" => from_parquet(engine_state, stack, call), - "ipc" | "arrow" => from_ipc(engine_state, stack, call), - "json" => from_json(engine_state, stack, call), - "jsonl" => from_jsonl(engine_state, stack, call), - "avro" => from_avro(engine_state, stack, call), - _ => Err(ShellError::FileNotFoundCustom { - msg: format!( - "{msg}. Supported values: csv, tsv, parquet, ipc, arrow, json, jsonl, avro" - ), - span: blamed, - }), - }, - None => Err(ShellError::FileNotFoundCustom { - msg: "File without extension".into(), - span: file.span, - }), - } - .map(|value| PipelineData::Value(value, None)) -} - -fn from_parquet( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, -) -> Result { - if call.has_flag(engine_state, stack, "lazy")? { - let file: String = call.req(engine_state, stack, 0)?; - let args = ScanArgsParquet { - n_rows: None, - cache: true, - parallel: ParallelStrategy::Auto, - rechunk: false, - row_index: None, - low_memory: false, - cloud_options: None, - use_statistics: false, - hive_options: HiveOptions::default(), - }; - - let df: NuLazyFrame = LazyFrame::scan_parquet(file, args) - .map_err(|e| ShellError::GenericError { - error: "Parquet reader error".into(), - msg: format!("{e:?}"), - span: Some(call.head), - help: None, - inner: vec![], - })? - .into(); - - df.into_value(call.head) - } else { - let file: Spanned = call.req(engine_state, stack, 0)?; - let columns: Option> = call.get_flag(engine_state, stack, "columns")?; - - let r = File::open(&file.item).map_err(|e| ShellError::GenericError { - error: "Error opening file".into(), - msg: e.to_string(), - span: Some(file.span), - help: None, - inner: vec![], - })?; - let reader = ParquetReader::new(r); - - let reader = match columns { - None => reader, - Some(columns) => reader.with_columns(Some(columns)), - }; - - let df: NuDataFrame = reader - .finish() - .map_err(|e| ShellError::GenericError { - error: "Parquet reader error".into(), - msg: format!("{e:?}"), - span: Some(call.head), - help: None, - inner: vec![], - })? - .into(); - - Ok(df.into_value(call.head)) - } -} - -fn from_avro( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, -) -> Result { - let file: Spanned = call.req(engine_state, stack, 0)?; - let columns: Option> = call.get_flag(engine_state, stack, "columns")?; - - let r = File::open(&file.item).map_err(|e| ShellError::GenericError { - error: "Error opening file".into(), - msg: e.to_string(), - span: Some(file.span), - help: None, - inner: vec![], - })?; - let reader = AvroReader::new(r); - - let reader = match columns { - None => reader, - Some(columns) => reader.with_columns(Some(columns)), - }; - - let df: NuDataFrame = reader - .finish() - .map_err(|e| ShellError::GenericError { - error: "Avro reader error".into(), - msg: format!("{e:?}"), - span: Some(call.head), - help: None, - inner: vec![], - })? - .into(); - - Ok(df.into_value(call.head)) -} - -fn from_ipc( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, -) -> Result { - if call.has_flag(engine_state, stack, "lazy")? { - let file: String = call.req(engine_state, stack, 0)?; - let args = ScanArgsIpc { - n_rows: None, - cache: true, - rechunk: false, - row_index: None, - memory_map: true, - cloud_options: None, - }; - - let df: NuLazyFrame = LazyFrame::scan_ipc(file, args) - .map_err(|e| ShellError::GenericError { - error: "IPC reader error".into(), - msg: format!("{e:?}"), - span: Some(call.head), - help: None, - inner: vec![], - })? - .into(); - - df.into_value(call.head) - } else { - let file: Spanned = call.req(engine_state, stack, 0)?; - let columns: Option> = call.get_flag(engine_state, stack, "columns")?; - - let r = File::open(&file.item).map_err(|e| ShellError::GenericError { - error: "Error opening file".into(), - msg: e.to_string(), - span: Some(file.span), - help: None, - inner: vec![], - })?; - let reader = IpcReader::new(r); - - let reader = match columns { - None => reader, - Some(columns) => reader.with_columns(Some(columns)), - }; - - let df: NuDataFrame = reader - .finish() - .map_err(|e| ShellError::GenericError { - error: "IPC reader error".into(), - msg: format!("{e:?}"), - span: Some(call.head), - help: None, - inner: vec![], - })? - .into(); - - Ok(df.into_value(call.head)) - } -} - -fn from_json( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, -) -> Result { - let file: Spanned = call.req(engine_state, stack, 0)?; - let file = File::open(&file.item).map_err(|e| ShellError::GenericError { - error: "Error opening file".into(), - msg: e.to_string(), - span: Some(file.span), - help: None, - inner: vec![], - })?; - let maybe_schema = call - .get_flag(engine_state, stack, "schema")? - .map(|schema| NuSchema::try_from(&schema)) - .transpose()?; - - let buf_reader = BufReader::new(file); - let reader = JsonReader::new(buf_reader); - - let reader = match maybe_schema { - Some(schema) => reader.with_schema(schema.into()), - None => reader, - }; - - let df: NuDataFrame = reader - .finish() - .map_err(|e| ShellError::GenericError { - error: "Json reader error".into(), - msg: format!("{e:?}"), - span: Some(call.head), - help: None, - inner: vec![], - })? - .into(); - - Ok(df.into_value(call.head)) -} - -fn from_jsonl( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, -) -> Result { - let infer_schema: Option = call.get_flag(engine_state, stack, "infer-schema")?; - let maybe_schema = call - .get_flag(engine_state, stack, "schema")? - .map(|schema| NuSchema::try_from(&schema)) - .transpose()?; - let file: Spanned = call.req(engine_state, stack, 0)?; - let file = File::open(&file.item).map_err(|e| ShellError::GenericError { - error: "Error opening file".into(), - msg: e.to_string(), - span: Some(file.span), - help: None, - inner: vec![], - })?; - - let buf_reader = BufReader::new(file); - let reader = JsonReader::new(buf_reader) - .with_json_format(JsonFormat::JsonLines) - .infer_schema_len(infer_schema); - - let reader = match maybe_schema { - Some(schema) => reader.with_schema(schema.into()), - None => reader, - }; - - let df: NuDataFrame = reader - .finish() - .map_err(|e| ShellError::GenericError { - error: "Json lines reader error".into(), - msg: format!("{e:?}"), - span: Some(call.head), - help: None, - inner: vec![], - })? - .into(); - - Ok(df.into_value(call.head)) -} - -fn from_csv( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, -) -> Result { - let delimiter: Option> = call.get_flag(engine_state, stack, "delimiter")?; - let no_header: bool = call.has_flag(engine_state, stack, "no-header")?; - let infer_schema: Option = call.get_flag(engine_state, stack, "infer-schema")?; - let skip_rows: Option = call.get_flag(engine_state, stack, "skip-rows")?; - let columns: Option> = call.get_flag(engine_state, stack, "columns")?; - - let maybe_schema = call - .get_flag(engine_state, stack, "schema")? - .map(|schema| NuSchema::try_from(&schema)) - .transpose()?; - - if call.has_flag(engine_state, stack, "lazy")? { - let file: String = call.req(engine_state, stack, 0)?; - let csv_reader = LazyCsvReader::new(file); - - let csv_reader = match delimiter { - None => csv_reader, - Some(d) => { - if d.item.len() != 1 { - return Err(ShellError::GenericError { - error: "Incorrect delimiter".into(), - msg: "Delimiter has to be one character".into(), - span: Some(d.span), - help: None, - inner: vec![], - }); - } else { - let delimiter = match d.item.chars().next() { - Some(d) => d as u8, - None => unreachable!(), - }; - csv_reader.with_separator(delimiter) - } - } - }; - - let csv_reader = csv_reader.has_header(!no_header); - - let csv_reader = match maybe_schema { - Some(schema) => csv_reader.with_schema(Some(schema.into())), - None => csv_reader, - }; - - let csv_reader = match infer_schema { - None => csv_reader, - Some(r) => csv_reader.with_infer_schema_length(Some(r)), - }; - - let csv_reader = match skip_rows { - None => csv_reader, - Some(r) => csv_reader.with_skip_rows(r), - }; - - let df: NuLazyFrame = csv_reader - .finish() - .map_err(|e| ShellError::GenericError { - error: "Parquet reader error".into(), - msg: format!("{e:?}"), - span: Some(call.head), - help: None, - inner: vec![], - })? - .into(); - - df.into_value(call.head) - } else { - let file: Spanned = call.req(engine_state, stack, 0)?; - let csv_reader = CsvReader::from_path(&file.item) - .map_err(|e| ShellError::GenericError { - error: "Error creating CSV reader".into(), - msg: e.to_string(), - span: Some(file.span), - help: None, - inner: vec![], - })? - .with_encoding(CsvEncoding::LossyUtf8); - - let csv_reader = match delimiter { - None => csv_reader, - Some(d) => { - if d.item.len() != 1 { - return Err(ShellError::GenericError { - error: "Incorrect delimiter".into(), - msg: "Delimiter has to be one character".into(), - span: Some(d.span), - help: None, - inner: vec![], - }); - } else { - let delimiter = match d.item.chars().next() { - Some(d) => d as u8, - None => unreachable!(), - }; - csv_reader.with_separator(delimiter) - } - } - }; - - let csv_reader = csv_reader.has_header(!no_header); - - let csv_reader = match maybe_schema { - Some(schema) => csv_reader.with_schema(Some(schema.into())), - None => csv_reader, - }; - - let csv_reader = match infer_schema { - None => csv_reader, - Some(r) => csv_reader.infer_schema(Some(r)), - }; - - let csv_reader = match skip_rows { - None => csv_reader, - Some(r) => csv_reader.with_skip_rows(r), - }; - - let csv_reader = match columns { - None => csv_reader, - Some(columns) => csv_reader.with_columns(Some(columns)), - }; - - let df: NuDataFrame = csv_reader - .finish() - .map_err(|e| ShellError::GenericError { - error: "Parquet reader error".into(), - msg: format!("{e:?}"), - span: Some(call.head), - help: None, - inner: vec![], - })? - .into(); - - Ok(df.into_value(call.head)) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/query_df.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/query_df.rs deleted file mode 100644 index 4088e00afa..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/query_df.rs +++ /dev/null @@ -1,104 +0,0 @@ -use crate::dataframe::{ - eager::SQLContext, - values::{Column, NuDataFrame, NuLazyFrame}, -}; -use nu_engine::command_prelude::*; - -// attribution: -// sql_context.rs, and sql_expr.rs were copied from polars-sql. thank you. -// maybe we should just use the crate at some point but it's not published yet. -// https://github.com/pola-rs/polars/tree/master/polars-sql - -#[derive(Clone)] -pub struct QueryDf; - -impl Command for QueryDf { - fn name(&self) -> &str { - "dfr query" - } - - fn usage(&self) -> &str { - "Query dataframe using SQL. Note: The dataframe is always named 'df' in your query's from clause." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("sql", SyntaxShape::String, "sql query") - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn search_terms(&self) -> Vec<&str> { - vec!["dataframe", "sql", "search"] - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Query dataframe using SQL", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr query 'select a from df'", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "a".to_string(), - vec![Value::test_int(1), Value::test_int(3)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let sql_query: String = call.req(engine_state, stack, 0)?; - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let mut ctx = SQLContext::new(); - ctx.register("df", &df.df); - let df_sql = ctx - .execute(&sql_query) - .map_err(|e| ShellError::GenericError { - error: "Dataframe Error".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - let lazy = NuLazyFrame::new(false, df_sql); - - let eager = lazy.collect(call.head)?; - let value = Value::custom(Box::new(eager), call.head); - - 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(QueryDf {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/rename.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/rename.rs deleted file mode 100644 index 0cb75f34f2..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/rename.rs +++ /dev/null @@ -1,185 +0,0 @@ -use crate::dataframe::{ - utils::extract_strings, - values::{Column, NuDataFrame, NuLazyFrame}, -}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct RenameDF; - -impl Command for RenameDF { - fn name(&self) -> &str { - "dfr rename" - } - - fn usage(&self) -> &str { - "Rename a dataframe column." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "columns", - SyntaxShape::Any, - "Column(s) to be renamed. A string or list of strings", - ) - .required( - "new names", - SyntaxShape::Any, - "New names for the selected column(s). A string or list of strings", - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe or lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Renames a series", - example: "[5 6 7 8] | dfr into-df | dfr rename '0' new_name", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "new_name".to_string(), - vec![ - Value::test_int(5), - Value::test_int(6), - Value::test_int(7), - Value::test_int(8), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Renames a dataframe column", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr rename a a_new", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a_new".to_string(), - vec![Value::test_int(1), Value::test_int(3)], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(2), Value::test_int(4)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Renames two dataframe columns", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr rename [a b] [a_new b_new]", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a_new".to_string(), - vec![Value::test_int(1), Value::test_int(3)], - ), - Column::new( - "b_new".to_string(), - vec![Value::test_int(2), Value::test_int(4)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let value = input.into_value(call.head)?; - if NuLazyFrame::can_downcast(&value) { - let df = NuLazyFrame::try_from_value(value)?; - command_lazy(engine_state, stack, call, df) - } else { - let df = NuDataFrame::try_from_value(value)?; - command_eager(engine_state, stack, call, df) - } - } -} - -fn command_eager( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - mut df: NuDataFrame, -) -> Result { - let columns: Value = call.req(engine_state, stack, 0)?; - let columns = extract_strings(columns)?; - - let new_names: Value = call.req(engine_state, stack, 1)?; - let new_names = extract_strings(new_names)?; - - for (from, to) in columns.iter().zip(new_names.iter()) { - df.as_mut() - .rename(from, to) - .map_err(|e| ShellError::GenericError { - error: "Error renaming".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - } - - Ok(PipelineData::Value(df.into_value(call.head), None)) -} - -fn command_lazy( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - lazy: NuLazyFrame, -) -> Result { - let columns: Value = call.req(engine_state, stack, 0)?; - let columns = extract_strings(columns)?; - - let new_names: Value = call.req(engine_state, stack, 1)?; - let new_names = extract_strings(new_names)?; - - if columns.len() != new_names.len() { - let value: Value = call.req(engine_state, stack, 1)?; - return Err(ShellError::IncompatibleParametersSingle { - msg: "New name list has different size to column list".into(), - span: value.span(), - }); - } - - let lazy = lazy.into_polars(); - let lazy: NuLazyFrame = lazy.rename(&columns, &new_names).into(); - - Ok(PipelineData::Value(lazy.into_value(call.head)?, None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(RenameDF {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/sample.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/sample.rs deleted file mode 100644 index 2387cca489..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/sample.rs +++ /dev/null @@ -1,127 +0,0 @@ -use crate::dataframe::values::NuDataFrame; -use nu_engine::command_prelude::*; - -use polars::{prelude::NamedFrom, series::Series}; - -#[derive(Clone)] -pub struct SampleDF; - -impl Command for SampleDF { - fn name(&self) -> &str { - "dfr sample" - } - - fn usage(&self) -> &str { - "Create sample dataframe." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .named( - "n-rows", - SyntaxShape::Int, - "number of rows to be taken from dataframe", - Some('n'), - ) - .named( - "fraction", - SyntaxShape::Number, - "fraction of dataframe to be taken", - Some('f'), - ) - .named( - "seed", - SyntaxShape::Number, - "seed for the selection", - Some('s'), - ) - .switch("replace", "sample with replace", Some('e')) - .switch("shuffle", "shuffle sample", Some('u')) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Sample rows from dataframe", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr sample --n-rows 1", - result: None, // No expected value because sampling is random - }, - Example { - description: "Shows sample row using fraction and replace", - example: - "[[a b]; [1 2] [3 4] [5 6]] | dfr into-df | dfr sample --fraction 0.5 --replace", - result: None, // No expected value because sampling is random - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let rows: Option> = call.get_flag(engine_state, stack, "n-rows")?; - let fraction: Option> = call.get_flag(engine_state, stack, "fraction")?; - let seed: Option = call - .get_flag::(engine_state, stack, "seed")? - .map(|val| val as u64); - let replace: bool = call.has_flag(engine_state, stack, "replace")?; - let shuffle: bool = call.has_flag(engine_state, stack, "shuffle")?; - - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - match (rows, fraction) { - (Some(rows), None) => df - .as_ref() - .sample_n(&Series::new("s", &[rows.item]), replace, shuffle, seed) - .map_err(|e| ShellError::GenericError { - error: "Error creating sample".into(), - msg: e.to_string(), - span: Some(rows.span), - help: None, - inner: vec![], - }), - (None, Some(frac)) => df - .as_ref() - .sample_frac(&Series::new("frac", &[frac.item]), replace, shuffle, seed) - .map_err(|e| ShellError::GenericError { - error: "Error creating sample".into(), - msg: e.to_string(), - span: Some(frac.span), - help: None, - inner: vec![], - }), - (Some(_), Some(_)) => Err(ShellError::GenericError { - error: "Incompatible flags".into(), - msg: "Only one selection criterion allowed".into(), - span: Some(call.head), - help: None, - inner: vec![], - }), - (None, None) => Err(ShellError::GenericError { - error: "No selection".into(), - msg: "No selection criterion was found".into(), - span: Some(call.head), - help: Some("Perhaps you want to use the flag -n or -f".into()), - inner: vec![], - }), - } - .map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None)) -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/schema.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/schema.rs deleted file mode 100644 index cf887482bd..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/schema.rs +++ /dev/null @@ -1,112 +0,0 @@ -use crate::dataframe::values::NuDataFrame; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct SchemaDF; - -impl Command for SchemaDF { - fn name(&self) -> &str { - "dfr schema" - } - - fn usage(&self) -> &str { - "Show schema for a dataframe." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .switch("datatype-list", "creates a lazy dataframe", Some('l')) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Dataframe schema", - example: r#"[[a b]; [1 "foo"] [3 "bar"]] | dfr into-df | dfr schema"#, - result: Some(Value::record( - record! { - "a" => Value::string("i64", Span::test_data()), - "b" => Value::string("str", Span::test_data()), - }, - Span::test_data(), - )), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - if call.has_flag(engine_state, stack, "datatype-list")? { - Ok(PipelineData::Value(datatype_list(Span::unknown()), None)) - } else { - command(engine_state, stack, call, input) - } - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let schema = df.schema(); - let value: Value = schema.into(); - Ok(PipelineData::Value(value, None)) -} - -fn datatype_list(span: Span) -> Value { - let types: Vec = [ - ("null", ""), - ("bool", ""), - ("u8", ""), - ("u16", ""), - ("u32", ""), - ("u64", ""), - ("i8", ""), - ("i16", ""), - ("i32", ""), - ("i64", ""), - ("f32", ""), - ("f64", ""), - ("str", ""), - ("binary", ""), - ("date", ""), - ("datetime", "Time Unit can be: milliseconds: ms, microseconds: us, nanoseconds: ns. Timezone wildcard is *. Other Timezone examples: UTC, America/Los_Angeles."), - ("duration", "Time Unit can be: milliseconds: ms, microseconds: us, nanoseconds: ns."), - ("time", ""), - ("object", ""), - ("unknown", ""), - ("list", ""), - ] - .iter() - .map(|(dtype, note)| { - Value::record(record! { - "dtype" => Value::string(*dtype, span), - "note" => Value::string(*note, span), - }, - span) - }) - .collect(); - Value::list(types, span) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(SchemaDF {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/shape.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/shape.rs deleted file mode 100644 index 6e5e7fa9d3..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/shape.rs +++ /dev/null @@ -1,82 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct ShapeDF; - -impl Command for ShapeDF { - fn name(&self) -> &str { - "dfr shape" - } - - fn usage(&self) -> &str { - "Shows column and row size for a dataframe." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Shows row and column shape", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr shape", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new("rows".to_string(), vec![Value::test_int(2)]), - Column::new("columns".to_string(), vec![Value::test_int(2)]), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let rows = Value::int(df.as_ref().height() as i64, call.head); - - let cols = Value::int(df.as_ref().width() as i64, call.head); - - let rows_col = Column::new("rows".to_string(), vec![rows]); - let cols_col = Column::new("columns".to_string(), vec![cols]); - - NuDataFrame::try_from_columns(vec![rows_col, cols_col], None) - .map(|df| PipelineData::Value(df.into_value(call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(ShapeDF {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/slice.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/slice.rs deleted file mode 100644 index 48906cba2c..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/slice.rs +++ /dev/null @@ -1,84 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct SliceDF; - -impl Command for SliceDF { - fn name(&self) -> &str { - "dfr slice" - } - - fn usage(&self) -> &str { - "Creates new dataframe from a slice of rows." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("offset", SyntaxShape::Int, "start of slice") - .required("size", SyntaxShape::Int, "size of slice") - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Create new dataframe from a slice of the rows", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr slice 0 1", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new("a".to_string(), vec![Value::test_int(1)]), - Column::new("b".to_string(), vec![Value::test_int(2)]), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let offset: i64 = call.req(engine_state, stack, 0)?; - let size: usize = call.req(engine_state, stack, 1)?; - - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let res = df.as_ref().slice(offset, size); - - Ok(PipelineData::Value( - NuDataFrame::dataframe_into_value(res, call.head), - None, - )) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(SliceDF {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/sql_context.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/sql_context.rs deleted file mode 100644 index f558904344..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/sql_context.rs +++ /dev/null @@ -1,228 +0,0 @@ -use crate::dataframe::eager::sql_expr::parse_sql_expr; -use polars::error::{ErrString, PolarsError}; -use polars::prelude::{col, DataFrame, DataType, IntoLazy, LazyFrame}; -use sqlparser::ast::{ - Expr as SqlExpr, GroupByExpr, Select, SelectItem, SetExpr, Statement, TableFactor, - Value as SQLValue, -}; -use sqlparser::dialect::GenericDialect; -use sqlparser::parser::Parser; -use std::collections::HashMap; - -#[derive(Default)] -pub struct SQLContext { - table_map: HashMap, - dialect: GenericDialect, -} - -impl SQLContext { - pub fn new() -> Self { - Self { - table_map: HashMap::new(), - dialect: GenericDialect, - } - } - - pub fn register(&mut self, name: &str, df: &DataFrame) { - self.table_map.insert(name.to_owned(), df.clone().lazy()); - } - - fn execute_select(&self, select_stmt: &Select) -> Result { - // Determine involved dataframe - // Implicit join require some more work in query parsers, Explicit join are preferred for now. - let tbl = select_stmt.from.first().ok_or_else(|| { - PolarsError::ComputeError(ErrString::from("No table found in select statement")) - })?; - let mut alias_map = HashMap::new(); - let tbl_name = match &tbl.relation { - TableFactor::Table { name, alias, .. } => { - let tbl_name = name - .0 - .first() - .ok_or_else(|| { - PolarsError::ComputeError(ErrString::from( - "No table found in select statement", - )) - })? - .value - .to_string(); - if self.table_map.contains_key(&tbl_name) { - if let Some(alias) = alias { - alias_map.insert(alias.name.value.clone(), tbl_name.to_owned()); - }; - tbl_name - } else { - return Err(PolarsError::ComputeError( - format!("Table name {tbl_name} was not found").into(), - )); - } - } - // Support bare table, optional with alias for now - _ => return Err(PolarsError::ComputeError("Not implemented".into())), - }; - let df = &self.table_map[&tbl_name]; - let mut raw_projection_before_alias: HashMap = HashMap::new(); - let mut contain_wildcard = false; - // Filter Expression - let df = match select_stmt.selection.as_ref() { - Some(expr) => { - let filter_expression = parse_sql_expr(expr)?; - df.clone().filter(filter_expression) - } - None => df.clone(), - }; - // Column Projections - let projection = select_stmt - .projection - .iter() - .enumerate() - .map(|(i, select_item)| { - Ok(match select_item { - SelectItem::UnnamedExpr(expr) => { - let expr = parse_sql_expr(expr)?; - raw_projection_before_alias.insert(format!("{expr:?}"), i); - expr - } - SelectItem::ExprWithAlias { expr, alias } => { - let expr = parse_sql_expr(expr)?; - raw_projection_before_alias.insert(format!("{expr:?}"), i); - expr.alias(&alias.value) - } - SelectItem::QualifiedWildcard(_, _) | SelectItem::Wildcard(_) => { - contain_wildcard = true; - col("*") - } - }) - }) - .collect::, PolarsError>>()?; - // Check for group by - // After projection since there might be number. - let group_by = match &select_stmt.group_by { - GroupByExpr::All => - Err( - PolarsError::ComputeError("Group-By Error: Only positive number or expression are supported, not all".into()) - )?, - GroupByExpr::Expressions(expressions) => expressions - } - .iter() - .map( - |e|match e { - SqlExpr::Value(SQLValue::Number(idx, _)) => { - let idx = match idx.parse::() { - Ok(0)| Err(_) => Err( - PolarsError::ComputeError( - format!("Group-By Error: Only positive number or expression are supported, got {idx}").into() - )), - Ok(idx) => Ok(idx) - }?; - Ok(projection[idx].clone()) - } - SqlExpr::Value(_) => Err( - PolarsError::ComputeError("Group-By Error: Only positive number or expression are supported".into()) - ), - _ => parse_sql_expr(e) - } - ) - .collect::, PolarsError>>()?; - - let df = if group_by.is_empty() { - df.select(projection) - } else { - // check groupby and projection due to difference between SQL and polars - // Return error on wild card, shouldn't process this - if contain_wildcard { - return Err(PolarsError::ComputeError( - "Group-By Error: Can't process wildcard in group-by".into(), - )); - } - // Default polars group by will have group by columns at the front - // need some container to contain position of group by columns and its position - // at the final agg projection, check the schema for the existence of group by column - // and its projections columns, keeping the original index - let (exclude_expr, groupby_pos): (Vec<_>, Vec<_>) = group_by - .iter() - .map(|expr| raw_projection_before_alias.get(&format!("{expr:?}"))) - .enumerate() - .filter(|(_, proj_p)| proj_p.is_some()) - .map(|(gb_p, proj_p)| (*proj_p.unwrap_or(&0), (*proj_p.unwrap_or(&0), gb_p))) - .unzip(); - let (agg_projection, agg_proj_pos): (Vec<_>, Vec<_>) = projection - .iter() - .enumerate() - .filter(|(i, _)| !exclude_expr.contains(i)) - .enumerate() - .map(|(agg_pj, (proj_p, expr))| (expr.clone(), (proj_p, agg_pj + group_by.len()))) - .unzip(); - let agg_df = df.group_by(group_by).agg(agg_projection); - let mut final_proj_pos = groupby_pos - .into_iter() - .chain(agg_proj_pos) - .collect::>(); - - final_proj_pos.sort_by(|(proj_pa, _), (proj_pb, _)| proj_pa.cmp(proj_pb)); - let final_proj = final_proj_pos - .into_iter() - .map(|(_, shm_p)| { - col(agg_df - .clone() - // FIXME: had to do this mess to get get_index to work, not sure why. need help - .collect() - .unwrap_or_default() - .schema() - .get_at_index(shm_p) - .unwrap_or((&"".into(), &DataType::Null)) - .0) - }) - .collect::>(); - agg_df.select(final_proj) - }; - Ok(df) - } - - pub fn execute(&self, query: &str) -> Result { - let ast = Parser::parse_sql(&self.dialect, query) - .map_err(|e| PolarsError::ComputeError(format!("{e:?}").into()))?; - if ast.len() != 1 { - Err(PolarsError::ComputeError( - "One and only one statement at a time please".into(), - )) - } else { - let ast = ast - .first() - .ok_or_else(|| PolarsError::ComputeError(ErrString::from("No statement found")))?; - Ok(match ast { - Statement::Query(query) => { - let rs = match &*query.body { - SetExpr::Select(select_stmt) => self.execute_select(select_stmt)?, - _ => { - return Err(PolarsError::ComputeError( - "INSERT, UPDATE is not supported for polars".into(), - )) - } - }; - match &query.limit { - Some(SqlExpr::Value(SQLValue::Number(nrow, _))) => { - let nrow = nrow.parse().map_err(|err| { - PolarsError::ComputeError( - format!("Conversion Error: {err:?}").into(), - ) - })?; - rs.limit(nrow) - } - None => rs, - _ => { - return Err(PolarsError::ComputeError( - "Only support number argument to LIMIT clause".into(), - )) - } - } - } - _ => { - return Err(PolarsError::ComputeError( - format!("Statement type {ast:?} is not supported").into(), - )) - } - }) - } - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/sql_expr.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/sql_expr.rs deleted file mode 100644 index 9c0728ea5f..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/sql_expr.rs +++ /dev/null @@ -1,200 +0,0 @@ -use polars::error::PolarsError; -use polars::prelude::{col, lit, DataType, Expr, LiteralValue, PolarsResult as Result, TimeUnit}; - -use sqlparser::ast::{ - ArrayElemTypeDef, BinaryOperator as SQLBinaryOperator, DataType as SQLDataType, - Expr as SqlExpr, Function as SQLFunction, Value as SqlValue, WindowType, -}; - -fn map_sql_polars_datatype(data_type: &SQLDataType) -> Result { - Ok(match data_type { - SQLDataType::Char(_) - | SQLDataType::Varchar(_) - | SQLDataType::Uuid - | SQLDataType::Clob(_) - | SQLDataType::Text - | SQLDataType::String(_) => DataType::String, - SQLDataType::Float(_) => DataType::Float32, - SQLDataType::Real => DataType::Float32, - SQLDataType::Double => DataType::Float64, - SQLDataType::TinyInt(_) => DataType::Int8, - SQLDataType::UnsignedTinyInt(_) => DataType::UInt8, - SQLDataType::SmallInt(_) => DataType::Int16, - SQLDataType::UnsignedSmallInt(_) => DataType::UInt16, - SQLDataType::Int(_) => DataType::Int32, - SQLDataType::UnsignedInt(_) => DataType::UInt32, - SQLDataType::BigInt(_) => DataType::Int64, - SQLDataType::UnsignedBigInt(_) => DataType::UInt64, - - SQLDataType::Boolean => DataType::Boolean, - SQLDataType::Date => DataType::Date, - SQLDataType::Time(_, _) => DataType::Time, - SQLDataType::Timestamp(_, _) => DataType::Datetime(TimeUnit::Microseconds, None), - SQLDataType::Interval => DataType::Duration(TimeUnit::Microseconds), - SQLDataType::Array(array_type_def) => match array_type_def { - ArrayElemTypeDef::AngleBracket(inner_type) - | ArrayElemTypeDef::SquareBracket(inner_type) => { - DataType::List(Box::new(map_sql_polars_datatype(inner_type)?)) - } - _ => { - return Err(PolarsError::ComputeError( - "SQL Datatype Array(None) was not supported in polars-sql yet!".into(), - )) - } - }, - _ => { - return Err(PolarsError::ComputeError( - format!("SQL Datatype {data_type:?} was not supported in polars-sql yet!").into(), - )) - } - }) -} - -fn cast_(expr: Expr, data_type: &SQLDataType) -> Result { - let polars_type = map_sql_polars_datatype(data_type)?; - Ok(expr.cast(polars_type)) -} - -fn binary_op_(left: Expr, right: Expr, op: &SQLBinaryOperator) -> Result { - Ok(match op { - SQLBinaryOperator::Plus => left + right, - SQLBinaryOperator::Minus => left - right, - SQLBinaryOperator::Multiply => left * right, - SQLBinaryOperator::Divide => left / right, - SQLBinaryOperator::Modulo => left % right, - SQLBinaryOperator::StringConcat => { - left.cast(DataType::String) + right.cast(DataType::String) - } - SQLBinaryOperator::Gt => left.gt(right), - SQLBinaryOperator::Lt => left.lt(right), - SQLBinaryOperator::GtEq => left.gt_eq(right), - SQLBinaryOperator::LtEq => left.lt_eq(right), - SQLBinaryOperator::Eq => left.eq(right), - SQLBinaryOperator::NotEq => left.eq(right).not(), - SQLBinaryOperator::And => left.and(right), - SQLBinaryOperator::Or => left.or(right), - SQLBinaryOperator::Xor => left.xor(right), - _ => { - return Err(PolarsError::ComputeError( - format!("SQL Operator {op:?} was not supported in polars-sql yet!").into(), - )) - } - }) -} - -fn literal_expr(value: &SqlValue) -> Result { - Ok(match value { - SqlValue::Number(s, _) => { - // Check for existence of decimal separator dot - if s.contains('.') { - s.parse::().map(lit).map_err(|_| { - PolarsError::ComputeError(format!("Can't parse literal {s:?}").into()) - }) - } else { - s.parse::().map(lit).map_err(|_| { - PolarsError::ComputeError(format!("Can't parse literal {s:?}").into()) - }) - }? - } - SqlValue::SingleQuotedString(s) => lit(s.clone()), - SqlValue::NationalStringLiteral(s) => lit(s.clone()), - SqlValue::HexStringLiteral(s) => lit(s.clone()), - SqlValue::DoubleQuotedString(s) => lit(s.clone()), - SqlValue::Boolean(b) => lit(*b), - SqlValue::Null => Expr::Literal(LiteralValue::Null), - _ => { - return Err(PolarsError::ComputeError( - format!("Parsing SQL Value {value:?} was not supported in polars-sql yet!").into(), - )) - } - }) -} - -pub fn parse_sql_expr(expr: &SqlExpr) -> Result { - Ok(match expr { - SqlExpr::Identifier(e) => col(&e.value), - SqlExpr::BinaryOp { left, op, right } => { - let left = parse_sql_expr(left)?; - let right = parse_sql_expr(right)?; - binary_op_(left, right, op)? - } - SqlExpr::Function(sql_function) => parse_sql_function(sql_function)?, - SqlExpr::Cast { - expr, - data_type, - format: _, - } => cast_(parse_sql_expr(expr)?, data_type)?, - SqlExpr::Nested(expr) => parse_sql_expr(expr)?, - SqlExpr::Value(value) => literal_expr(value)?, - _ => { - return Err(PolarsError::ComputeError( - format!("Expression: {expr:?} was not supported in polars-sql yet!").into(), - )) - } - }) -} - -fn apply_window_spec(expr: Expr, window_type: Option<&WindowType>) -> Result { - Ok(match &window_type { - Some(wtype) => match wtype { - WindowType::WindowSpec(window_spec) => { - // Process for simple window specification, partition by first - let partition_by = window_spec - .partition_by - .iter() - .map(parse_sql_expr) - .collect::>>()?; - expr.over(partition_by) - // Order by and Row range may not be supported at the moment - } - // TODO: make NamedWindow work - WindowType::NamedWindow(_named) => { - return Err(PolarsError::ComputeError( - format!("Expression: {expr:?} was not supported in polars-sql yet!").into(), - )) - } - }, - None => expr, - }) -} - -fn parse_sql_function(sql_function: &SQLFunction) -> Result { - use sqlparser::ast::{FunctionArg, FunctionArgExpr}; - // Function name mostly do not have name space, so it mostly take the first args - let function_name = sql_function.name.0[0].value.to_ascii_lowercase(); - let args = sql_function - .args - .iter() - .map(|arg| match arg { - FunctionArg::Named { arg, .. } => arg, - FunctionArg::Unnamed(arg) => arg, - }) - .collect::>(); - Ok( - match ( - function_name.as_str(), - args.as_slice(), - sql_function.distinct, - ) { - ("sum", [FunctionArgExpr::Expr(expr)], false) => { - apply_window_spec(parse_sql_expr(expr)?, sql_function.over.as_ref())?.sum() - } - ("count", [FunctionArgExpr::Expr(expr)], false) => { - apply_window_spec(parse_sql_expr(expr)?, sql_function.over.as_ref())?.count() - } - ("count", [FunctionArgExpr::Expr(expr)], true) => { - apply_window_spec(parse_sql_expr(expr)?, sql_function.over.as_ref())?.n_unique() - } - // Special case for wildcard args to count function. - ("count", [FunctionArgExpr::Wildcard], false) => lit(1i32).count(), - _ => { - return Err(PolarsError::ComputeError( - format!( - "Function {function_name:?} with args {args:?} was not supported in polars-sql yet!" - ) - .into(), - )) - } - }, - ) -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/summary.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/summary.rs deleted file mode 100644 index 845929a52d..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/summary.rs +++ /dev/null @@ -1,279 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -use polars::{ - chunked_array::ChunkedArray, - prelude::{ - AnyValue, DataFrame, DataType, Float64Type, IntoSeries, NewChunkedArray, - QuantileInterpolOptions, Series, StringType, - }, -}; - -#[derive(Clone)] -pub struct Summary; - -impl Command for Summary { - fn name(&self) -> &str { - "dfr summary" - } - - fn usage(&self) -> &str { - "For a dataframe, produces descriptive statistics (summary statistics) for its numeric columns." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .category(Category::Custom("dataframe".into())) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .named( - "quantiles", - SyntaxShape::Table(vec![]), - "provide optional quantiles", - Some('q'), - ) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "list dataframe descriptives", - example: "[[a b]; [1 1] [1 1]] | dfr into-df | dfr summary", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "descriptor".to_string(), - vec![ - Value::test_string("count"), - Value::test_string("sum"), - Value::test_string("mean"), - Value::test_string("median"), - Value::test_string("std"), - Value::test_string("min"), - Value::test_string("25%"), - Value::test_string("50%"), - Value::test_string("75%"), - Value::test_string("max"), - ], - ), - Column::new( - "a (i64)".to_string(), - vec![ - Value::test_float(2.0), - Value::test_float(2.0), - Value::test_float(1.0), - Value::test_float(1.0), - Value::test_float(0.0), - Value::test_float(1.0), - Value::test_float(1.0), - Value::test_float(1.0), - Value::test_float(1.0), - Value::test_float(1.0), - ], - ), - Column::new( - "b (i64)".to_string(), - vec![ - Value::test_float(2.0), - Value::test_float(2.0), - Value::test_float(1.0), - Value::test_float(1.0), - Value::test_float(0.0), - Value::test_float(1.0), - Value::test_float(1.0), - Value::test_float(1.0), - Value::test_float(1.0), - Value::test_float(1.0), - ], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let quantiles: Option> = call.get_flag(engine_state, stack, "quantiles")?; - let quantiles = quantiles.map(|values| { - values - .iter() - .map(|value| { - let span = value.span(); - match value { - Value::Float { val, .. } => { - if (&0.0..=&1.0).contains(&val) { - Ok(*val) - } else { - Err(ShellError::GenericError { - error: "Incorrect value for quantile".into(), - msg: "value should be between 0 and 1".into(), - span: Some(span), - help: None, - inner: vec![], - }) - } - } - Value::Error { error, .. } => Err(*error.clone()), - _ => Err(ShellError::GenericError { - error: "Incorrect value for quantile".into(), - msg: "value should be a float".into(), - span: Some(span), - help: None, - inner: vec![], - }), - } - }) - .collect::, ShellError>>() - }); - - let quantiles = match quantiles { - Some(quantiles) => quantiles?, - None => vec![0.25, 0.50, 0.75], - }; - - let mut quantiles_labels = quantiles - .iter() - .map(|q| Some(format!("{}%", q * 100.0))) - .collect::>>(); - let mut labels = vec![ - Some("count".to_string()), - Some("sum".to_string()), - Some("mean".to_string()), - Some("median".to_string()), - Some("std".to_string()), - Some("min".to_string()), - ]; - labels.append(&mut quantiles_labels); - labels.push(Some("max".to_string())); - - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let names = ChunkedArray::::from_slice_options("descriptor", &labels).into_series(); - - let head = std::iter::once(names); - - let tail = df - .as_ref() - .get_columns() - .iter() - .filter(|col| !matches!(col.dtype(), &DataType::Object("object", _))) - .map(|col| { - let count = col.len() as f64; - - let sum = col.sum_as_series().ok().and_then(|series| { - series - .cast(&DataType::Float64) - .ok() - .and_then(|ca| match ca.get(0) { - Ok(AnyValue::Float64(v)) => Some(v), - _ => None, - }) - }); - - let mean = match col.mean_as_series().get(0) { - Ok(AnyValue::Float64(v)) => Some(v), - _ => None, - }; - - let median = match col.median_as_series() { - Ok(v) => match v.get(0) { - Ok(AnyValue::Float64(v)) => Some(v), - _ => None, - }, - _ => None, - }; - - let std = match col.std_as_series(0) { - Ok(v) => match v.get(0) { - Ok(AnyValue::Float64(v)) => Some(v), - _ => None, - }, - _ => None, - }; - - let min = col.min_as_series().ok().and_then(|series| { - series - .cast(&DataType::Float64) - .ok() - .and_then(|ca| match ca.get(0) { - Ok(AnyValue::Float64(v)) => Some(v), - _ => None, - }) - }); - - let mut quantiles = quantiles - .clone() - .into_iter() - .map(|q| { - col.quantile_as_series(q, QuantileInterpolOptions::default()) - .ok() - .and_then(|ca| ca.cast(&DataType::Float64).ok()) - .and_then(|ca| match ca.get(0) { - Ok(AnyValue::Float64(v)) => Some(v), - _ => None, - }) - }) - .collect::>>(); - - let max = col.max_as_series().ok().and_then(|series| { - series - .cast(&DataType::Float64) - .ok() - .and_then(|ca| match ca.get(0) { - Ok(AnyValue::Float64(v)) => Some(v), - _ => None, - }) - }); - - let mut descriptors = vec![Some(count), sum, mean, median, std, min]; - descriptors.append(&mut quantiles); - descriptors.push(max); - - let name = format!("{} ({})", col.name(), col.dtype()); - ChunkedArray::::from_slice_options(&name, &descriptors).into_series() - }); - - let res = head.chain(tail).collect::>(); - - DataFrame::new(res) - .map_err(|e| ShellError::GenericError { - error: "Dataframe Error".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - }) - .map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(Summary {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/take.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/take.rs deleted file mode 100644 index 406dd1d624..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/take.rs +++ /dev/null @@ -1,148 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -use polars::prelude::DataType; - -#[derive(Clone)] -pub struct TakeDF; - -impl Command for TakeDF { - fn name(&self) -> &str { - "dfr take" - } - - fn usage(&self) -> &str { - "Creates new dataframe using the given indices." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "indices", - SyntaxShape::Any, - "list of indices used to take data", - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Takes selected rows from dataframe", - example: r#"let df = ([[a b]; [4 1] [5 2] [4 3]] | dfr into-df); - let indices = ([0 2] | dfr into-df); - $df | dfr take $indices"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(4), Value::test_int(4)], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(1), Value::test_int(3)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Takes selected rows from series", - example: r#"let series = ([4 1 5 2 4 3] | dfr into-df); - let indices = ([0 2] | dfr into-df); - $series | dfr take $indices"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![Value::test_int(4), Value::test_int(5)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let index_value: Value = call.req(engine_state, stack, 0)?; - let index_span = index_value.span(); - let index = NuDataFrame::try_from_value(index_value)?.as_series(index_span)?; - - let casted = match index.dtype() { - DataType::UInt32 | DataType::UInt64 | DataType::Int32 | DataType::Int64 => index - .cast(&DataType::UInt32) - .map_err(|e| ShellError::GenericError { - error: "Error casting index list".into(), - msg: e.to_string(), - span: Some(index_span), - help: None, - inner: vec![], - }), - _ => Err(ShellError::GenericError { - error: "Incorrect type".into(), - msg: "Series with incorrect type".into(), - span: Some(call.head), - help: Some("Consider using a Series with type int type".into()), - inner: vec![], - }), - }?; - - let indices = casted.u32().map_err(|e| ShellError::GenericError { - error: "Error casting index list".into(), - msg: e.to_string(), - span: Some(index_span), - help: None, - inner: vec![], - })?; - - NuDataFrame::try_from_pipeline(input, call.head).and_then(|df| { - df.as_ref() - .take(indices) - .map_err(|e| ShellError::GenericError { - error: "Error taking values".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - }) - .map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None)) - }) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(TakeDF {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/to_arrow.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/to_arrow.rs deleted file mode 100644 index 66f13121bf..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/to_arrow.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::dataframe::values::NuDataFrame; -use nu_engine::command_prelude::*; - -use polars::prelude::{IpcWriter, SerWriter}; -use std::{fs::File, path::PathBuf}; - -#[derive(Clone)] -pub struct ToArrow; - -impl Command for ToArrow { - fn name(&self) -> &str { - "dfr to-arrow" - } - - fn usage(&self) -> &str { - "Saves dataframe to arrow file." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("file", SyntaxShape::Filepath, "file path to save dataframe") - .input_output_type(Type::Custom("dataframe".into()), Type::Any) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Saves dataframe to arrow file", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr to-arrow test.arrow", - result: None, - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let file_name: Spanned = call.req(engine_state, stack, 0)?; - - let mut df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let mut file = File::create(&file_name.item).map_err(|e| ShellError::GenericError { - error: "Error with file name".into(), - msg: e.to_string(), - span: Some(file_name.span), - help: None, - inner: vec![], - })?; - - IpcWriter::new(&mut file) - .finish(df.as_mut()) - .map_err(|e| ShellError::GenericError { - error: "Error saving file".into(), - msg: e.to_string(), - span: Some(file_name.span), - help: None, - inner: vec![], - })?; - - let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span); - - Ok(PipelineData::Value( - Value::list(vec![file_value], call.head), - None, - )) -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/to_avro.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/to_avro.rs deleted file mode 100644 index e5e5c6fae1..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/to_avro.rs +++ /dev/null @@ -1,109 +0,0 @@ -use crate::dataframe::values::NuDataFrame; -use nu_engine::command_prelude::*; - -use polars_io::{ - avro::{AvroCompression, AvroWriter}, - SerWriter, -}; -use std::{fs::File, path::PathBuf}; - -#[derive(Clone)] -pub struct ToAvro; - -impl Command for ToAvro { - fn name(&self) -> &str { - "dfr to-avro" - } - - fn usage(&self) -> &str { - "Saves dataframe to avro file." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .named( - "compression", - SyntaxShape::String, - "use compression, supports deflate or snappy", - Some('c'), - ) - .required("file", SyntaxShape::Filepath, "file path to save dataframe") - .input_output_type(Type::Custom("dataframe".into()), Type::Any) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Saves dataframe to avro file", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr to-avro test.avro", - result: None, - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn get_compression(call: &Call) -> Result, ShellError> { - if let Some((compression, span)) = call - .get_flag_expr("compression") - .and_then(|e| e.as_string().map(|s| (s, e.span))) - { - match compression.as_ref() { - "snappy" => Ok(Some(AvroCompression::Snappy)), - "deflate" => Ok(Some(AvroCompression::Deflate)), - _ => Err(ShellError::IncorrectValue { - msg: "compression must be one of deflate or snappy".to_string(), - val_span: span, - call_span: span, - }), - } - } else { - Ok(None) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let file_name: Spanned = call.req(engine_state, stack, 0)?; - let compression = get_compression(call)?; - - let mut df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let file = File::create(&file_name.item).map_err(|e| ShellError::GenericError { - error: "Error with file name".into(), - msg: e.to_string(), - span: Some(file_name.span), - help: None, - inner: vec![], - })?; - - AvroWriter::new(file) - .with_compression(compression) - .finish(df.as_mut()) - .map_err(|e| ShellError::GenericError { - error: "Error saving file".into(), - msg: e.to_string(), - span: Some(file_name.span), - help: None, - inner: vec![], - })?; - - let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span); - - Ok(PipelineData::Value( - Value::list(vec![file_value], call.head), - None, - )) -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/to_csv.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/to_csv.rs deleted file mode 100644 index d85bed5150..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/to_csv.rs +++ /dev/null @@ -1,125 +0,0 @@ -use crate::dataframe::values::NuDataFrame; -use nu_engine::command_prelude::*; - -use polars::prelude::{CsvWriter, SerWriter}; -use std::{fs::File, path::PathBuf}; - -#[derive(Clone)] -pub struct ToCSV; - -impl Command for ToCSV { - fn name(&self) -> &str { - "dfr to-csv" - } - - fn usage(&self) -> &str { - "Saves dataframe to CSV file." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("file", SyntaxShape::Filepath, "file path to save dataframe") - .named( - "delimiter", - SyntaxShape::String, - "file delimiter character", - Some('d'), - ) - .switch("no-header", "Indicates if file doesn't have header", None) - .input_output_type(Type::Custom("dataframe".into()), Type::Any) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Saves dataframe to CSV file", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr to-csv test.csv", - result: None, - }, - Example { - description: "Saves dataframe to CSV file using other delimiter", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr to-csv test.csv --delimiter '|'", - result: None, - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let file_name: Spanned = call.req(engine_state, stack, 0)?; - let delimiter: Option> = call.get_flag(engine_state, stack, "delimiter")?; - let no_header: bool = call.has_flag(engine_state, stack, "no-header")?; - - let mut df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let mut file = File::create(&file_name.item).map_err(|e| ShellError::GenericError { - error: "Error with file name".into(), - msg: e.to_string(), - span: Some(file_name.span), - help: None, - inner: vec![], - })?; - - let writer = CsvWriter::new(&mut file); - - let writer = if no_header { - writer.include_header(false) - } else { - writer.include_header(true) - }; - - let mut writer = match delimiter { - None => writer, - Some(d) => { - if d.item.len() != 1 { - return Err(ShellError::GenericError { - error: "Incorrect delimiter".into(), - msg: "Delimiter has to be one char".into(), - span: Some(d.span), - help: None, - inner: vec![], - }); - } else { - let delimiter = match d.item.chars().next() { - Some(d) => d as u8, - None => unreachable!(), - }; - - writer.with_separator(delimiter) - } - } - }; - - writer - .finish(df.as_mut()) - .map_err(|e| ShellError::GenericError { - error: "Error writing to file".into(), - msg: e.to_string(), - span: Some(file_name.span), - help: None, - inner: vec![], - })?; - - let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span); - - Ok(PipelineData::Value( - Value::list(vec![file_value], call.head), - None, - )) -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/to_df.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/to_df.rs deleted file mode 100644 index d768c7a742..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/to_df.rs +++ /dev/null @@ -1,189 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuSchema}; -use nu_engine::command_prelude::*; - -use polars::prelude::*; - -#[derive(Clone)] -pub struct ToDataFrame; - -impl Command for ToDataFrame { - fn name(&self) -> &str { - "dfr into-df" - } - - fn usage(&self) -> &str { - "Converts a list, table or record into a dataframe." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .named( - "schema", - SyntaxShape::Record(vec![]), - r#"Polars Schema in format [{name: str}]. CSV, JSON, and JSONL files"#, - Some('s'), - ) - .input_output_type(Type::Any, Type::Custom("dataframe".into())) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Takes a dictionary and creates a dataframe", - example: "[[a b];[1 2] [3 4]] | dfr into-df", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(1), Value::test_int(3)], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(2), Value::test_int(4)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Takes a list of tables and creates a dataframe", - example: "[[1 2 a] [3 4 b] [5 6 c]] | dfr into-df", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "0".to_string(), - vec![Value::test_int(1), Value::test_int(3), Value::test_int(5)], - ), - Column::new( - "1".to_string(), - vec![Value::test_int(2), Value::test_int(4), Value::test_int(6)], - ), - Column::new( - "2".to_string(), - vec![ - Value::test_string("a"), - Value::test_string("b"), - Value::test_string("c"), - ], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Takes a list and creates a dataframe", - example: "[a b c] | dfr into-df", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![ - Value::test_string("a"), - Value::test_string("b"), - Value::test_string("c"), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Takes a list of booleans and creates a dataframe", - example: "[true true false] | dfr into-df", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![ - Value::test_bool(true), - Value::test_bool(true), - Value::test_bool(false), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Convert to a dataframe and provide a schema", - example: "{a: 1, b: {a: [1 2 3]}, c: [a b c]}| dfr into-df -s {a: u8, b: {a: list}, c: list}", - result: Some( - NuDataFrame::try_from_series(vec![ - Series::new("a", &[1u8]), - { - let dtype = DataType::Struct(vec![Field::new("a", DataType::List(Box::new(DataType::UInt64)))]); - let vals = vec![AnyValue::StructOwned( - Box::new((vec![AnyValue::List(Series::new("a", &[1u64, 2, 3]))], vec![Field::new("a", DataType::String)]))); 1]; - Series::from_any_values_and_dtype("b", &vals, &dtype, false) - .expect("Struct series should not fail") - }, - { - let dtype = DataType::List(Box::new(DataType::String)); - let vals = vec![AnyValue::List(Series::new("c", &["a", "b", "c"]))]; - Series::from_any_values_and_dtype("c", &vals, &dtype, false) - .expect("List series should not fail") - } - ], Span::test_data()) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Convert to a dataframe and provide a schema that adds a new column", - example: r#"[[a b]; [1 "foo"] [2 "bar"]] | dfr into-df -s {a: u8, b:str, c:i64} | dfr fill-null 3"#, - result: Some(NuDataFrame::try_from_series(vec![ - Series::new("a", [1u8, 2]), - Series::new("b", ["foo", "bar"]), - Series::new("c", [3i64, 3]), - ], Span::test_data()) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - } - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let maybe_schema = call - .get_flag(engine_state, stack, "schema")? - .map(|schema| NuSchema::try_from(&schema)) - .transpose()?; - - let df = NuDataFrame::try_from_iter(input.into_iter(), maybe_schema.clone())?; - - Ok(PipelineData::Value( - NuDataFrame::into_value(df, call.head), - None, - )) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(ToDataFrame {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/to_json_lines.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/to_json_lines.rs deleted file mode 100644 index 5875f17107..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/to_json_lines.rs +++ /dev/null @@ -1,80 +0,0 @@ -use crate::dataframe::values::NuDataFrame; -use nu_engine::command_prelude::*; - -use polars::prelude::{JsonWriter, SerWriter}; -use std::{fs::File, io::BufWriter, path::PathBuf}; - -#[derive(Clone)] -pub struct ToJsonLines; - -impl Command for ToJsonLines { - fn name(&self) -> &str { - "dfr to-jsonl" - } - - fn usage(&self) -> &str { - "Saves dataframe to a JSON lines file." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("file", SyntaxShape::Filepath, "file path to save dataframe") - .input_output_type(Type::Custom("dataframe".into()), Type::Any) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Saves dataframe to JSON lines file", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr to-jsonl test.jsonl", - result: None, - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let file_name: Spanned = call.req(engine_state, stack, 0)?; - - let mut df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let file = File::create(&file_name.item).map_err(|e| ShellError::GenericError { - error: "Error with file name".into(), - msg: e.to_string(), - span: Some(file_name.span), - help: None, - inner: vec![], - })?; - let buf_writer = BufWriter::new(file); - - JsonWriter::new(buf_writer) - .finish(df.as_mut()) - .map_err(|e| ShellError::GenericError { - error: "Error saving file".into(), - msg: e.to_string(), - span: Some(file_name.span), - help: None, - inner: vec![], - })?; - - let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span); - - Ok(PipelineData::Value( - Value::list(vec![file_value], call.head), - None, - )) -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/to_nu.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/to_nu.rs deleted file mode 100644 index a6ab42052c..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/to_nu.rs +++ /dev/null @@ -1,136 +0,0 @@ -use crate::dataframe::values::{NuDataFrame, NuExpression}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct ToNu; - -impl Command for ToNu { - fn name(&self) -> &str { - "dfr into-nu" - } - - fn usage(&self) -> &str { - "Converts a dataframe or an expression into into nushell value for access and exploration." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .named( - "rows", - SyntaxShape::Number, - "number of rows to be shown", - Some('n'), - ) - .switch("tail", "shows tail rows", Some('t')) - .input_output_types(vec![ - (Type::Custom("expression".into()), Type::Any), - (Type::Custom("dataframe".into()), Type::table()), - ]) - //.input_output_type(Type::Any, Type::Any) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - let rec_1 = Value::test_record(record! { - "index" => Value::test_int(0), - "a" => Value::test_int(1), - "b" => Value::test_int(2), - }); - let rec_2 = Value::test_record(record! { - "index" => Value::test_int(1), - "a" => Value::test_int(3), - "b" => Value::test_int(4), - }); - let rec_3 = Value::test_record(record! { - "index" => Value::test_int(2), - "a" => Value::test_int(3), - "b" => Value::test_int(4), - }); - - vec![ - Example { - description: "Shows head rows from dataframe", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr into-nu", - result: Some(Value::list(vec![rec_1, rec_2], Span::test_data())), - }, - Example { - description: "Shows tail rows from dataframe", - example: "[[a b]; [1 2] [5 6] [3 4]] | dfr into-df | dfr into-nu --tail --rows 1", - result: Some(Value::list(vec![rec_3], Span::test_data())), - }, - Example { - description: "Convert a col expression into a nushell value", - example: "dfr col a | dfr into-nu", - result: Some(Value::test_record(record! { - "expr" => Value::test_string("column"), - "value" => Value::test_string("a"), - })), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let value = input.into_value(call.head)?; - if NuDataFrame::can_downcast(&value) { - dataframe_command(engine_state, stack, call, value) - } else { - expression_command(call, value) - } - } -} - -fn dataframe_command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: Value, -) -> Result { - let rows: Option = call.get_flag(engine_state, stack, "rows")?; - let tail: bool = call.has_flag(engine_state, stack, "tail")?; - - let df = NuDataFrame::try_from_value(input)?; - - let values = if tail { - df.tail(rows, call.head)? - } else { - // if rows is specified, return those rows, otherwise return everything - if rows.is_some() { - df.head(rows, call.head)? - } else { - df.head(Some(df.height()), call.head)? - } - }; - - let value = Value::list(values, call.head); - - Ok(PipelineData::Value(value, None)) -} -fn expression_command(call: &Call, input: Value) -> Result { - let expr = NuExpression::try_from_value(input)?; - let value = expr.to_value(call.head)?; - - Ok(PipelineData::Value(value, None)) -} - -#[cfg(test)] -mod test { - use super::super::super::expressions::ExprCol; - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples_dataframe_input() { - test_dataframe(vec![Box::new(ToNu {})]) - } - - #[test] - fn test_examples_expression_input() { - test_dataframe(vec![Box::new(ToNu {}), Box::new(ExprCol {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/to_parquet.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/to_parquet.rs deleted file mode 100644 index ce6419a9ac..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/to_parquet.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::dataframe::values::NuDataFrame; -use nu_engine::command_prelude::*; - -use polars::prelude::ParquetWriter; -use std::{fs::File, path::PathBuf}; - -#[derive(Clone)] -pub struct ToParquet; - -impl Command for ToParquet { - fn name(&self) -> &str { - "dfr to-parquet" - } - - fn usage(&self) -> &str { - "Saves dataframe to parquet file." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("file", SyntaxShape::Filepath, "file path to save dataframe") - .input_output_type(Type::Custom("dataframe".into()), Type::Any) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Saves dataframe to parquet file", - example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr to-parquet test.parquet", - result: None, - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let file_name: Spanned = call.req(engine_state, stack, 0)?; - - let mut df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let file = File::create(&file_name.item).map_err(|e| ShellError::GenericError { - error: "Error with file name".into(), - msg: e.to_string(), - span: Some(file_name.span), - help: None, - inner: vec![], - })?; - - ParquetWriter::new(file) - .finish(df.as_mut()) - .map_err(|e| ShellError::GenericError { - error: "Error saving file".into(), - msg: e.to_string(), - span: Some(file_name.span), - help: None, - inner: vec![], - })?; - - let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span); - - Ok(PipelineData::Value( - Value::list(vec![file_value], call.head), - None, - )) -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/eager/with_column.rs b/crates/nu-cmd-dataframe/src/dataframe/eager/with_column.rs deleted file mode 100644 index 79d3427e8a..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/eager/with_column.rs +++ /dev/null @@ -1,202 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression, NuLazyFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct WithColumn; - -impl Command for WithColumn { - fn name(&self) -> &str { - "dfr with-column" - } - - fn usage(&self) -> &str { - "Adds a series to the dataframe." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .named("name", SyntaxShape::String, "new column name", Some('n')) - .rest( - "series or expressions", - SyntaxShape::Any, - "series to be added or expressions used to define the new columns", - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe or lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Adds a series to the dataframe", - example: r#"[[a b]; [1 2] [3 4]] - | dfr into-df - | dfr with-column ([5 6] | dfr into-df) --name c"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(1), Value::test_int(3)], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(2), Value::test_int(4)], - ), - Column::new( - "c".to_string(), - vec![Value::test_int(5), Value::test_int(6)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Adds a series to the dataframe", - example: r#"[[a b]; [1 2] [3 4]] - | dfr into-lazy - | dfr with-column [ - ((dfr col a) * 2 | dfr as "c") - ((dfr col a) * 3 | dfr as "d") - ] - | dfr collect"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(1), Value::test_int(3)], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(2), Value::test_int(4)], - ), - Column::new( - "c".to_string(), - vec![Value::test_int(2), Value::test_int(6)], - ), - Column::new( - "d".to_string(), - vec![Value::test_int(3), Value::test_int(9)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let value = input.into_value(call.head)?; - if NuLazyFrame::can_downcast(&value) { - let df = NuLazyFrame::try_from_value(value)?; - command_lazy(engine_state, stack, call, df) - } else if NuDataFrame::can_downcast(&value) { - let df = NuDataFrame::try_from_value(value)?; - command_eager(engine_state, stack, call, df) - } else { - Err(ShellError::CantConvert { - to_type: "lazy or eager dataframe".into(), - from_type: value.get_type().to_string(), - span: value.span(), - help: None, - }) - } - } -} - -fn command_eager( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - mut df: NuDataFrame, -) -> Result { - let new_column: Value = call.req(engine_state, stack, 0)?; - let column_span = new_column.span(); - - if NuExpression::can_downcast(&new_column) { - let vals: Vec = call.rest(engine_state, stack, 0)?; - let value = Value::list(vals, call.head); - let expressions = NuExpression::extract_exprs(value)?; - let lazy = NuLazyFrame::new(true, df.lazy().with_columns(&expressions)); - - let df = lazy.collect(call.head)?; - - Ok(PipelineData::Value(df.into_value(call.head), None)) - } else { - let mut other = NuDataFrame::try_from_value(new_column)?.as_series(column_span)?; - - let name = match call.get_flag::(engine_state, stack, "name")? { - Some(name) => name, - None => other.name().to_string(), - }; - - let series = other.rename(&name).clone(); - - df.as_mut() - .with_column(series) - .map_err(|e| ShellError::GenericError { - error: "Error adding column to dataframe".into(), - msg: e.to_string(), - span: Some(column_span), - help: None, - inner: vec![], - }) - .map(|df| { - PipelineData::Value( - NuDataFrame::dataframe_into_value(df.clone(), call.head), - None, - ) - }) - } -} - -fn command_lazy( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - lazy: NuLazyFrame, -) -> Result { - let vals: Vec = call.rest(engine_state, stack, 0)?; - let value = Value::list(vals, call.head); - let expressions = NuExpression::extract_exprs(value)?; - - let lazy: NuLazyFrame = lazy.into_polars().with_columns(&expressions).into(); - - Ok(PipelineData::Value( - NuLazyFrame::into_value(lazy, call.head)?, - None, - )) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - use crate::dataframe::expressions::ExprAlias; - use crate::dataframe::expressions::ExprCol; - - #[test] - fn test_examples() { - test_dataframe(vec![ - Box::new(WithColumn {}), - Box::new(ExprAlias {}), - Box::new(ExprCol {}), - ]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/expressions/alias.rs b/crates/nu-cmd-dataframe/src/dataframe/expressions/alias.rs deleted file mode 100644 index 9d36100276..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/expressions/alias.rs +++ /dev/null @@ -1,86 +0,0 @@ -use crate::dataframe::values::NuExpression; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct ExprAlias; - -impl Command for ExprAlias { - fn name(&self) -> &str { - "dfr as" - } - - fn usage(&self) -> &str { - "Creates an alias expression." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "Alias name", - SyntaxShape::String, - "Alias name for the expression", - ) - .input_output_type( - Type::Custom("expression".into()), - Type::Custom("expression".into()), - ) - .category(Category::Custom("expression".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Creates and alias expression", - example: "dfr col a | dfr as new_a | dfr into-nu", - result: { - let record = Value::test_record(record! { - "expr" => Value::test_record(record! { - "expr" => Value::test_string("column"), - "value" => Value::test_string("a"), - }), - "alias" => Value::test_string("new_a"), - }); - - Some(record) - }, - }] - } - - fn search_terms(&self) -> Vec<&str> { - vec!["aka", "abbr", "otherwise"] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let alias: String = call.req(engine_state, stack, 0)?; - - let expr = NuExpression::try_from_pipeline(input, call.head)?; - let expr: NuExpression = expr.into_polars().alias(alias.as_str()).into(); - - Ok(PipelineData::Value( - NuExpression::into_value(expr, call.head), - None, - )) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - use crate::dataframe::eager::ToNu; - use crate::dataframe::expressions::ExprCol; - - #[test] - fn test_examples() { - test_dataframe(vec![ - Box::new(ExprAlias {}), - Box::new(ExprCol {}), - Box::new(ToNu {}), - ]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/expressions/arg_where.rs b/crates/nu-cmd-dataframe/src/dataframe/expressions/arg_where.rs deleted file mode 100644 index 49c13c3f44..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/expressions/arg_where.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression}; -use nu_engine::command_prelude::*; - -use polars::prelude::arg_where; - -#[derive(Clone)] -pub struct ExprArgWhere; - -impl Command for ExprArgWhere { - fn name(&self) -> &str { - "dfr arg-where" - } - - fn usage(&self) -> &str { - "Creates an expression that returns the arguments where expression is true." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("column name", SyntaxShape::Any, "Expression to evaluate") - .input_output_type(Type::Any, Type::Custom("expression".into())) - .category(Category::Custom("expression".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Return a dataframe where the value match the expression", - example: "let df = ([[a b]; [one 1] [two 2] [three 3]] | dfr into-df); - $df | dfr select (dfr arg-where ((dfr col b) >= 2) | dfr as b_arg)", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "b_arg".to_string(), - vec![Value::test_int(1), Value::test_int(2)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn search_terms(&self) -> Vec<&str> { - vec!["condition", "match", "if"] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - _input: PipelineData, - ) -> Result { - let value: Value = call.req(engine_state, stack, 0)?; - let expr = NuExpression::try_from_value(value)?; - let expr: NuExpression = arg_where(expr.into_polars()).into(); - - Ok(PipelineData::Value(expr.into_value(call.head), None)) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - use crate::dataframe::expressions::ExprAlias; - use crate::dataframe::lazy::LazySelect; - - #[test] - fn test_examples() { - test_dataframe(vec![ - Box::new(ExprArgWhere {}), - Box::new(ExprAlias {}), - Box::new(LazySelect {}), - ]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/expressions/col.rs b/crates/nu-cmd-dataframe/src/dataframe/expressions/col.rs deleted file mode 100644 index 1520ef995d..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/expressions/col.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::dataframe::values::NuExpression; -use nu_engine::command_prelude::*; - -use polars::prelude::col; - -#[derive(Clone)] -pub struct ExprCol; - -impl Command for ExprCol { - fn name(&self) -> &str { - "dfr col" - } - - fn usage(&self) -> &str { - "Creates a named column expression." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "column name", - SyntaxShape::String, - "Name of column to be used", - ) - .input_output_type(Type::Any, Type::Custom("expression".into())) - .category(Category::Custom("expression".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Creates a named column expression and converts it to a nu object", - example: "dfr col a | dfr into-nu", - result: Some(Value::test_record(record! { - "expr" => Value::test_string("column"), - "value" => Value::test_string("a"), - })), - }] - } - - fn search_terms(&self) -> Vec<&str> { - vec!["create"] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - _input: PipelineData, - ) -> Result { - let name: String = call.req(engine_state, stack, 0)?; - let expr: NuExpression = col(name.as_str()).into(); - - Ok(PipelineData::Value(expr.into_value(call.head), None)) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - use crate::dataframe::eager::ToNu; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(ExprCol {}), Box::new(ToNu {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/expressions/concat_str.rs b/crates/nu-cmd-dataframe/src/dataframe/expressions/concat_str.rs deleted file mode 100644 index 28f9bbda71..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/expressions/concat_str.rs +++ /dev/null @@ -1,108 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression}; -use nu_engine::command_prelude::*; - -use polars::prelude::concat_str; - -#[derive(Clone)] -pub struct ExprConcatStr; - -impl Command for ExprConcatStr { - fn name(&self) -> &str { - "dfr concat-str" - } - - fn usage(&self) -> &str { - "Creates a concat string expression." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "separator", - SyntaxShape::String, - "Separator used during the concatenation", - ) - .required( - "concat expressions", - SyntaxShape::List(Box::new(SyntaxShape::Any)), - "Expression(s) that define the string concatenation", - ) - .input_output_type(Type::Any, Type::Custom("expression".into())) - .category(Category::Custom("expression".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Creates a concat string expression", - example: r#"let df = ([[a b c]; [one two 1] [three four 2]] | dfr into-df); - $df | dfr with-column ((dfr concat-str "-" [(dfr col a) (dfr col b) ((dfr col c) * 2)]) | dfr as concat)"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_string("one"), Value::test_string("three")], - ), - Column::new( - "b".to_string(), - vec![Value::test_string("two"), Value::test_string("four")], - ), - Column::new( - "c".to_string(), - vec![Value::test_int(1), Value::test_int(2)], - ), - Column::new( - "concat".to_string(), - vec![ - Value::test_string("one-two-2"), - Value::test_string("three-four-4"), - ], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn search_terms(&self) -> Vec<&str> { - vec!["join", "connect", "update"] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - _input: PipelineData, - ) -> Result { - let separator: String = call.req(engine_state, stack, 0)?; - let value: Value = call.req(engine_state, stack, 1)?; - - let expressions = NuExpression::extract_exprs(value)?; - let expr: NuExpression = concat_str(expressions, &separator, false).into(); - - Ok(PipelineData::Value(expr.into_value(call.head), None)) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - use crate::dataframe::eager::WithColumn; - use crate::dataframe::expressions::alias::ExprAlias; - use crate::dataframe::expressions::col::ExprCol; - - #[test] - fn test_examples() { - test_dataframe(vec![ - Box::new(ExprConcatStr {}), - Box::new(ExprAlias {}), - Box::new(ExprCol {}), - Box::new(WithColumn {}), - ]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/expressions/datepart.rs b/crates/nu-cmd-dataframe/src/dataframe/expressions/datepart.rs deleted file mode 100644 index 60913c0dc6..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/expressions/datepart.rs +++ /dev/null @@ -1,170 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression}; -use chrono::{DateTime, FixedOffset}; -use nu_engine::command_prelude::*; - -use polars::{ - datatypes::{DataType, TimeUnit}, - prelude::NamedFrom, - series::Series, -}; - -#[derive(Clone)] -pub struct ExprDatePart; - -impl Command for ExprDatePart { - fn name(&self) -> &str { - "dfr datepart" - } - - fn usage(&self) -> &str { - "Creates an expression for capturing the specified datepart in a column." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "Datepart name", - SyntaxShape::String, - "Part of the date to capture. Possible values are year, quarter, month, week, weekday, day, hour, minute, second, millisecond, microsecond, nanosecond", - ) - .input_output_type( - Type::Custom("expression".into()), - Type::Custom("expression".into()), - ) - .category(Category::Custom("expression".into())) - } - - fn examples(&self) -> Vec { - let dt = DateTime::::parse_from_str( - "2021-12-30T01:02:03.123456789 +0000", - "%Y-%m-%dT%H:%M:%S.%9f %z", - ) - .expect("date calculation should not fail in test"); - vec![ - Example { - description: "Creates an expression to capture the year date part", - example: r#"[["2021-12-30T01:02:03.123456789"]] | dfr into-df | dfr as-datetime "%Y-%m-%dT%H:%M:%S.%9f" | dfr with-column [(dfr col datetime | dfr datepart year | dfr as datetime_year )]"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new("datetime".to_string(), vec![Value::test_date(dt)]), - Column::new("datetime_year".to_string(), vec![Value::test_int(2021)]), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Creates an expression to capture multiple date parts", - example: r#"[["2021-12-30T01:02:03.123456789"]] | dfr into-df | dfr as-datetime "%Y-%m-%dT%H:%M:%S.%9f" | - dfr with-column [ (dfr col datetime | dfr datepart year | dfr as datetime_year ), - (dfr col datetime | dfr datepart month | dfr as datetime_month ), - (dfr col datetime | dfr datepart day | dfr as datetime_day ), - (dfr col datetime | dfr datepart hour | dfr as datetime_hour ), - (dfr col datetime | dfr datepart minute | dfr as datetime_minute ), - (dfr col datetime | dfr datepart second | dfr as datetime_second ), - (dfr col datetime | dfr datepart nanosecond | dfr as datetime_ns ) ]"#, - result: Some( - NuDataFrame::try_from_series( - vec![ - Series::new("datetime", &[dt.timestamp_nanos_opt()]) - .cast(&DataType::Datetime(TimeUnit::Nanoseconds, None)) - .expect("Error casting to datetime type"), - Series::new("datetime_year", &[2021_i64]), // i32 was coerced to i64 - Series::new("datetime_month", &[12_i8]), - Series::new("datetime_day", &[30_i8]), - Series::new("datetime_hour", &[1_i8]), - Series::new("datetime_minute", &[2_i8]), - Series::new("datetime_second", &[3_i8]), - Series::new("datetime_ns", &[123456789_i64]), // i32 was coerced to i64 - ], - Span::test_data(), - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn search_terms(&self) -> Vec<&str> { - vec![ - "year", - "month", - "week", - "weekday", - "quarter", - "day", - "hour", - "minute", - "second", - "millisecond", - "microsecond", - "nanosecond", - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let part: Spanned = call.req(engine_state, stack, 0)?; - - let expr = NuExpression::try_from_pipeline(input, call.head)?; - let expr_dt = expr.into_polars().dt(); - let expr = match part.item.as_str() { - "year" => expr_dt.year(), - "quarter" => expr_dt.quarter(), - "month" => expr_dt.month(), - "week" => expr_dt.week(), - "day" => expr_dt.day(), - "hour" => expr_dt.hour(), - "minute" => expr_dt.minute(), - "second" => expr_dt.second(), - "millisecond" => expr_dt.millisecond(), - "microsecond" => expr_dt.microsecond(), - "nanosecond" => expr_dt.nanosecond(), - _ => { - return Err(ShellError::UnsupportedInput { - msg: format!("{} is not a valid datepart, expected one of year, month, day, hour, minute, second, millisecond, microsecond, nanosecond", part.item), - input: "value originates from here".to_string(), - msg_span: call.head, - input_span: part.span, - }); - } - }.into(); - - Ok(PipelineData::Value( - NuExpression::into_value(expr, call.head), - None, - )) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - use crate::dataframe::eager::ToNu; - use crate::dataframe::eager::WithColumn; - use crate::dataframe::expressions::ExprAlias; - use crate::dataframe::expressions::ExprCol; - use crate::dataframe::series::AsDateTime; - - #[test] - fn test_examples() { - test_dataframe(vec![ - Box::new(ExprDatePart {}), - Box::new(ExprCol {}), - Box::new(ToNu {}), - Box::new(AsDateTime {}), - Box::new(WithColumn {}), - Box::new(ExprAlias {}), - ]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/expressions/expressions_macro.rs b/crates/nu-cmd-dataframe/src/dataframe/expressions/expressions_macro.rs deleted file mode 100644 index 4cc56e030b..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/expressions/expressions_macro.rs +++ /dev/null @@ -1,736 +0,0 @@ -/// Definition of multiple Expression commands using a macro rule -/// All of these expressions have an identical body and only require -/// to have a change in the name, description and expression function -use crate::dataframe::values::{Column, NuDataFrame, NuExpression, NuLazyFrame}; -use nu_engine::command_prelude::*; - -// The structs defined in this file are structs that form part of other commands -// since they share a similar name -macro_rules! expr_command { - ($command: ident, $name: expr, $desc: expr, $examples: expr, $func: ident, $test: ident) => { - #[derive(Clone)] - pub struct $command; - - impl Command for $command { - fn name(&self) -> &str { - $name - } - - fn usage(&self) -> &str { - $desc - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("expression".into()), - Type::Custom("expression".into()), - ) - .category(Category::Custom("expression".into())) - } - - fn examples(&self) -> Vec { - $examples - } - - fn run( - &self, - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let expr = NuExpression::try_from_pipeline(input, call.head)?; - let expr: NuExpression = expr.into_polars().$func().into(); - - Ok(PipelineData::Value( - NuExpression::into_value(expr, call.head), - None, - )) - } - } - - #[cfg(test)] - mod $test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - use crate::dataframe::lazy::aggregate::LazyAggregate; - use crate::dataframe::lazy::groupby::ToLazyGroupBy; - - #[test] - fn test_examples() { - test_dataframe(vec![ - Box::new($command {}), - Box::new(LazyAggregate {}), - Box::new(ToLazyGroupBy {}), - ]) - } - } - }; - - ($command: ident, $name: expr, $desc: expr, $examples: expr, $func: ident, $test: ident, $ddof: expr) => { - #[derive(Clone)] - pub struct $command; - - impl Command for $command { - fn name(&self) -> &str { - $name - } - - fn usage(&self) -> &str { - $desc - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("expression".into()), - Type::Custom("expression".into()), - ) - .category(Category::Custom("expression".into())) - } - - fn examples(&self) -> Vec { - $examples - } - - fn run( - &self, - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let expr = NuExpression::try_from_pipeline(input, call.head)?; - let expr: NuExpression = expr.into_polars().$func($ddof).into(); - - Ok(PipelineData::Value( - NuExpression::into_value(expr, call.head), - None, - )) - } - } - - #[cfg(test)] - mod $test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - use crate::dataframe::lazy::aggregate::LazyAggregate; - use crate::dataframe::lazy::groupby::ToLazyGroupBy; - - #[test] - fn test_examples() { - test_dataframe(vec![ - Box::new($command {}), - Box::new(LazyAggregate {}), - Box::new(ToLazyGroupBy {}), - ]) - } - } - }; -} - -// The structs defined in this file are structs that form part of other commands -// since they share a similar name -macro_rules! lazy_expr_command { - ($command: ident, $name: expr, $desc: expr, $examples: expr, $func: ident, $test: ident) => { - #[derive(Clone)] - pub struct $command; - - impl Command for $command { - fn name(&self) -> &str { - $name - } - - fn usage(&self) -> &str { - $desc - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_types(vec![ - ( - Type::Custom("expression".into()), - Type::Custom("expression".into()), - ), - ( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ), - ]) - .category(Category::Custom("expression".into())) - } - - fn examples(&self) -> Vec { - $examples - } - - fn run( - &self, - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let value = input.into_value(call.head)?; - if NuDataFrame::can_downcast(&value) { - let lazy = NuLazyFrame::try_from_value(value)?; - let lazy = NuLazyFrame::new( - lazy.from_eager, - lazy.into_polars() - .$func() - .map_err(|e| ShellError::GenericError { - error: "Dataframe Error".into(), - msg: e.to_string(), - help: None, - span: None, - inner: vec![], - })?, - ); - - Ok(PipelineData::Value(lazy.into_value(call.head)?, None)) - } else { - let expr = NuExpression::try_from_value(value)?; - let expr: NuExpression = expr.into_polars().$func().into(); - - Ok(PipelineData::Value( - NuExpression::into_value(expr, call.head), - None, - )) - } - } - } - - #[cfg(test)] - mod $test { - use super::super::super::test_dataframe::{ - build_test_engine_state, test_dataframe_example, - }; - use super::*; - use crate::dataframe::lazy::aggregate::LazyAggregate; - use crate::dataframe::lazy::groupby::ToLazyGroupBy; - - #[test] - fn test_examples_dataframe() { - // the first example should be a for the dataframe case - let example = &$command.examples()[0]; - let mut engine_state = build_test_engine_state(vec![Box::new($command {})]); - test_dataframe_example(&mut engine_state, &example) - } - - #[test] - fn test_examples_expressions() { - // the second example should be a for the dataframe case - let example = &$command.examples()[1]; - let mut engine_state = build_test_engine_state(vec![ - Box::new($command {}), - Box::new(LazyAggregate {}), - Box::new(ToLazyGroupBy {}), - ]); - test_dataframe_example(&mut engine_state, &example) - } - } - }; - - ($command: ident, $name: expr, $desc: expr, $examples: expr, $func: ident, $test: ident, $ddof: expr) => { - #[derive(Clone)] - pub struct $command; - - impl Command for $command { - fn name(&self) -> &str { - $name - } - - fn usage(&self) -> &str { - $desc - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_types(vec![ - ( - Type::Custom("expression".into()), - Type::Custom("expression".into()), - ), - ( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ), - ]) - .category(Category::Custom("expression".into())) - } - - fn examples(&self) -> Vec { - $examples - } - - fn run( - &self, - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let value = input.into_value(call.head)?; - if NuDataFrame::can_downcast(&value) { - let lazy = NuLazyFrame::try_from_value(value)?; - let lazy = NuLazyFrame::new( - lazy.from_eager, - lazy.into_polars() - .$func($ddof) - .map_err(|e| ShellError::GenericError { - error: "Dataframe Error".into(), - msg: e.to_string(), - help: None, - span: None, - inner: vec![], - })?, - ); - - Ok(PipelineData::Value(lazy.into_value(call.head)?, None)) - } else { - let expr = NuExpression::try_from_value(value)?; - let expr: NuExpression = expr.into_polars().$func($ddof).into(); - - Ok(PipelineData::Value( - NuExpression::into_value(expr, call.head), - None, - )) - } - } - } - - #[cfg(test)] - mod $test { - use super::super::super::test_dataframe::{ - build_test_engine_state, test_dataframe_example, - }; - use super::*; - use crate::dataframe::lazy::aggregate::LazyAggregate; - use crate::dataframe::lazy::groupby::ToLazyGroupBy; - - #[test] - fn test_examples_dataframe() { - // the first example should be a for the dataframe case - let example = &$command.examples()[0]; - let mut engine_state = build_test_engine_state(vec![Box::new($command {})]); - test_dataframe_example(&mut engine_state, &example) - } - - #[test] - fn test_examples_expressions() { - // the second example should be a for the dataframe case - let example = &$command.examples()[1]; - let mut engine_state = build_test_engine_state(vec![ - Box::new($command {}), - Box::new(LazyAggregate {}), - Box::new(ToLazyGroupBy {}), - ]); - test_dataframe_example(&mut engine_state, &example) - } - } - }; -} - -// ExprList command -// Expands to a command definition for a list expression -expr_command!( - ExprList, - "dfr implode", - "Aggregates a group to a Series.", - vec![Example { - description: "", - example: "", - result: None, - }], - implode, - test_implode -); - -// ExprAggGroups command -// Expands to a command definition for a agg groups expression -expr_command!( - ExprAggGroups, - "dfr agg-groups", - "Creates an agg_groups expression.", - vec![Example { - description: "", - example: "", - result: None, - }], - agg_groups, - test_groups -); - -// ExprCount command -// Expands to a command definition for a count expression -expr_command!( - ExprCount, - "dfr count", - "Creates a count expression.", - vec![Example { - description: "", - example: "", - result: None, - }], - count, - test_count -); - -// ExprNot command -// Expands to a command definition for a not expression -expr_command!( - ExprNot, - "dfr expr-not", - "Creates a not expression.", - vec![Example { - description: "Creates a not expression", - example: "(dfr col a) > 2) | dfr expr-not", - result: None, - },], - not, - test_not -); - -// ExprMax command -// Expands to a command definition for max aggregation -lazy_expr_command!( - ExprMax, - "dfr max", - "Creates a max expression or aggregates columns to their max value.", - vec![ - Example { - description: "Max value from columns in a dataframe", - example: "[[a b]; [6 2] [1 4] [4 1]] | dfr into-df | dfr max", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new("a".to_string(), vec![Value::test_int(6)],), - Column::new("b".to_string(), vec![Value::test_int(4)],), - ], - None - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Max aggregation for a group-by", - example: r#"[[a b]; [one 2] [one 4] [two 1]] - | dfr into-df - | dfr group-by a - | dfr agg (dfr col b | dfr max)"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_string("one"), Value::test_string("two")], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(4), Value::test_int(1)], - ), - ], - None - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ], - max, - test_max -); - -// ExprMin command -// Expands to a command definition for min aggregation -lazy_expr_command!( - ExprMin, - "dfr min", - "Creates a min expression or aggregates columns to their min value.", - vec![ - Example { - description: "Min value from columns in a dataframe", - example: "[[a b]; [6 2] [1 4] [4 1]] | dfr into-df | dfr min", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new("a".to_string(), vec![Value::test_int(1)],), - Column::new("b".to_string(), vec![Value::test_int(1)],), - ], - None - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Min aggregation for a group-by", - example: r#"[[a b]; [one 2] [one 4] [two 1]] - | dfr into-df - | dfr group-by a - | dfr agg (dfr col b | dfr min)"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_string("one"), Value::test_string("two")], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(2), Value::test_int(1)], - ), - ], - None - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ], - min, - test_min -); - -// ExprSum command -// Expands to a command definition for sum aggregation -lazy_expr_command!( - ExprSum, - "dfr sum", - "Creates a sum expression for an aggregation or aggregates columns to their sum value.", - vec![ - Example { - description: "Sums all columns in a dataframe", - example: "[[a b]; [6 2] [1 4] [4 1]] | dfr into-df | dfr sum", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new("a".to_string(), vec![Value::test_int(11)],), - Column::new("b".to_string(), vec![Value::test_int(7)],), - ], - None - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Sum aggregation for a group-by", - example: r#"[[a b]; [one 2] [one 4] [two 1]] - | dfr into-df - | dfr group-by a - | dfr agg (dfr col b | dfr sum)"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_string("one"), Value::test_string("two")], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(6), Value::test_int(1)], - ), - ], - None - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ], - sum, - test_sum -); - -// ExprMean command -// Expands to a command definition for mean aggregation -lazy_expr_command!( - ExprMean, - "dfr mean", - "Creates a mean expression for an aggregation or aggregates columns to their mean value.", - vec![ - Example { - description: "Mean value from columns in a dataframe", - example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr mean", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new("a".to_string(), vec![Value::test_float(4.0)],), - Column::new("b".to_string(), vec![Value::test_float(2.0)],), - ], - None - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Mean aggregation for a group-by", - example: r#"[[a b]; [one 2] [one 4] [two 1]] - | dfr into-df - | dfr group-by a - | dfr agg (dfr col b | dfr mean)"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_string("one"), Value::test_string("two")], - ), - Column::new( - "b".to_string(), - vec![Value::test_float(3.0), Value::test_float(1.0)], - ), - ], - None - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ], - mean, - test_mean -); - -// ExprMedian command -// Expands to a command definition for median aggregation -expr_command!( - ExprMedian, - "dfr median", - "Creates a median expression for an aggregation.", - vec![Example { - description: "Median aggregation for a group-by", - example: r#"[[a b]; [one 2] [one 4] [two 1]] - | dfr into-df - | dfr group-by a - | dfr agg (dfr col b | dfr median)"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_string("one"), Value::test_string("two")], - ), - Column::new( - "b".to_string(), - vec![Value::test_float(3.0), Value::test_float(1.0)], - ), - ], - None - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - },], - median, - test_median -); - -// ExprStd command -// Expands to a command definition for std aggregation -lazy_expr_command!( - ExprStd, - "dfr std", - "Creates a std expression for an aggregation of std value from columns in a dataframe.", - vec![ - Example { - description: "Std value from columns in a dataframe", - example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr std", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new("a".to_string(), vec![Value::test_float(2.0)],), - Column::new("b".to_string(), vec![Value::test_float(0.0)],), - ], - None - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Std aggregation for a group-by", - example: r#"[[a b]; [one 2] [one 2] [two 1] [two 1]] - | dfr into-df - | dfr group-by a - | dfr agg (dfr col b | dfr std)"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_string("one"), Value::test_string("two")], - ), - Column::new( - "b".to_string(), - vec![Value::test_float(0.0), Value::test_float(0.0)], - ), - ], - None - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ], - std, - test_std, - 1 -); - -// ExprVar command -// Expands to a command definition for var aggregation -lazy_expr_command!( - ExprVar, - "dfr var", - "Create a var expression for an aggregation.", - vec![ - Example { - description: - "Var value from columns in a dataframe or aggregates columns to their var value", - example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr var", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new("a".to_string(), vec![Value::test_float(4.0)],), - Column::new("b".to_string(), vec![Value::test_float(0.0)],), - ], - None - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Var aggregation for a group-by", - example: r#"[[a b]; [one 2] [one 2] [two 1] [two 1]] - | dfr into-df - | dfr group-by a - | dfr agg (dfr col b | dfr var)"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_string("one"), Value::test_string("two")], - ), - Column::new( - "b".to_string(), - vec![Value::test_float(0.0), Value::test_float(0.0)], - ), - ], - None - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ], - var, - test_var, - 1 -); diff --git a/crates/nu-cmd-dataframe/src/dataframe/expressions/is_in.rs b/crates/nu-cmd-dataframe/src/dataframe/expressions/is_in.rs deleted file mode 100644 index 1579ba0e20..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/expressions/is_in.rs +++ /dev/null @@ -1,116 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression}; -use nu_engine::command_prelude::*; - -use polars::prelude::{lit, DataType}; - -#[derive(Clone)] -pub struct ExprIsIn; - -impl Command for ExprIsIn { - fn name(&self) -> &str { - "dfr is-in" - } - - fn usage(&self) -> &str { - "Creates an is-in expression." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "list", - SyntaxShape::List(Box::new(SyntaxShape::Any)), - "List to check if values are in", - ) - .input_output_type( - Type::Custom("expression".into()), - Type::Custom("expression".into()), - ) - .category(Category::Custom("expression".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Creates a is-in expression", - example: r#"let df = ([[a b]; [one 1] [two 2] [three 3]] | dfr into-df); - $df | dfr with-column (dfr col a | dfr is-in [one two] | dfr as a_in)"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![ - Value::test_string("one"), - Value::test_string("two"), - Value::test_string("three"), - ], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(1), Value::test_int(2), Value::test_int(3)], - ), - Column::new( - "a_in".to_string(), - vec![ - Value::test_bool(true), - Value::test_bool(true), - Value::test_bool(false), - ], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn search_terms(&self) -> Vec<&str> { - vec!["check", "contained", "is-contain", "match"] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let list: Vec = call.req(engine_state, stack, 0)?; - let expr = NuExpression::try_from_pipeline(input, call.head)?; - - let values = - NuDataFrame::try_from_columns(vec![Column::new("list".to_string(), list)], None)?; - let list = values.as_series(call.head)?; - - if matches!(list.dtype(), DataType::Object(..)) { - return Err(ShellError::IncompatibleParametersSingle { - msg: "Cannot use a mixed list as argument".into(), - span: call.head, - }); - } - - let expr: NuExpression = expr.into_polars().is_in(lit(list)).into(); - Ok(PipelineData::Value(expr.into_value(call.head), None)) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - use crate::dataframe::eager::WithColumn; - use crate::dataframe::expressions::alias::ExprAlias; - use crate::dataframe::expressions::col::ExprCol; - - #[test] - fn test_examples() { - test_dataframe(vec![ - Box::new(ExprIsIn {}), - Box::new(ExprAlias {}), - Box::new(ExprCol {}), - Box::new(WithColumn {}), - ]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/expressions/lit.rs b/crates/nu-cmd-dataframe/src/dataframe/expressions/lit.rs deleted file mode 100644 index 8610a59048..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/expressions/lit.rs +++ /dev/null @@ -1,69 +0,0 @@ -use crate::dataframe::values::NuExpression; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct ExprLit; - -impl Command for ExprLit { - fn name(&self) -> &str { - "dfr lit" - } - - fn usage(&self) -> &str { - "Creates a literal expression." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "literal", - SyntaxShape::Any, - "literal to construct the expression", - ) - .input_output_type(Type::Any, Type::Custom("expression".into())) - .category(Category::Custom("expression".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Created a literal expression and converts it to a nu object", - example: "dfr lit 2 | dfr into-nu", - result: Some(Value::test_record(record! { - "expr" => Value::test_string("literal"), - "value" => Value::test_string("2"), - })), - }] - } - - fn search_terms(&self) -> Vec<&str> { - vec!["string", "literal", "expression"] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - _input: PipelineData, - ) -> Result { - let literal: Value = call.req(engine_state, stack, 0)?; - - let expr = NuExpression::try_from_value(literal)?; - Ok(PipelineData::Value( - NuExpression::into_value(expr, call.head), - None, - )) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - use crate::dataframe::eager::ToNu; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(ExprLit {}), Box::new(ToNu {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/expressions/mod.rs b/crates/nu-cmd-dataframe/src/dataframe/expressions/mod.rs deleted file mode 100644 index 4ba70d900d..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/expressions/mod.rs +++ /dev/null @@ -1,62 +0,0 @@ -mod alias; -mod arg_where; -mod col; -mod concat_str; -mod datepart; -mod expressions_macro; -mod is_in; -mod lit; -mod otherwise; -mod quantile; -mod when; - -use nu_protocol::engine::StateWorkingSet; - -pub(crate) use crate::dataframe::expressions::alias::ExprAlias; -use crate::dataframe::expressions::arg_where::ExprArgWhere; -pub(super) use crate::dataframe::expressions::col::ExprCol; -pub(super) use crate::dataframe::expressions::concat_str::ExprConcatStr; -pub(crate) use crate::dataframe::expressions::datepart::ExprDatePart; -pub(crate) use crate::dataframe::expressions::expressions_macro::*; -pub(super) use crate::dataframe::expressions::is_in::ExprIsIn; -pub(super) use crate::dataframe::expressions::lit::ExprLit; -pub(super) use crate::dataframe::expressions::otherwise::ExprOtherwise; -pub(super) use crate::dataframe::expressions::quantile::ExprQuantile; -pub(super) use crate::dataframe::expressions::when::ExprWhen; - -pub fn add_expressions(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)); )* - }; - } - - // Dataframe commands - bind_command!( - ExprAlias, - ExprArgWhere, - ExprCol, - ExprConcatStr, - ExprCount, - ExprLit, - ExprWhen, - ExprOtherwise, - ExprQuantile, - ExprList, - ExprAggGroups, - ExprCount, - ExprIsIn, - ExprNot, - ExprMax, - ExprMin, - ExprSum, - ExprMean, - ExprMedian, - ExprStd, - ExprVar, - ExprDatePart - ); -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/expressions/otherwise.rs b/crates/nu-cmd-dataframe/src/dataframe/expressions/otherwise.rs deleted file mode 100644 index eb97c575b7..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/expressions/otherwise.rs +++ /dev/null @@ -1,126 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression, NuWhen}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct ExprOtherwise; - -impl Command for ExprOtherwise { - fn name(&self) -> &str { - "dfr otherwise" - } - - fn usage(&self) -> &str { - "Completes a when expression." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "otherwise expression", - SyntaxShape::Any, - "expression to apply when no when predicate matches", - ) - .input_output_type(Type::Any, Type::Custom("expression".into())) - .category(Category::Custom("expression".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Create a when conditions", - example: "dfr when ((dfr col a) > 2) 4 | dfr otherwise 5", - result: None, - }, - Example { - description: "Create a when conditions", - example: - "dfr when ((dfr col a) > 2) 4 | dfr when ((dfr col a) < 0) 6 | dfr otherwise 0", - result: None, - }, - Example { - description: "Create a new column for the dataframe", - example: r#"[[a b]; [6 2] [1 4] [4 1]] - | dfr into-lazy - | dfr with-column ( - dfr when ((dfr col a) > 2) 4 | dfr otherwise 5 | dfr as c - ) - | dfr with-column ( - dfr when ((dfr col a) > 5) 10 | dfr when ((dfr col a) < 2) 6 | dfr otherwise 0 | dfr as d - ) - | dfr collect"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(6), Value::test_int(1), Value::test_int(4)], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(2), Value::test_int(4), Value::test_int(1)], - ), - Column::new( - "c".to_string(), - vec![Value::test_int(4), Value::test_int(5), Value::test_int(4)], - ), - Column::new( - "d".to_string(), - vec![Value::test_int(10), Value::test_int(6), Value::test_int(0)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn search_terms(&self) -> Vec<&str> { - vec!["condition", "else"] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let otherwise_predicate: Value = call.req(engine_state, stack, 0)?; - let otherwise_predicate = NuExpression::try_from_value(otherwise_predicate)?; - - let value = input.into_value(call.head)?; - let complete: NuExpression = match NuWhen::try_from_value(value)? { - NuWhen::Then(then) => then.otherwise(otherwise_predicate.into_polars()).into(), - NuWhen::ChainedThen(chained_when) => chained_when - .otherwise(otherwise_predicate.into_polars()) - .into(), - }; - - Ok(PipelineData::Value(complete.into_value(call.head), None)) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use crate::dataframe::eager::{ToNu, WithColumn}; - use crate::dataframe::expressions::when::ExprWhen; - use crate::dataframe::expressions::{ExprAlias, ExprCol}; - - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![ - Box::new(WithColumn {}), - Box::new(ExprCol {}), - Box::new(ExprAlias {}), - Box::new(ExprWhen {}), - Box::new(ExprOtherwise {}), - Box::new(ToNu {}), - ]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/expressions/quantile.rs b/crates/nu-cmd-dataframe/src/dataframe/expressions/quantile.rs deleted file mode 100644 index aaa1029ee9..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/expressions/quantile.rs +++ /dev/null @@ -1,101 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression}; -use nu_engine::command_prelude::*; - -use polars::prelude::{lit, QuantileInterpolOptions}; - -#[derive(Clone)] -pub struct ExprQuantile; - -impl Command for ExprQuantile { - fn name(&self) -> &str { - "dfr quantile" - } - - fn usage(&self) -> &str { - "Aggregates the columns to the selected quantile." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "quantile", - SyntaxShape::Number, - "quantile value for quantile operation", - ) - .input_output_type( - Type::Custom("expression".into()), - Type::Custom("expression".into()), - ) - .category(Category::Custom("expression".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Quantile aggregation for a group-by", - example: r#"[[a b]; [one 2] [one 4] [two 1]] - | dfr into-df - | dfr group-by a - | dfr agg (dfr col b | dfr quantile 0.5)"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_string("one"), Value::test_string("two")], - ), - Column::new( - "b".to_string(), - vec![Value::test_float(4.0), Value::test_float(1.0)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn search_terms(&self) -> Vec<&str> { - vec!["statistics", "percentile", "distribution"] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let value = input.into_value(call.head)?; - let quantile: f64 = call.req(engine_state, stack, 0)?; - - let expr = NuExpression::try_from_value(value)?; - let expr: NuExpression = expr - .into_polars() - .quantile(lit(quantile), QuantileInterpolOptions::default()) - .into(); - - Ok(PipelineData::Value( - NuExpression::into_value(expr, call.head), - None, - )) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - use crate::dataframe::lazy::aggregate::LazyAggregate; - use crate::dataframe::lazy::groupby::ToLazyGroupBy; - - #[test] - fn test_examples() { - test_dataframe(vec![ - Box::new(ExprQuantile {}), - Box::new(LazyAggregate {}), - Box::new(ToLazyGroupBy {}), - ]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/expressions/when.rs b/crates/nu-cmd-dataframe/src/dataframe/expressions/when.rs deleted file mode 100644 index 5a6aad2de7..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/expressions/when.rs +++ /dev/null @@ -1,147 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression, NuWhen}; -use nu_engine::command_prelude::*; - -use polars::prelude::when; - -#[derive(Clone)] -pub struct ExprWhen; - -impl Command for ExprWhen { - fn name(&self) -> &str { - "dfr when" - } - - fn usage(&self) -> &str { - "Creates and modifies a when expression." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "when expression", - SyntaxShape::Any, - "when expression used for matching", - ) - .required( - "then expression", - SyntaxShape::Any, - "expression that will be applied when predicate is true", - ) - .input_output_type( - Type::Custom("expression".into()), - Type::Custom("expression".into()), - ) - .category(Category::Custom("expression".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Create a when conditions", - example: "dfr when ((dfr col a) > 2) 4", - result: None, - }, - Example { - description: "Create a when conditions", - example: "dfr when ((dfr col a) > 2) 4 | dfr when ((dfr col a) < 0) 6", - result: None, - }, - Example { - description: "Create a new column for the dataframe", - example: r#"[[a b]; [6 2] [1 4] [4 1]] - | dfr into-lazy - | dfr with-column ( - dfr when ((dfr col a) > 2) 4 | dfr otherwise 5 | dfr as c - ) - | dfr with-column ( - dfr when ((dfr col a) > 5) 10 | dfr when ((dfr col a) < 2) 6 | dfr otherwise 0 | dfr as d - ) - | dfr collect"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(6), Value::test_int(1), Value::test_int(4)], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(2), Value::test_int(4), Value::test_int(1)], - ), - Column::new( - "c".to_string(), - vec![Value::test_int(4), Value::test_int(5), Value::test_int(4)], - ), - Column::new( - "d".to_string(), - vec![Value::test_int(10), Value::test_int(6), Value::test_int(0)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn search_terms(&self) -> Vec<&str> { - vec!["condition", "match", "if", "else"] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let when_predicate: Value = call.req(engine_state, stack, 0)?; - let when_predicate = NuExpression::try_from_value(when_predicate)?; - - let then_predicate: Value = call.req(engine_state, stack, 1)?; - let then_predicate = NuExpression::try_from_value(then_predicate)?; - - let value = input.into_value(call.head)?; - let when_then: NuWhen = match value { - Value::Nothing { .. } => when(when_predicate.into_polars()) - .then(then_predicate.into_polars()) - .into(), - v => match NuWhen::try_from_value(v)? { - NuWhen::Then(when_then) => when_then - .when(when_predicate.into_polars()) - .then(then_predicate.into_polars()) - .into(), - NuWhen::ChainedThen(when_then_then) => when_then_then - .when(when_predicate.into_polars()) - .then(then_predicate.into_polars()) - .into(), - }, - }; - - Ok(PipelineData::Value(when_then.into_value(call.head), None)) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use crate::dataframe::eager::{ToNu, WithColumn}; - use crate::dataframe::expressions::otherwise::ExprOtherwise; - use crate::dataframe::expressions::{ExprAlias, ExprCol}; - - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![ - Box::new(WithColumn {}), - Box::new(ExprCol {}), - Box::new(ExprAlias {}), - Box::new(ExprWhen {}), - Box::new(ExprOtherwise {}), - Box::new(ToNu {}), - ]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/lazy/aggregate.rs b/crates/nu-cmd-dataframe/src/dataframe/lazy/aggregate.rs deleted file mode 100644 index 715c3d156b..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/lazy/aggregate.rs +++ /dev/null @@ -1,216 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression, NuLazyFrame, NuLazyGroupBy}; -use nu_engine::command_prelude::*; - -use polars::{datatypes::DataType, prelude::Expr}; - -#[derive(Clone)] -pub struct LazyAggregate; - -impl Command for LazyAggregate { - fn name(&self) -> &str { - "dfr agg" - } - - fn usage(&self) -> &str { - "Performs a series of aggregations from a group-by." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .rest( - "Group-by expressions", - SyntaxShape::Any, - "Expression(s) that define the aggregations to be applied", - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Group by and perform an aggregation", - example: r#"[[a b]; [1 2] [1 4] [2 6] [2 4]] - | dfr into-df - | dfr group-by a - | dfr agg [ - (dfr col b | dfr min | dfr as "b_min") - (dfr col b | dfr max | dfr as "b_max") - (dfr col b | dfr sum | dfr as "b_sum") - ]"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(1), Value::test_int(2)], - ), - Column::new( - "b_min".to_string(), - vec![Value::test_int(2), Value::test_int(4)], - ), - Column::new( - "b_max".to_string(), - vec![Value::test_int(4), Value::test_int(6)], - ), - Column::new( - "b_sum".to_string(), - vec![Value::test_int(6), Value::test_int(10)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Group by and perform an aggregation", - example: r#"[[a b]; [1 2] [1 4] [2 6] [2 4]] - | dfr into-lazy - | dfr group-by a - | dfr agg [ - (dfr col b | dfr min | dfr as "b_min") - (dfr col b | dfr max | dfr as "b_max") - (dfr col b | dfr sum | dfr as "b_sum") - ] - | dfr collect"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(1), Value::test_int(2)], - ), - Column::new( - "b_min".to_string(), - vec![Value::test_int(2), Value::test_int(4)], - ), - Column::new( - "b_max".to_string(), - vec![Value::test_int(4), Value::test_int(6)], - ), - Column::new( - "b_sum".to_string(), - vec![Value::test_int(6), Value::test_int(10)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let vals: Vec = call.rest(engine_state, stack, 0)?; - let value = Value::list(vals, call.head); - let expressions = NuExpression::extract_exprs(value)?; - - let group_by = NuLazyGroupBy::try_from_pipeline(input, call.head)?; - - if let Some(schema) = &group_by.schema { - for expr in expressions.iter() { - if let Some(name) = get_col_name(expr) { - let dtype = schema.get(name.as_str()); - - if matches!(dtype, Some(DataType::Object(..))) { - return Err(ShellError::GenericError { - error: "Object type column not supported for aggregation".into(), - msg: format!("Column '{name}' is type Object"), - span: Some(call.head), - help: Some("Aggregations cannot be performed on Object type columns. Use dtype command to check column types".into()), - inner: vec![], - }); - } - } - } - } - - let lazy = NuLazyFrame { - from_eager: group_by.from_eager, - lazy: Some(group_by.into_polars().agg(&expressions)), - schema: None, - }; - - let res = lazy.into_value(call.head)?; - Ok(PipelineData::Value(res, None)) - } -} - -fn get_col_name(expr: &Expr) -> Option { - match expr { - Expr::Column(column) => Some(column.to_string()), - Expr::Agg(agg) => match agg { - polars::prelude::AggExpr::Min { input: e, .. } - | polars::prelude::AggExpr::Max { input: e, .. } - | polars::prelude::AggExpr::Median(e) - | polars::prelude::AggExpr::NUnique(e) - | polars::prelude::AggExpr::First(e) - | polars::prelude::AggExpr::Last(e) - | polars::prelude::AggExpr::Mean(e) - | polars::prelude::AggExpr::Implode(e) - | polars::prelude::AggExpr::Count(e, _) - | polars::prelude::AggExpr::Sum(e) - | polars::prelude::AggExpr::AggGroups(e) - | polars::prelude::AggExpr::Std(e, _) - | polars::prelude::AggExpr::Var(e, _) => get_col_name(e.as_ref()), - polars::prelude::AggExpr::Quantile { expr, .. } => get_col_name(expr.as_ref()), - }, - Expr::Filter { input: expr, .. } - | Expr::Slice { input: expr, .. } - | Expr::Cast { expr, .. } - | Expr::Sort { expr, .. } - | Expr::Gather { expr, .. } - | Expr::SortBy { expr, .. } - | Expr::Exclude(expr, _) - | Expr::Alias(expr, _) - | Expr::KeepName(expr) - | Expr::Explode(expr) => get_col_name(expr.as_ref()), - Expr::Ternary { .. } - | Expr::AnonymousFunction { .. } - | Expr::Function { .. } - | Expr::Columns(_) - | Expr::DtypeColumn(_) - | Expr::Literal(_) - | Expr::BinaryExpr { .. } - | Expr::Window { .. } - | Expr::Wildcard - | Expr::RenameAlias { .. } - | Expr::Len - | Expr::Nth(_) - | Expr::SubPlan(_, _) - | Expr::Selector(_) => None, - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - use crate::dataframe::expressions::{ExprAlias, ExprMax, ExprMin, ExprSum}; - use crate::dataframe::lazy::groupby::ToLazyGroupBy; - - #[test] - fn test_examples() { - test_dataframe(vec![ - Box::new(LazyAggregate {}), - Box::new(ToLazyGroupBy {}), - Box::new(ExprAlias {}), - Box::new(ExprMin {}), - Box::new(ExprMax {}), - Box::new(ExprSum {}), - ]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/lazy/collect.rs b/crates/nu-cmd-dataframe/src/dataframe/lazy/collect.rs deleted file mode 100644 index c27591cc1d..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/lazy/collect.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuLazyFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct LazyCollect; - -impl Command for LazyCollect { - fn name(&self) -> &str { - "dfr collect" - } - - fn usage(&self) -> &str { - "Collect lazy dataframe into eager dataframe." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "drop duplicates", - example: "[[a b]; [1 2] [3 4]] | dfr into-lazy | dfr collect", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(1), Value::test_int(3)], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(2), Value::test_int(4)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?; - let eager = lazy.collect(call.head)?; - let value = Value::custom(Box::new(eager), call.head); - - 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(LazyCollect {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/lazy/explode.rs b/crates/nu-cmd-dataframe/src/dataframe/lazy/explode.rs deleted file mode 100644 index a027e84d36..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/lazy/explode.rs +++ /dev/null @@ -1,153 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression, NuLazyFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct LazyExplode; - -impl Command for LazyExplode { - fn name(&self) -> &str { - "dfr explode" - } - - fn usage(&self) -> &str { - "Explodes a dataframe or creates a explode expression." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .rest( - "columns", - SyntaxShape::String, - "columns to explode, only applicable for dataframes", - ) - .input_output_types(vec![ - ( - Type::Custom("expression".into()), - Type::Custom("expression".into()), - ), - ( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ), - ]) - .category(Category::Custom("lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Explode the specified dataframe", - example: "[[id name hobbies]; [1 Mercy [Cycling Knitting]] [2 Bob [Skiing Football]]] | dfr into-df | dfr explode hobbies | dfr collect", - result: Some( - NuDataFrame::try_from_columns(vec![ - Column::new( - "id".to_string(), - vec![ - Value::test_int(1), - Value::test_int(1), - Value::test_int(2), - Value::test_int(2), - ]), - Column::new( - "name".to_string(), - vec![ - Value::test_string("Mercy"), - Value::test_string("Mercy"), - Value::test_string("Bob"), - Value::test_string("Bob"), - ]), - Column::new( - "hobbies".to_string(), - vec![ - Value::test_string("Cycling"), - Value::test_string("Knitting"), - Value::test_string("Skiing"), - Value::test_string("Football"), - ]), - ], None).expect("simple df for test should not fail") - .into_value(Span::test_data()), - ) - }, - Example { - description: "Select a column and explode the values", - example: "[[id name hobbies]; [1 Mercy [Cycling Knitting]] [2 Bob [Skiing Football]]] | dfr into-df | dfr select (dfr col hobbies | dfr explode)", - result: Some( - NuDataFrame::try_from_columns(vec![ - Column::new( - "hobbies".to_string(), - vec![ - Value::test_string("Cycling"), - Value::test_string("Knitting"), - Value::test_string("Skiing"), - Value::test_string("Football"), - ]), - ], None).expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - explode(call, input) - } -} - -pub(crate) fn explode(call: &Call, input: PipelineData) -> Result { - let value = input.into_value(call.head)?; - if NuDataFrame::can_downcast(&value) { - let df = NuLazyFrame::try_from_value(value)?; - let columns: Vec = call - .positional_iter() - .filter_map(|e| e.as_string()) - .collect(); - - let exploded = df - .into_polars() - .explode(columns.iter().map(AsRef::as_ref).collect::>()); - - Ok(PipelineData::Value( - NuLazyFrame::from(exploded).into_value(call.head)?, - None, - )) - } else { - let expr = NuExpression::try_from_value(value)?; - let expr: NuExpression = expr.into_polars().explode().into(); - - Ok(PipelineData::Value( - NuExpression::into_value(expr, call.head), - None, - )) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::{build_test_engine_state, test_dataframe_example}; - use super::*; - use crate::dataframe::lazy::aggregate::LazyAggregate; - use crate::dataframe::lazy::groupby::ToLazyGroupBy; - - #[test] - fn test_examples_dataframe() { - let mut engine_state = build_test_engine_state(vec![Box::new(LazyExplode {})]); - test_dataframe_example(&mut engine_state, &LazyExplode.examples()[0]); - } - - #[ignore] - #[test] - fn test_examples_expression() { - let mut engine_state = build_test_engine_state(vec![ - Box::new(LazyExplode {}), - Box::new(LazyAggregate {}), - Box::new(ToLazyGroupBy {}), - ]); - test_dataframe_example(&mut engine_state, &LazyExplode.examples()[1]); - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/lazy/fetch.rs b/crates/nu-cmd-dataframe/src/dataframe/lazy/fetch.rs deleted file mode 100644 index 6ba75aa970..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/lazy/fetch.rs +++ /dev/null @@ -1,92 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuLazyFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct LazyFetch; - -impl Command for LazyFetch { - fn name(&self) -> &str { - "dfr fetch" - } - - fn usage(&self) -> &str { - "Collects the lazyframe to the selected rows." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "rows", - SyntaxShape::Int, - "number of rows to be fetched from lazyframe", - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Fetch a rows from the dataframe", - example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr fetch 2", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(6), Value::test_int(4)], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(2), Value::test_int(2)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let rows: i64 = call.req(engine_state, stack, 0)?; - - let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?; - let eager: NuDataFrame = lazy - .into_polars() - .fetch(rows as usize) - .map_err(|e| ShellError::GenericError { - error: "Error fetching rows".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })? - .into(); - - Ok(PipelineData::Value( - NuDataFrame::into_value(eager, call.head), - None, - )) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(LazyFetch {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/lazy/fill_nan.rs b/crates/nu-cmd-dataframe/src/dataframe/lazy/fill_nan.rs deleted file mode 100644 index 4c75f1d9a3..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/lazy/fill_nan.rs +++ /dev/null @@ -1,143 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct LazyFillNA; - -impl Command for LazyFillNA { - fn name(&self) -> &str { - "dfr fill-nan" - } - - fn usage(&self) -> &str { - "Replaces NaN values with the given expression." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "fill", - SyntaxShape::Any, - "Expression to use to fill the NAN values", - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Fills the NaN values with 0", - example: "[1 2 NaN 3 NaN] | dfr into-df | dfr fill-nan 0", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![ - Value::test_int(1), - Value::test_int(2), - Value::test_int(0), - Value::test_int(3), - Value::test_int(0), - ], - )], - None, - ) - .expect("Df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Fills the NaN values of a whole dataframe", - example: "[[a b]; [0.2 1] [0.1 NaN]] | dfr into-df | dfr fill-nan 0", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_float(0.2), Value::test_float(0.1)], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(1), Value::test_int(0)], - ), - ], - None, - ) - .expect("Df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let fill: Value = call.req(engine_state, stack, 0)?; - let value = input.into_value(call.head)?; - - if NuExpression::can_downcast(&value) { - let expr = NuExpression::try_from_value(value)?; - let fill = NuExpression::try_from_value(fill)?.into_polars(); - let expr: NuExpression = expr.into_polars().fill_nan(fill).into(); - - Ok(PipelineData::Value( - NuExpression::into_value(expr, call.head), - None, - )) - } else { - let val_span = value.span(); - let frame = NuDataFrame::try_from_value(value)?; - let columns = frame.columns(val_span)?; - let dataframe = columns - .into_iter() - .map(|column| { - let column_name = column.name().to_string(); - let values = column - .into_iter() - .map(|value| { - let span = value.span(); - match value { - Value::Float { val, .. } => { - if val.is_nan() { - fill.clone() - } else { - value - } - } - Value::List { vals, .. } => { - NuDataFrame::fill_list_nan(vals, span, fill.clone()) - } - _ => value, - } - }) - .collect::>(); - Column::new(column_name, values) - }) - .collect::>(); - Ok(PipelineData::Value( - NuDataFrame::try_from_columns(dataframe, None)?.into_value(call.head), - None, - )) - } - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(LazyFillNA {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/lazy/fill_null.rs b/crates/nu-cmd-dataframe/src/dataframe/lazy/fill_null.rs deleted file mode 100644 index 88be2a9e88..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/lazy/fill_null.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression, NuLazyFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct LazyFillNull; - -impl Command for LazyFillNull { - fn name(&self) -> &str { - "dfr fill-null" - } - - fn usage(&self) -> &str { - "Replaces NULL values with the given expression." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "fill", - SyntaxShape::Any, - "Expression to use to fill the null values", - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Fills the null values by 0", - example: "[1 2 2 3 3] | dfr into-df | dfr shift 2 | dfr fill-null 0", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![ - Value::test_int(0), - Value::test_int(0), - Value::test_int(1), - Value::test_int(2), - Value::test_int(2), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let fill: Value = call.req(engine_state, stack, 0)?; - let value = input.into_value(call.head)?; - - if NuExpression::can_downcast(&value) { - let expr = NuExpression::try_from_value(value)?; - let fill = NuExpression::try_from_value(fill)?.into_polars(); - let expr: NuExpression = expr.into_polars().fill_null(fill).into(); - - Ok(PipelineData::Value( - NuExpression::into_value(expr, call.head), - None, - )) - } else { - let lazy = NuLazyFrame::try_from_value(value)?; - let expr = NuExpression::try_from_value(fill)?.into_polars(); - let lazy = NuLazyFrame::new(lazy.from_eager, lazy.into_polars().fill_null(expr)); - - Ok(PipelineData::Value(lazy.into_value(call.head)?, None)) - } - } -} - -#[cfg(test)] -mod test { - use super::super::super::series::Shift; - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(LazyFillNull {}), Box::new(Shift {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/lazy/filter.rs b/crates/nu-cmd-dataframe/src/dataframe/lazy/filter.rs deleted file mode 100644 index 5635a77e88..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/lazy/filter.rs +++ /dev/null @@ -1,83 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression, NuLazyFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct LazyFilter; - -impl Command for LazyFilter { - fn name(&self) -> &str { - "dfr filter" - } - - fn usage(&self) -> &str { - "Filter dataframe based in expression." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "filter expression", - SyntaxShape::Any, - "Expression that define the column selection", - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Filter dataframe using an expression", - example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr filter ((dfr col a) >= 4)", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(6), Value::test_int(4)], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(2), Value::test_int(2)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let value: Value = call.req(engine_state, stack, 0)?; - let expression = NuExpression::try_from_value(value)?; - - let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?; - let lazy = NuLazyFrame::new( - lazy.from_eager, - lazy.into_polars().filter(expression.into_polars()), - ); - - Ok(PipelineData::Value(lazy.into_value(call.head)?, None)) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(LazyFilter {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/lazy/flatten.rs b/crates/nu-cmd-dataframe/src/dataframe/lazy/flatten.rs deleted file mode 100644 index 602dcbcee3..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/lazy/flatten.rs +++ /dev/null @@ -1,126 +0,0 @@ -use super::explode::explode; -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct LazyFlatten; - -impl Command for LazyFlatten { - fn name(&self) -> &str { - "dfr flatten" - } - - fn usage(&self) -> &str { - "An alias for dfr explode." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .rest( - "columns", - SyntaxShape::String, - "columns to flatten, only applicable for dataframes", - ) - .input_output_types(vec![ - ( - Type::Custom("expression".into()), - Type::Custom("expression".into()), - ), - ( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ), - ]) - .category(Category::Custom("lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![ -Example { - description: "Flatten the specified dataframe", - example: "[[id name hobbies]; [1 Mercy [Cycling Knitting]] [2 Bob [Skiing Football]]] | dfr into-df | dfr flatten hobbies | dfr collect", - result: Some( - NuDataFrame::try_from_columns(vec![ - Column::new( - "id".to_string(), - vec![ - Value::test_int(1), - Value::test_int(1), - Value::test_int(2), - Value::test_int(2), - ]), - Column::new( - "name".to_string(), - vec![ - Value::test_string("Mercy"), - Value::test_string("Mercy"), - Value::test_string("Bob"), - Value::test_string("Bob"), - ]), - Column::new( - "hobbies".to_string(), - vec![ - Value::test_string("Cycling"), - Value::test_string("Knitting"), - Value::test_string("Skiing"), - Value::test_string("Football"), - ]), - ], None).expect("simple df for test should not fail") - .into_value(Span::test_data()), - ) - }, - Example { - description: "Select a column and flatten the values", - example: "[[id name hobbies]; [1 Mercy [Cycling Knitting]] [2 Bob [Skiing Football]]] | dfr into-df | dfr select (dfr col hobbies | dfr flatten)", - result: Some( - NuDataFrame::try_from_columns(vec![ - Column::new( - "hobbies".to_string(), - vec![ - Value::test_string("Cycling"), - Value::test_string("Knitting"), - Value::test_string("Skiing"), - Value::test_string("Football"), - ]), - ], None).expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - explode(call, input) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::{build_test_engine_state, test_dataframe_example}; - use super::*; - use crate::dataframe::lazy::aggregate::LazyAggregate; - use crate::dataframe::lazy::groupby::ToLazyGroupBy; - - #[test] - fn test_examples_dataframe() { - let mut engine_state = build_test_engine_state(vec![Box::new(LazyFlatten {})]); - test_dataframe_example(&mut engine_state, &LazyFlatten.examples()[0]); - } - - #[ignore] - #[test] - fn test_examples_expression() { - let mut engine_state = build_test_engine_state(vec![ - Box::new(LazyFlatten {}), - Box::new(LazyAggregate {}), - Box::new(ToLazyGroupBy {}), - ]); - test_dataframe_example(&mut engine_state, &LazyFlatten.examples()[1]); - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/lazy/groupby.rs b/crates/nu-cmd-dataframe/src/dataframe/lazy/groupby.rs deleted file mode 100644 index c31d563eb6..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/lazy/groupby.rs +++ /dev/null @@ -1,161 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression, NuLazyFrame, NuLazyGroupBy}; -use nu_engine::command_prelude::*; - -use polars::prelude::Expr; - -#[derive(Clone)] -pub struct ToLazyGroupBy; - -impl Command for ToLazyGroupBy { - fn name(&self) -> &str { - "dfr group-by" - } - - fn usage(&self) -> &str { - "Creates a group-by object that can be used for other aggregations." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .rest( - "Group-by expressions", - SyntaxShape::Any, - "Expression(s) that define the lazy group-by", - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Group by and perform an aggregation", - example: r#"[[a b]; [1 2] [1 4] [2 6] [2 4]] - | dfr into-df - | dfr group-by a - | dfr agg [ - (dfr col b | dfr min | dfr as "b_min") - (dfr col b | dfr max | dfr as "b_max") - (dfr col b | dfr sum | dfr as "b_sum") - ]"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(1), Value::test_int(2)], - ), - Column::new( - "b_min".to_string(), - vec![Value::test_int(2), Value::test_int(4)], - ), - Column::new( - "b_max".to_string(), - vec![Value::test_int(4), Value::test_int(6)], - ), - Column::new( - "b_sum".to_string(), - vec![Value::test_int(6), Value::test_int(10)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Group by and perform an aggregation", - example: r#"[[a b]; [1 2] [1 4] [2 6] [2 4]] - | dfr into-lazy - | dfr group-by a - | dfr agg [ - (dfr col b | dfr min | dfr as "b_min") - (dfr col b | dfr max | dfr as "b_max") - (dfr col b | dfr sum | dfr as "b_sum") - ] - | dfr collect"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(1), Value::test_int(2)], - ), - Column::new( - "b_min".to_string(), - vec![Value::test_int(2), Value::test_int(4)], - ), - Column::new( - "b_max".to_string(), - vec![Value::test_int(4), Value::test_int(6)], - ), - Column::new( - "b_sum".to_string(), - vec![Value::test_int(6), Value::test_int(10)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let vals: Vec = call.rest(engine_state, stack, 0)?; - let value = Value::list(vals, call.head); - let expressions = NuExpression::extract_exprs(value)?; - - if expressions - .iter() - .any(|expr| !matches!(expr, Expr::Column(..))) - { - let value: Value = call.req(engine_state, stack, 0)?; - return Err(ShellError::IncompatibleParametersSingle { - msg: "Expected only Col expressions".into(), - span: value.span(), - }); - } - - let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?; - let group_by = NuLazyGroupBy { - schema: lazy.schema.clone(), - from_eager: lazy.from_eager, - group_by: Some(lazy.into_polars().group_by(&expressions)), - }; - - Ok(PipelineData::Value(group_by.into_value(call.head), None)) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - use crate::dataframe::expressions::{ExprAlias, ExprMax, ExprMin, ExprSum}; - use crate::dataframe::lazy::aggregate::LazyAggregate; - - #[test] - fn test_examples() { - test_dataframe(vec![ - Box::new(LazyAggregate {}), - Box::new(ToLazyGroupBy {}), - Box::new(ExprAlias {}), - Box::new(ExprMin {}), - Box::new(ExprMax {}), - Box::new(ExprSum {}), - ]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/lazy/join.rs b/crates/nu-cmd-dataframe/src/dataframe/lazy/join.rs deleted file mode 100644 index 4ae297acfd..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/lazy/join.rs +++ /dev/null @@ -1,252 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression, NuLazyFrame}; -use nu_engine::command_prelude::*; - -use polars::prelude::{Expr, JoinType}; - -#[derive(Clone)] -pub struct LazyJoin; - -impl Command for LazyJoin { - fn name(&self) -> &str { - "dfr join" - } - - fn usage(&self) -> &str { - "Joins a lazy frame with other lazy frame." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("other", SyntaxShape::Any, "LazyFrame to join with") - .required("left_on", SyntaxShape::Any, "Left column(s) to join on") - .required("right_on", SyntaxShape::Any, "Right column(s) to join on") - .switch( - "inner", - "inner join between lazyframes (default)", - Some('i'), - ) - .switch("left", "left join between lazyframes", Some('l')) - .switch("outer", "outer join between lazyframes", Some('o')) - .switch("cross", "cross join between lazyframes", Some('c')) - .named( - "suffix", - SyntaxShape::String, - "Suffix to use on columns with same name", - Some('s'), - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Join two lazy dataframes", - example: r#"let df_a = ([[a b c];[1 "a" 0] [2 "b" 1] [1 "c" 2] [1 "c" 3]] | dfr into-lazy); - let df_b = ([["foo" "bar" "ham"];[1 "a" "let"] [2 "c" "var"] [3 "c" "const"]] | dfr into-lazy); - $df_a | dfr join $df_b a foo | dfr collect"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![ - Value::test_int(1), - Value::test_int(2), - Value::test_int(1), - Value::test_int(1), - ], - ), - Column::new( - "b".to_string(), - vec![ - Value::test_string("a"), - Value::test_string("b"), - Value::test_string("c"), - Value::test_string("c"), - ], - ), - Column::new( - "c".to_string(), - vec![ - Value::test_int(0), - Value::test_int(1), - Value::test_int(2), - Value::test_int(3), - ], - ), - Column::new( - "bar".to_string(), - vec![ - Value::test_string("a"), - Value::test_string("c"), - Value::test_string("a"), - Value::test_string("a"), - ], - ), - Column::new( - "ham".to_string(), - vec![ - Value::test_string("let"), - Value::test_string("var"), - Value::test_string("let"), - Value::test_string("let"), - ], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Join one eager dataframe with a lazy dataframe", - example: r#"let df_a = ([[a b c];[1 "a" 0] [2 "b" 1] [1 "c" 2] [1 "c" 3]] | dfr into-df); - let df_b = ([["foo" "bar" "ham"];[1 "a" "let"] [2 "c" "var"] [3 "c" "const"]] | dfr into-lazy); - $df_a | dfr join $df_b a foo"#, - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![ - Value::test_int(1), - Value::test_int(2), - Value::test_int(1), - Value::test_int(1), - ], - ), - Column::new( - "b".to_string(), - vec![ - Value::test_string("a"), - Value::test_string("b"), - Value::test_string("c"), - Value::test_string("c"), - ], - ), - Column::new( - "c".to_string(), - vec![ - Value::test_int(0), - Value::test_int(1), - Value::test_int(2), - Value::test_int(3), - ], - ), - Column::new( - "bar".to_string(), - vec![ - Value::test_string("a"), - Value::test_string("c"), - Value::test_string("a"), - Value::test_string("a"), - ], - ), - Column::new( - "ham".to_string(), - vec![ - Value::test_string("let"), - Value::test_string("var"), - Value::test_string("let"), - Value::test_string("let"), - ], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let left = call.has_flag(engine_state, stack, "left")?; - let outer = call.has_flag(engine_state, stack, "outer")?; - let cross = call.has_flag(engine_state, stack, "cross")?; - - let how = if left { - JoinType::Left - } else if outer { - JoinType::Outer { coalesce: true } - } else if cross { - JoinType::Cross - } else { - JoinType::Inner - }; - - let other: Value = call.req(engine_state, stack, 0)?; - let other = NuLazyFrame::try_from_value(other)?; - let other = other.into_polars(); - - let left_on: Value = call.req(engine_state, stack, 1)?; - let left_on = NuExpression::extract_exprs(left_on)?; - - let right_on: Value = call.req(engine_state, stack, 2)?; - let right_on = NuExpression::extract_exprs(right_on)?; - - if left_on.len() != right_on.len() { - let right_on: Value = call.req(engine_state, stack, 2)?; - return Err(ShellError::IncompatibleParametersSingle { - msg: "The right column list has a different size to the left column list".into(), - span: right_on.span(), - }); - } - - // Checking that both list of expressions are made out of col expressions or strings - for (index, list) in &[(1usize, &left_on), (2, &left_on)] { - if list.iter().any(|expr| !matches!(expr, Expr::Column(..))) { - let value: Value = call.req(engine_state, stack, *index)?; - return Err(ShellError::IncompatibleParametersSingle { - msg: "Expected only a string, col expressions or list of strings".into(), - span: value.span(), - }); - } - } - - let suffix: Option = call.get_flag(engine_state, stack, "suffix")?; - let suffix = suffix.unwrap_or_else(|| "_x".into()); - - let value = input.into_value(call.head)?; - let lazy = NuLazyFrame::try_from_value(value)?; - let from_eager = lazy.from_eager; - let lazy = lazy.into_polars(); - - let lazy = lazy - .join_builder() - .with(other) - .left_on(left_on) - .right_on(right_on) - .how(how) - .force_parallel(true) - .suffix(suffix) - .finish(); - - let lazy = NuLazyFrame::new(from_eager, lazy); - - Ok(PipelineData::Value(lazy.into_value(call.head)?, None)) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(LazyJoin {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/lazy/macro_commands.rs b/crates/nu-cmd-dataframe/src/dataframe/lazy/macro_commands.rs deleted file mode 100644 index 89655b8e3f..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/lazy/macro_commands.rs +++ /dev/null @@ -1,246 +0,0 @@ -/// Definition of multiple lazyframe commands using a macro rule -/// All of these commands have an identical body and only require -/// to have a change in the name, description and function -use crate::dataframe::values::{Column, NuDataFrame, NuLazyFrame}; -use nu_engine::command_prelude::*; - -macro_rules! lazy_command { - ($command: ident, $name: expr, $desc: expr, $examples: expr, $func: ident, $test: ident) => { - #[derive(Clone)] - pub struct $command; - - impl Command for $command { - fn name(&self) -> &str { - $name - } - - fn usage(&self) -> &str { - $desc - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("lazyframe".into())) - } - - fn examples(&self) -> Vec { - $examples - } - - fn run( - &self, - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?; - let lazy = NuLazyFrame::new(lazy.from_eager, lazy.into_polars().$func()); - - Ok(PipelineData::Value(lazy.into_value(call.head)?, None)) - } - } - - #[cfg(test)] - mod $test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new($command {})]) - } - } - }; - - ($command: ident, $name: expr, $desc: expr, $examples: expr, $func: ident, $test: ident, $ddot: expr) => { - #[derive(Clone)] - pub struct $command; - - impl Command for $command { - fn name(&self) -> &str { - $name - } - - fn usage(&self) -> &str { - $desc - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("lazyframe".into())) - } - - fn examples(&self) -> Vec { - $examples - } - - fn run( - &self, - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?; - let lazy = NuLazyFrame::new(lazy.from_eager, lazy.into_polars().$func($ddot)); - - Ok(PipelineData::Value(lazy.into_value(call.head)?, None)) - } - } - - #[cfg(test)] - mod $test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new($command {})]) - } - } - }; - - ($command: ident, $name: expr, $desc: expr, $examples: expr, $func: ident?, $test: ident) => { - #[derive(Clone)] - pub struct $command; - - impl Command for $command { - fn name(&self) -> &str { - $name - } - - fn usage(&self) -> &str { - $desc - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("lazyframe".into())) - } - - fn examples(&self) -> Vec { - $examples - } - - fn run( - &self, - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?; - - let lazy = NuLazyFrame::new( - lazy.from_eager, - lazy.into_polars() - .$func() - .map_err(|e| ShellError::GenericError { - error: "Dataframe Error".into(), - msg: e.to_string(), - help: None, - span: None, - inner: vec![], - })?, - ); - - Ok(PipelineData::Value(lazy.into_value(call.head)?, None)) - } - } - - #[cfg(test)] - mod $test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new($command {})]) - } - } - }; -} - -// LazyReverse command -// Expands to a command definition for reverse -lazy_command!( - LazyReverse, - "dfr reverse", - "Reverses the LazyFrame", - vec![Example { - description: "Reverses the dataframe.", - example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr reverse", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(2), Value::test_int(4), Value::test_int(6),], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(2), Value::test_int(2), Value::test_int(2),], - ), - ], - None - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - },], - reverse, - test_reverse -); - -// LazyCache command -// Expands to a command definition for cache -lazy_command!( - LazyCache, - "dfr cache", - "Caches operations in a new LazyFrame.", - vec![Example { - description: "Caches the result into a new LazyFrame", - example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr reverse | dfr cache", - result: None, - }], - cache, - test_cache -); - -// LazyMedian command -// Expands to a command definition for median aggregation -lazy_command!( - LazyMedian, - "dfr median", - "Aggregates columns to their median value", - vec![Example { - description: "Median value from columns in a dataframe", - example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr median", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new("a".to_string(), vec![Value::test_float(4.0)],), - Column::new("b".to_string(), vec![Value::test_float(2.0)],), - ], - None - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - },], - median?, - test_median -); diff --git a/crates/nu-cmd-dataframe/src/dataframe/lazy/mod.rs b/crates/nu-cmd-dataframe/src/dataframe/lazy/mod.rs deleted file mode 100644 index cbbc4e8589..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/lazy/mod.rs +++ /dev/null @@ -1,65 +0,0 @@ -pub mod aggregate; -mod collect; -mod explode; -mod fetch; -mod fill_nan; -mod fill_null; -mod filter; -mod flatten; -pub mod groupby; -mod join; -mod macro_commands; -mod quantile; -mod select; -mod sort_by_expr; -mod to_lazy; - -use nu_protocol::engine::StateWorkingSet; - -use crate::dataframe::lazy::aggregate::LazyAggregate; -pub use crate::dataframe::lazy::collect::LazyCollect; -use crate::dataframe::lazy::fetch::LazyFetch; -use crate::dataframe::lazy::fill_nan::LazyFillNA; -pub use crate::dataframe::lazy::fill_null::LazyFillNull; -use crate::dataframe::lazy::filter::LazyFilter; -use crate::dataframe::lazy::groupby::ToLazyGroupBy; -use crate::dataframe::lazy::join::LazyJoin; -pub(crate) use crate::dataframe::lazy::macro_commands::*; -use crate::dataframe::lazy::quantile::LazyQuantile; -pub(crate) use crate::dataframe::lazy::select::LazySelect; -use crate::dataframe::lazy::sort_by_expr::LazySortBy; -pub use crate::dataframe::lazy::to_lazy::ToLazyFrame; -pub use explode::LazyExplode; -pub use flatten::LazyFlatten; - -pub fn add_lazy_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)); )* - }; - } - - // Dataframe commands - bind_command!( - LazyAggregate, - LazyCache, - LazyCollect, - LazyFetch, - LazyFillNA, - LazyFillNull, - LazyFilter, - LazyJoin, - LazyQuantile, - LazyMedian, - LazyReverse, - LazySelect, - LazySortBy, - ToLazyFrame, - ToLazyGroupBy, - LazyExplode, - LazyFlatten - ); -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/lazy/quantile.rs b/crates/nu-cmd-dataframe/src/dataframe/lazy/quantile.rs deleted file mode 100644 index ac8ec590c6..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/lazy/quantile.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuLazyFrame}; -use nu_engine::command_prelude::*; - -use polars::prelude::{lit, QuantileInterpolOptions}; - -#[derive(Clone)] -pub struct LazyQuantile; - -impl Command for LazyQuantile { - fn name(&self) -> &str { - "dfr quantile" - } - - fn usage(&self) -> &str { - "Aggregates the columns to the selected quantile." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "quantile", - SyntaxShape::Number, - "quantile value for quantile operation", - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "quantile value from columns in a dataframe", - example: "[[a b]; [6 2] [1 4] [4 1]] | dfr into-df | dfr quantile 0.5", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new("a".to_string(), vec![Value::test_float(4.0)]), - Column::new("b".to_string(), vec![Value::test_float(2.0)]), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let value = input.into_value(call.head)?; - let quantile: f64 = call.req(engine_state, stack, 0)?; - - let lazy = NuLazyFrame::try_from_value(value)?; - let lazy = NuLazyFrame::new( - lazy.from_eager, - lazy.into_polars() - .quantile(lit(quantile), QuantileInterpolOptions::default()) - .map_err(|e| ShellError::GenericError { - error: "Dataframe Error".into(), - msg: e.to_string(), - help: None, - span: None, - inner: vec![], - })?, - ); - - Ok(PipelineData::Value(lazy.into_value(call.head)?, None)) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(LazyQuantile {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/lazy/select.rs b/crates/nu-cmd-dataframe/src/dataframe/lazy/select.rs deleted file mode 100644 index b4f01bdc07..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/lazy/select.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression, NuLazyFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct LazySelect; - -impl Command for LazySelect { - fn name(&self) -> &str { - "dfr select" - } - - fn usage(&self) -> &str { - "Selects columns from lazyframe." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .rest( - "select expressions", - SyntaxShape::Any, - "Expression(s) that define the column selection", - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Select a column from the dataframe", - example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr select a", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "a".to_string(), - vec![Value::test_int(6), Value::test_int(4), Value::test_int(2)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let vals: Vec = call.rest(engine_state, stack, 0)?; - let value = Value::list(vals, call.head); - let expressions = NuExpression::extract_exprs(value)?; - - let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?; - let lazy = NuLazyFrame::new(lazy.from_eager, lazy.into_polars().select(&expressions)); - - Ok(PipelineData::Value(lazy.into_value(call.head)?, None)) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(LazySelect {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/lazy/sort_by_expr.rs b/crates/nu-cmd-dataframe/src/dataframe/lazy/sort_by_expr.rs deleted file mode 100644 index 2e109338a9..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/lazy/sort_by_expr.rs +++ /dev/null @@ -1,159 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression, NuLazyFrame}; -use nu_engine::command_prelude::*; -use polars::chunked_array::ops::SortMultipleOptions; - -#[derive(Clone)] -pub struct LazySortBy; - -impl Command for LazySortBy { - fn name(&self) -> &str { - "dfr sort-by" - } - - fn usage(&self) -> &str { - "Sorts a lazy dataframe based on expression(s)." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .rest( - "sort expression", - SyntaxShape::Any, - "sort expression for the dataframe", - ) - .named( - "reverse", - SyntaxShape::List(Box::new(SyntaxShape::Boolean)), - "Reverse sorting. Default is false", - Some('r'), - ) - .switch( - "nulls-last", - "nulls are shown last in the dataframe", - Some('n'), - ) - .switch("maintain-order", "Maintains order during sort", Some('m')) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Sort dataframe by one column", - example: "[[a b]; [6 2] [1 4] [4 1]] | dfr into-df | dfr sort-by a", - result: Some( - NuDataFrame::try_from_columns(vec![ - Column::new( - "a".to_string(), - vec![Value::test_int(1), Value::test_int(4), Value::test_int(6)], - ), - Column::new( - "b".to_string(), - vec![Value::test_int(4), Value::test_int(1), Value::test_int(2)], - ), - ], None) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Sort column using two columns", - example: - "[[a b]; [6 2] [1 1] [1 4] [2 4]] | dfr into-df | dfr sort-by [a b] -r [false true]", - result: Some( - NuDataFrame::try_from_columns(vec![ - Column::new( - "a".to_string(), - vec![ - Value::test_int(1), - Value::test_int(1), - Value::test_int(2), - Value::test_int(6), - ], - ), - Column::new( - "b".to_string(), - vec![ - Value::test_int(4), - Value::test_int(1), - Value::test_int(4), - Value::test_int(2), - ], - ), - ], None) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let vals: Vec = call.rest(engine_state, stack, 0)?; - let value = Value::list(vals, call.head); - let expressions = NuExpression::extract_exprs(value)?; - let nulls_last = call.has_flag(engine_state, stack, "nulls-last")?; - let maintain_order = call.has_flag(engine_state, stack, "maintain-order")?; - - let reverse: Option> = call.get_flag(engine_state, stack, "reverse")?; - let reverse = match reverse { - Some(list) => { - if expressions.len() != list.len() { - let span = call - .get_flag::(engine_state, stack, "reverse")? - .expect("already checked and it exists") - .span(); - return Err(ShellError::GenericError { - error: "Incorrect list size".into(), - msg: "Size doesn't match expression list".into(), - span: Some(span), - help: None, - inner: vec![], - }); - } else { - list - } - } - None => expressions.iter().map(|_| false).collect::>(), - }; - - let sort_options = SortMultipleOptions { - descending: reverse, - nulls_last, - multithreaded: true, - maintain_order, - }; - - let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?; - let lazy = NuLazyFrame::new( - lazy.from_eager, - lazy.into_polars().sort_by_exprs(&expressions, sort_options), - ); - - Ok(PipelineData::Value( - NuLazyFrame::into_value(lazy, call.head)?, - None, - )) - } -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(LazySortBy {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/lazy/to_lazy.rs b/crates/nu-cmd-dataframe/src/dataframe/lazy/to_lazy.rs deleted file mode 100644 index 1c711cdd57..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/lazy/to_lazy.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::dataframe::values::{NuDataFrame, NuLazyFrame, NuSchema}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct ToLazyFrame; - -impl Command for ToLazyFrame { - fn name(&self) -> &str { - "dfr into-lazy" - } - - fn usage(&self) -> &str { - "Converts a dataframe into a lazy dataframe." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .named( - "schema", - SyntaxShape::Record(vec![]), - r#"Polars Schema in format [{name: str}]. CSV, JSON, and JSONL files"#, - Some('s'), - ) - .input_output_type(Type::Any, Type::Custom("dataframe".into())) - .category(Category::Custom("lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Takes a dictionary and creates a lazy dataframe", - example: "[[a b];[1 2] [3 4]] | dfr into-lazy", - result: None, - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let maybe_schema = call - .get_flag(engine_state, stack, "schema")? - .map(|schema| NuSchema::try_from(&schema)) - .transpose()?; - - let df = NuDataFrame::try_from_iter(input.into_iter(), maybe_schema)?; - let lazy = NuLazyFrame::from_dataframe(df); - let value = Value::custom(Box::new(lazy), call.head); - Ok(PipelineData::Value(value, None)) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/mod.rs b/crates/nu-cmd-dataframe/src/dataframe/mod.rs deleted file mode 100644 index d99ce516be..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/mod.rs +++ /dev/null @@ -1,36 +0,0 @@ -mod eager; -mod expressions; -mod lazy; -mod series; -mod stub; -mod utils; -mod values; - -pub use eager::add_eager_decls; -pub use expressions::add_expressions; -pub use lazy::add_lazy_decls; -pub use series::add_series_decls; - -use nu_protocol::engine::{EngineState, StateWorkingSet}; - -pub fn add_dataframe_context(mut engine_state: EngineState) -> EngineState { - let delta = { - let mut working_set = StateWorkingSet::new(&engine_state); - working_set.add_decl(Box::new(stub::Dfr)); - add_series_decls(&mut working_set); - add_eager_decls(&mut working_set); - add_expressions(&mut working_set); - add_lazy_decls(&mut working_set); - - working_set.render() - }; - - if let Err(err) = engine_state.merge_delta(delta) { - eprintln!("Error creating dataframe command context: {err:?}"); - } - - engine_state -} - -#[cfg(test)] -mod test_dataframe; diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/all_false.rs b/crates/nu-cmd-dataframe/src/dataframe/series/all_false.rs deleted file mode 100644 index 66921e793c..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/all_false.rs +++ /dev/null @@ -1,108 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct AllFalse; - -impl Command for AllFalse { - fn name(&self) -> &str { - "dfr all-false" - } - - fn usage(&self) -> &str { - "Returns true if all values are false." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Returns true if all values are false", - example: "[false false false] | dfr into-df | dfr all-false", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "all_false".to_string(), - vec![Value::test_bool(true)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Checks the result from a comparison", - example: r#"let s = ([5 6 2 10] | dfr into-df); - let res = ($s > 9); - $res | dfr all-false"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "all_false".to_string(), - vec![Value::test_bool(false)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let series = df.as_series(call.head)?; - let bool = series.bool().map_err(|_| ShellError::GenericError { - error: "Error converting to bool".into(), - msg: "all-false only works with series of type bool".into(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let value = Value::bool(!bool.any(), call.head); - - NuDataFrame::try_from_columns( - vec![Column::new("all_false".to_string(), vec![value])], - None, - ) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(AllFalse {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/all_true.rs b/crates/nu-cmd-dataframe/src/dataframe/series/all_true.rs deleted file mode 100644 index 16b4a9edd9..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/all_true.rs +++ /dev/null @@ -1,105 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct AllTrue; - -impl Command for AllTrue { - fn name(&self) -> &str { - "dfr all-true" - } - - fn usage(&self) -> &str { - "Returns true if all values are true." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Returns true if all values are true", - example: "[true true true] | dfr into-df | dfr all-true", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "all_true".to_string(), - vec![Value::test_bool(true)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Checks the result from a comparison", - example: r#"let s = ([5 6 2 8] | dfr into-df); - let res = ($s > 9); - $res | dfr all-true"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "all_true".to_string(), - vec![Value::test_bool(false)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let series = df.as_series(call.head)?; - let bool = series.bool().map_err(|_| ShellError::GenericError { - error: "Error converting to bool".into(), - msg: "all-false only works with series of type bool".into(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let value = Value::bool(bool.all(), call.head); - - NuDataFrame::try_from_columns(vec![Column::new("all_true".to_string(), vec![value])], None) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(AllTrue {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/arg_max.rs b/crates/nu-cmd-dataframe/src/dataframe/series/arg_max.rs deleted file mode 100644 index d7539401ab..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/arg_max.rs +++ /dev/null @@ -1,85 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::{ArgAgg, IntoSeries, NewChunkedArray, UInt32Chunked}; - -#[derive(Clone)] -pub struct ArgMax; - -impl Command for ArgMax { - fn name(&self) -> &str { - "dfr arg-max" - } - - fn usage(&self) -> &str { - "Return index for max value in series." - } - - fn search_terms(&self) -> Vec<&str> { - vec!["argmax", "maximum", "most", "largest", "greatest"] - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Returns index for max value", - example: "[1 3 2] | dfr into-df | dfr arg-max", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new("arg_max".to_string(), vec![Value::test_int(1)])], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let res = series.arg_max(); - let chunked = match res { - Some(index) => UInt32Chunked::from_slice("arg_max", &[index as u32]), - None => UInt32Chunked::from_slice("arg_max", &[]), - }; - - let res = chunked.into_series(); - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(ArgMax {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/arg_min.rs b/crates/nu-cmd-dataframe/src/dataframe/series/arg_min.rs deleted file mode 100644 index 1b685d65b4..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/arg_min.rs +++ /dev/null @@ -1,85 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::{ArgAgg, IntoSeries, NewChunkedArray, UInt32Chunked}; - -#[derive(Clone)] -pub struct ArgMin; - -impl Command for ArgMin { - fn name(&self) -> &str { - "dfr arg-min" - } - - fn usage(&self) -> &str { - "Return index for min value in series." - } - - fn search_terms(&self) -> Vec<&str> { - vec!["argmin", "minimum", "least", "smallest", "lowest"] - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Returns index for min value", - example: "[1 3 2] | dfr into-df | dfr arg-min", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new("arg_min".to_string(), vec![Value::test_int(0)])], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let res = series.arg_min(); - let chunked = match res { - Some(index) => UInt32Chunked::from_slice("arg_min", &[index as u32]), - None => UInt32Chunked::from_slice("arg_min", &[]), - }; - - let res = chunked.into_series(); - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(ArgMin {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/cumulative.rs b/crates/nu-cmd-dataframe/src/dataframe/series/cumulative.rs deleted file mode 100644 index c32875e87b..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/cumulative.rs +++ /dev/null @@ -1,148 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -use polars::prelude::{DataType, IntoSeries}; -use polars_ops::prelude::{cum_max, cum_min, cum_sum}; - -enum CumType { - Min, - Max, - Sum, -} - -impl CumType { - fn from_str(roll_type: &str, span: Span) -> Result { - match roll_type { - "min" => Ok(Self::Min), - "max" => Ok(Self::Max), - "sum" => Ok(Self::Sum), - _ => Err(ShellError::GenericError { - error: "Wrong operation".into(), - msg: "Operation not valid for cumulative".into(), - span: Some(span), - help: Some("Allowed values: max, min, sum".into()), - inner: vec![], - }), - } - } - - fn to_str(&self) -> &'static str { - match self { - CumType::Min => "cumulative_min", - CumType::Max => "cumulative_max", - CumType::Sum => "cumulative_sum", - } - } -} - -#[derive(Clone)] -pub struct Cumulative; - -impl Command for Cumulative { - fn name(&self) -> &str { - "dfr cumulative" - } - - fn usage(&self) -> &str { - "Cumulative calculation for a series." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("type", SyntaxShape::String, "rolling operation") - .switch("reverse", "Reverse cumulative calculation", Some('r')) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Cumulative sum for a series", - example: "[1 2 3 4 5] | dfr into-df | dfr cumulative sum", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0_cumulative_sum".to_string(), - vec![ - Value::test_int(1), - Value::test_int(3), - Value::test_int(6), - Value::test_int(10), - Value::test_int(15), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let cum_type: Spanned = call.req(engine_state, stack, 0)?; - let reverse = call.has_flag(engine_state, stack, "reverse")?; - - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - if let DataType::Object(..) = series.dtype() { - return Err(ShellError::GenericError { - error: "Found object series".into(), - msg: "Series of type object cannot be used for cumulative operation".into(), - span: Some(call.head), - help: None, - inner: vec![], - }); - } - - let cum_type = CumType::from_str(&cum_type.item, cum_type.span)?; - let mut res = match cum_type { - CumType::Max => cum_max(&series, reverse), - CumType::Min => cum_min(&series, reverse), - CumType::Sum => cum_sum(&series, reverse), - } - .map_err(|e| ShellError::GenericError { - error: "Error creating cumulative".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let name = format!("{}_{}", series.name(), cum_type.to_str()); - res.rename(&name); - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(Cumulative {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/date/as_date.rs b/crates/nu-cmd-dataframe/src/dataframe/series/date/as_date.rs deleted file mode 100644 index b406057572..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/date/as_date.rs +++ /dev/null @@ -1,94 +0,0 @@ -use crate::dataframe::values::NuDataFrame; -use nu_engine::command_prelude::*; - -use polars::prelude::{IntoSeries, StringMethods}; - -#[derive(Clone)] -pub struct AsDate; - -impl Command for AsDate { - fn name(&self) -> &str { - "dfr as-date" - } - - fn usage(&self) -> &str { - r#"Converts string to date."# - } - - fn extra_usage(&self) -> &str { - r#"Format example: - "%Y-%m-%d" => 2021-12-31 - "%d-%m-%Y" => 31-12-2021 - "%Y%m%d" => 2021319 (2021-03-19)"# - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("format", SyntaxShape::String, "formatting date string") - .switch("not-exact", "the format string may be contained in the date (e.g. foo-2021-01-01-bar could match 2021-01-01)", Some('n')) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Converts string to date", - example: r#"["2021-12-30" "2021-12-31"] | dfr into-df | dfr as-datetime "%Y-%m-%d""#, - result: None, - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let format: String = call.req(engine_state, stack, 0)?; - let not_exact = call.has_flag(engine_state, stack, "not-exact")?; - - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - let casted = series.str().map_err(|e| ShellError::GenericError { - error: "Error casting to string".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let res = if not_exact { - casted.as_date_not_exact(Some(format.as_str())) - } else { - casted.as_date(Some(format.as_str()), false) - }; - - let mut res = res - .map_err(|e| ShellError::GenericError { - error: "Error creating datetime".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })? - .into_series(); - - res.rename("date"); - - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/date/as_datetime.rs b/crates/nu-cmd-dataframe/src/dataframe/series/date/as_datetime.rs deleted file mode 100644 index 6ee979b069..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/date/as_datetime.rs +++ /dev/null @@ -1,187 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use chrono::DateTime; -use nu_engine::command_prelude::*; - -use polars::prelude::{IntoSeries, StringMethods, TimeUnit}; - -#[derive(Clone)] -pub struct AsDateTime; - -impl Command for AsDateTime { - fn name(&self) -> &str { - "dfr as-datetime" - } - - fn usage(&self) -> &str { - r#"Converts string to datetime."# - } - - fn extra_usage(&self) -> &str { - r#"Format example: - "%y/%m/%d %H:%M:%S" => 21/12/31 12:54:98 - "%y-%m-%d %H:%M:%S" => 2021-12-31 24:58:01 - "%y/%m/%d %H:%M:%S" => 21/12/31 24:58:01 - "%y%m%d %H:%M:%S" => 210319 23:58:50 - "%Y/%m/%d %H:%M:%S" => 2021/12/31 12:54:98 - "%Y-%m-%d %H:%M:%S" => 2021-12-31 24:58:01 - "%Y/%m/%d %H:%M:%S" => 2021/12/31 24:58:01 - "%Y%m%d %H:%M:%S" => 20210319 23:58:50 - "%FT%H:%M:%S" => 2019-04-18T02:45:55 - "%FT%H:%M:%S.%6f" => microseconds - "%FT%H:%M:%S.%9f" => nanoseconds"# - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("format", SyntaxShape::String, "formatting date time string") - .switch("not-exact", "the format string may be contained in the date (e.g. foo-2021-01-01-bar could match 2021-01-01)", Some('n')) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Converts string to datetime", - example: r#"["2021-12-30 00:00:00" "2021-12-31 00:00:00"] | dfr into-df | dfr as-datetime "%Y-%m-%d %H:%M:%S""#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "datetime".to_string(), - vec![ - Value::date( - DateTime::parse_from_str( - "2021-12-30 00:00:00 +0000", - "%Y-%m-%d %H:%M:%S %z", - ) - .expect("date calculation should not fail in test"), - Span::test_data(), - ), - Value::date( - DateTime::parse_from_str( - "2021-12-31 00:00:00 +0000", - "%Y-%m-%d %H:%M:%S %z", - ) - .expect("date calculation should not fail in test"), - Span::test_data(), - ), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Converts string to datetime with high resolutions", - example: r#"["2021-12-30 00:00:00.123456789" "2021-12-31 00:00:00.123456789"] | dfr into-df | dfr as-datetime "%Y-%m-%d %H:%M:%S.%9f""#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "datetime".to_string(), - vec![ - Value::date( - DateTime::parse_from_str( - "2021-12-30 00:00:00.123456789 +0000", - "%Y-%m-%d %H:%M:%S.%9f %z", - ) - .expect("date calculation should not fail in test"), - Span::test_data(), - ), - Value::date( - DateTime::parse_from_str( - "2021-12-31 00:00:00.123456789 +0000", - "%Y-%m-%d %H:%M:%S.%9f %z", - ) - .expect("date calculation should not fail in test"), - Span::test_data(), - ), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let format: String = call.req(engine_state, stack, 0)?; - let not_exact = call.has_flag(engine_state, stack, "not-exact")?; - - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - let casted = series.str().map_err(|e| ShellError::GenericError { - error: "Error casting to string".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let res = if not_exact { - casted.as_datetime_not_exact( - Some(format.as_str()), - TimeUnit::Nanoseconds, - false, - None, - &Default::default(), - ) - } else { - casted.as_datetime( - Some(format.as_str()), - TimeUnit::Nanoseconds, - false, - false, - None, - &Default::default(), - ) - }; - - let mut res = res - .map_err(|e| ShellError::GenericError { - error: "Error creating datetime".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })? - .into_series(); - - res.rename("datetime"); - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(AsDateTime {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_day.rs b/crates/nu-cmd-dataframe/src/dataframe/series/date/get_day.rs deleted file mode 100644 index 9187219d7a..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_day.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::{DatetimeMethods, IntoSeries}; - -#[derive(Clone)] -pub struct GetDay; - -impl Command for GetDay { - fn name(&self) -> &str { - "dfr get-day" - } - - fn usage(&self) -> &str { - "Gets day from date." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Returns day from a date", - example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime --timezone 'UTC'); - let df = ([$dt $dt] | dfr into-df); - $df | dfr get-day"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![Value::test_int(4), Value::test_int(4)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let casted = series.datetime().map_err(|e| ShellError::GenericError { - error: "Error casting to datetime type".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let res = casted.day().into_series(); - - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(explore_refactor_IntoDatetime)] -mod test { - use super::super::super::super::super::IntoDatetime; - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(GetDay {}), Box::new(IntoDatetime {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_hour.rs b/crates/nu-cmd-dataframe/src/dataframe/series/date/get_hour.rs deleted file mode 100644 index ba05843047..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_hour.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::{DatetimeMethods, IntoSeries}; - -#[derive(Clone)] -pub struct GetHour; - -impl Command for GetHour { - fn name(&self) -> &str { - "dfr get-hour" - } - - fn usage(&self) -> &str { - "Gets hour from date." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Returns hour from a date", - example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime --timezone 'UTC'); - let df = ([$dt $dt] | dfr into-df); - $df | dfr get-hour"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![Value::test_int(16), Value::test_int(16)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let casted = series.datetime().map_err(|e| ShellError::GenericError { - error: "Error casting to datetime type".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let res = casted.hour().into_series(); - - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(explore_refactor_IntoDatetime)] -mod test { - use super::super::super::super::super::IntoDatetime; - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(GetHour {}), Box::new(IntoDatetime {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_minute.rs b/crates/nu-cmd-dataframe/src/dataframe/series/date/get_minute.rs deleted file mode 100644 index 902ed61d56..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_minute.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::{DatetimeMethods, IntoSeries}; - -#[derive(Clone)] -pub struct GetMinute; - -impl Command for GetMinute { - fn name(&self) -> &str { - "dfr get-minute" - } - - fn usage(&self) -> &str { - "Gets minute from date." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Returns minute from a date", - example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime --timezone 'UTC'); - let df = ([$dt $dt] | dfr into-df); - $df | dfr get-minute"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![Value::test_int(39), Value::test_int(39)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let casted = series.datetime().map_err(|e| ShellError::GenericError { - error: "Error casting to datetime type".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let res = casted.minute().into_series(); - - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(explore_refactor_IntoDatetime)] -mod test { - use super::super::super::super::super::IntoDatetime; - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(GetMinute {}), Box::new(IntoDatetime {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_month.rs b/crates/nu-cmd-dataframe/src/dataframe/series/date/get_month.rs deleted file mode 100644 index 077d5afc1e..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_month.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::{DatetimeMethods, IntoSeries}; - -#[derive(Clone)] -pub struct GetMonth; - -impl Command for GetMonth { - fn name(&self) -> &str { - "dfr get-month" - } - - fn usage(&self) -> &str { - "Gets month from date." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Returns month from a date", - example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime --timezone 'UTC'); - let df = ([$dt $dt] | dfr into-df); - $df | dfr get-month"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![Value::test_int(8), Value::test_int(8)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let casted = series.datetime().map_err(|e| ShellError::GenericError { - error: "Error casting to datetime type".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let res = casted.month().into_series(); - - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(explore_refactor_IntoDatetime)] -mod test { - use super::super::super::super::super::IntoDatetime; - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(GetMonth {}), Box::new(IntoDatetime {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_nanosecond.rs b/crates/nu-cmd-dataframe/src/dataframe/series/date/get_nanosecond.rs deleted file mode 100644 index 1543e31082..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_nanosecond.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::{DatetimeMethods, IntoSeries}; - -#[derive(Clone)] -pub struct GetNanosecond; - -impl Command for GetNanosecond { - fn name(&self) -> &str { - "dfr get-nanosecond" - } - - fn usage(&self) -> &str { - "Gets nanosecond from date." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Returns nanosecond from a date", - example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime --timezone 'UTC'); - let df = ([$dt $dt] | dfr into-df); - $df | dfr get-nanosecond"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![Value::test_int(0), Value::test_int(0)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let casted = series.datetime().map_err(|e| ShellError::GenericError { - error: "Error casting to datetime type".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let res = casted.nanosecond().into_series(); - - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(explore_refactor_IntoDatetime)] -mod test { - use super::super::super::super::super::IntoDatetime; - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(GetNanosecond {}), Box::new(IntoDatetime {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_ordinal.rs b/crates/nu-cmd-dataframe/src/dataframe/series/date/get_ordinal.rs deleted file mode 100644 index b77ebbc14c..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_ordinal.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::{DatetimeMethods, IntoSeries}; - -#[derive(Clone)] -pub struct GetOrdinal; - -impl Command for GetOrdinal { - fn name(&self) -> &str { - "dfr get-ordinal" - } - - fn usage(&self) -> &str { - "Gets ordinal from date." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Returns ordinal from a date", - example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime --timezone 'UTC'); - let df = ([$dt $dt] | dfr into-df); - $df | dfr get-ordinal"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![Value::test_int(217), Value::test_int(217)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let casted = series.datetime().map_err(|e| ShellError::GenericError { - error: "Error casting to datetime type".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let res = casted.ordinal().into_series(); - - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(explore_refactor_IntoDatetime)] -mod test { - use super::super::super::super::super::IntoDatetime; - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(GetOrdinal {}), Box::new(IntoDatetime {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_second.rs b/crates/nu-cmd-dataframe/src/dataframe/series/date/get_second.rs deleted file mode 100644 index e039bcc010..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_second.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::{DatetimeMethods, IntoSeries}; - -#[derive(Clone)] -pub struct GetSecond; - -impl Command for GetSecond { - fn name(&self) -> &str { - "dfr get-second" - } - - fn usage(&self) -> &str { - "Gets second from date." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Returns second from a date", - example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime --timezone 'UTC'); - let df = ([$dt $dt] | dfr into-df); - $df | dfr get-second"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![Value::test_int(18), Value::test_int(18)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let casted = series.datetime().map_err(|e| ShellError::GenericError { - error: "Error casting to datetime type".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let res = casted.second().into_series(); - - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(explore_refactor_IntoDatetime)] -mod test { - use super::super::super::super::super::IntoDatetime; - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(GetSecond {}), Box::new(IntoDatetime {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_week.rs b/crates/nu-cmd-dataframe/src/dataframe/series/date/get_week.rs deleted file mode 100644 index 1a1bc2c12d..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_week.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::{DatetimeMethods, IntoSeries}; - -#[derive(Clone)] -pub struct GetWeek; - -impl Command for GetWeek { - fn name(&self) -> &str { - "dfr get-week" - } - - fn usage(&self) -> &str { - "Gets week from date." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Returns week from a date", - example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime --timezone 'UTC'); - let df = ([$dt $dt] | dfr into-df); - $df | dfr get-week"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![Value::test_int(32), Value::test_int(32)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let casted = series.datetime().map_err(|e| ShellError::GenericError { - error: "Error casting to datetime type".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let res = casted.week().into_series(); - - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(explore_refactor_IntoDatetime)] -mod test { - use super::super::super::super::super::IntoDatetime; - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(GetWeek {}), Box::new(IntoDatetime {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_weekday.rs b/crates/nu-cmd-dataframe/src/dataframe/series/date/get_weekday.rs deleted file mode 100644 index b5cf1b3197..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_weekday.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::{DatetimeMethods, IntoSeries}; - -#[derive(Clone)] -pub struct GetWeekDay; - -impl Command for GetWeekDay { - fn name(&self) -> &str { - "dfr get-weekday" - } - - fn usage(&self) -> &str { - "Gets weekday from date." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Returns weekday from a date", - example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime --timezone 'UTC'); - let df = ([$dt $dt] | dfr into-df); - $df | dfr get-weekday"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![Value::test_int(2), Value::test_int(2)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let casted = series.datetime().map_err(|e| ShellError::GenericError { - error: "Error casting to datetime type".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let res = casted.weekday().into_series(); - - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(explore_refactor_IntoDatetime)] -mod test { - use super::super::super::super::super::IntoDatetime; - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(GetWeekDay {}), Box::new(IntoDatetime {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_year.rs b/crates/nu-cmd-dataframe/src/dataframe/series/date/get_year.rs deleted file mode 100644 index 1ec3515949..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/date/get_year.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::{DatetimeMethods, IntoSeries}; - -#[derive(Clone)] -pub struct GetYear; - -impl Command for GetYear { - fn name(&self) -> &str { - "dfr get-year" - } - - fn usage(&self) -> &str { - "Gets year from date." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Returns year from a date", - example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime --timezone 'UTC'); - let df = ([$dt $dt] | dfr into-df); - $df | dfr get-year"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![Value::test_int(2020), Value::test_int(2020)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let casted = series.datetime().map_err(|e| ShellError::GenericError { - error: "Error casting to datetime type".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let res = casted.year().into_series(); - - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(explore_refactor_IntoDatetime)] -mod test { - use super::super::super::super::super::IntoDatetime; - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(GetYear {}), Box::new(IntoDatetime {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/date/mod.rs b/crates/nu-cmd-dataframe/src/dataframe/series/date/mod.rs deleted file mode 100644 index ed3895a172..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/date/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -mod as_date; -mod as_datetime; -mod get_day; -mod get_hour; -mod get_minute; -mod get_month; -mod get_nanosecond; -mod get_ordinal; -mod get_second; -mod get_week; -mod get_weekday; -mod get_year; - -pub use as_date::AsDate; -pub use as_datetime::AsDateTime; -pub use get_day::GetDay; -pub use get_hour::GetHour; -pub use get_minute::GetMinute; -pub use get_month::GetMonth; -pub use get_nanosecond::GetNanosecond; -pub use get_ordinal::GetOrdinal; -pub use get_second::GetSecond; -pub use get_week::GetWeek; -pub use get_weekday::GetWeekDay; -pub use get_year::GetYear; diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/indexes/arg_sort.rs b/crates/nu-cmd-dataframe/src/dataframe/series/indexes/arg_sort.rs deleted file mode 100644 index bf28cbac58..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/indexes/arg_sort.rs +++ /dev/null @@ -1,130 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -use polars::prelude::{IntoSeries, SortOptions}; - -#[derive(Clone)] -pub struct ArgSort; - -impl Command for ArgSort { - fn name(&self) -> &str { - "dfr arg-sort" - } - - fn usage(&self) -> &str { - "Returns indexes for a sorted series." - } - - fn search_terms(&self) -> Vec<&str> { - vec!["argsort", "order", "arrange"] - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .switch("reverse", "reverse order", Some('r')) - .switch("nulls-last", "nulls ordered last", Some('n')) - .switch( - "maintain-order", - "maintain order on sorted items", - Some('m'), - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Returns indexes for a sorted series", - example: "[1 2 2 3 3] | dfr into-df | dfr arg-sort", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "arg_sort".to_string(), - vec![ - Value::test_int(0), - Value::test_int(1), - Value::test_int(2), - Value::test_int(3), - Value::test_int(4), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Returns indexes for a sorted series", - example: "[1 2 2 3 3] | dfr into-df | dfr arg-sort --reverse", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "arg_sort".to_string(), - vec![ - Value::test_int(3), - Value::test_int(4), - Value::test_int(1), - Value::test_int(2), - Value::test_int(0), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let sort_options = SortOptions { - descending: call.has_flag(engine_state, stack, "reverse")?, - nulls_last: call.has_flag(engine_state, stack, "nulls-last")?, - multithreaded: true, - maintain_order: call.has_flag(engine_state, stack, "maintain-order")?, - }; - - let mut res = df - .as_series(call.head)? - .arg_sort(sort_options) - .into_series(); - res.rename("arg_sort"); - - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(ArgSort {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/indexes/arg_true.rs b/crates/nu-cmd-dataframe/src/dataframe/series/indexes/arg_true.rs deleted file mode 100644 index 106e95f5ea..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/indexes/arg_true.rs +++ /dev/null @@ -1,115 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::{arg_where, col, IntoLazy}; - -#[derive(Clone)] -pub struct ArgTrue; - -impl Command for ArgTrue { - fn name(&self) -> &str { - "dfr arg-true" - } - - fn usage(&self) -> &str { - "Returns indexes where values are true." - } - - fn search_terms(&self) -> Vec<&str> { - vec!["argtrue", "truth", "boolean-true"] - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Returns indexes where values are true", - example: "[false true false] | dfr into-df | dfr arg-true", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "arg_true".to_string(), - vec![Value::test_int(1)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let columns = df.as_ref().get_column_names(); - if columns.len() > 1 { - return Err(ShellError::GenericError { - error: "Error using as series".into(), - msg: "dataframe has more than one column".into(), - span: Some(call.head), - help: None, - inner: vec![], - }); - } - - match columns.first() { - Some(column) => { - let expression = arg_where(col(column).eq(true)).alias("arg_true"); - let res = df - .as_ref() - .clone() - .lazy() - .select(&[expression]) - .collect() - .map_err(|err| ShellError::GenericError { - error: "Error creating index column".into(), - msg: err.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let value = NuDataFrame::dataframe_into_value(res, call.head); - Ok(PipelineData::Value(value, None)) - } - _ => Err(ShellError::UnsupportedInput { - msg: "Expected the dataframe to have a column".to_string(), - input: "".to_string(), - msg_span: call.head, - input_span: call.head, - }), - } -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(ArgTrue {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/indexes/arg_unique.rs b/crates/nu-cmd-dataframe/src/dataframe/series/indexes/arg_unique.rs deleted file mode 100644 index 6b69518cba..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/indexes/arg_unique.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::IntoSeries; - -#[derive(Clone)] -pub struct ArgUnique; - -impl Command for ArgUnique { - fn name(&self) -> &str { - "dfr arg-unique" - } - - fn usage(&self) -> &str { - "Returns indexes for unique values." - } - - fn search_terms(&self) -> Vec<&str> { - vec!["argunique", "distinct", "noduplicate", "unrepeated"] - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Returns indexes for unique values", - example: "[1 2 2 3 3] | dfr into-df | dfr arg-unique", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "arg_unique".to_string(), - vec![Value::test_int(0), Value::test_int(1), Value::test_int(3)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let mut res = df - .as_series(call.head)? - .arg_unique() - .map_err(|e| ShellError::GenericError { - error: "Error extracting unique values".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })? - .into_series(); - res.rename("arg_unique"); - - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(ArgUnique {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/indexes/mod.rs b/crates/nu-cmd-dataframe/src/dataframe/series/indexes/mod.rs deleted file mode 100644 index c0af8c8653..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/indexes/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod arg_sort; -mod arg_true; -mod arg_unique; -mod set_with_idx; - -pub use arg_sort::ArgSort; -pub use arg_true::ArgTrue; -pub use arg_unique::ArgUnique; -pub use set_with_idx::SetWithIndex; diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/indexes/set_with_idx.rs b/crates/nu-cmd-dataframe/src/dataframe/series/indexes/set_with_idx.rs deleted file mode 100644 index 307ef4d5c3..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/indexes/set_with_idx.rs +++ /dev/null @@ -1,213 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -use polars::prelude::{ChunkSet, DataType, IntoSeries}; - -#[derive(Clone)] -pub struct SetWithIndex; - -impl Command for SetWithIndex { - fn name(&self) -> &str { - "dfr set-with-idx" - } - - fn usage(&self) -> &str { - "Sets value in the given index." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("value", SyntaxShape::Any, "value to be inserted in series") - .required_named( - "indices", - SyntaxShape::Any, - "list of indices indicating where to set the value", - Some('i'), - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Set value in selected rows from series", - example: r#"let series = ([4 1 5 2 4 3] | dfr into-df); - let indices = ([0 2] | dfr into-df); - $series | dfr set-with-idx 6 --indices $indices"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![ - Value::test_int(6), - Value::test_int(1), - Value::test_int(6), - Value::test_int(2), - Value::test_int(4), - Value::test_int(3), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let value: Value = call.req(engine_state, stack, 0)?; - - let indices_value: Value = call - .get_flag(engine_state, stack, "indices")? - .expect("required named value"); - let indices_span = indices_value.span(); - let indices = NuDataFrame::try_from_value(indices_value)?.as_series(indices_span)?; - - let casted = match indices.dtype() { - DataType::UInt32 | DataType::UInt64 | DataType::Int32 | DataType::Int64 => indices - .as_ref() - .cast(&DataType::UInt32) - .map_err(|e| ShellError::GenericError { - error: "Error casting indices".into(), - msg: e.to_string(), - span: Some(indices_span), - help: None, - inner: vec![], - }), - _ => Err(ShellError::GenericError { - error: "Incorrect type".into(), - msg: "Series with incorrect type".into(), - span: Some(indices_span), - help: Some("Consider using a Series with type int type".into()), - inner: vec![], - }), - }?; - - let indices = casted - .u32() - .map_err(|e| ShellError::GenericError { - error: "Error casting indices".into(), - msg: e.to_string(), - span: Some(indices_span), - help: None, - inner: vec![], - })? - .into_iter() - .flatten(); - - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let span = value.span(); - let res = match value { - Value::Int { val, .. } => { - let chunked = series.i64().map_err(|e| ShellError::GenericError { - error: "Error casting to i64".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - })?; - - let res = chunked.scatter_single(indices, Some(val)).map_err(|e| { - ShellError::GenericError { - error: "Error setting value".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - } - })?; - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - } - Value::Float { val, .. } => { - let chunked = series.f64().map_err(|e| ShellError::GenericError { - error: "Error casting to f64".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - })?; - - let res = chunked.scatter_single(indices, Some(val)).map_err(|e| { - ShellError::GenericError { - error: "Error setting value".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - } - })?; - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - } - Value::String { val, .. } => { - let chunked = series.str().map_err(|e| ShellError::GenericError { - error: "Error casting to string".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - })?; - - let res = chunked - .scatter_single(indices, Some(val.as_ref())) - .map_err(|e| ShellError::GenericError { - error: "Error setting value".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - })?; - - let mut res = res.into_series(); - res.rename("string"); - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - } - _ => Err(ShellError::GenericError { - error: "Incorrect value type".into(), - msg: format!( - "this value cannot be set in a series of type '{}'", - series.dtype() - ), - span: Some(span), - help: None, - inner: vec![], - }), - }; - - res.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(SetWithIndex {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/masks/is_duplicated.rs b/crates/nu-cmd-dataframe/src/dataframe/series/masks/is_duplicated.rs deleted file mode 100644 index b28f977b47..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/masks/is_duplicated.rs +++ /dev/null @@ -1,122 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::IntoSeries; - -#[derive(Clone)] -pub struct IsDuplicated; - -impl Command for IsDuplicated { - fn name(&self) -> &str { - "dfr is-duplicated" - } - - fn usage(&self) -> &str { - "Creates mask indicating duplicated values." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Create mask indicating duplicated values", - example: "[5 6 6 6 8 8 8] | dfr into-df | dfr is-duplicated", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "is_duplicated".to_string(), - vec![ - Value::test_bool(false), - Value::test_bool(true), - Value::test_bool(true), - Value::test_bool(true), - Value::test_bool(true), - Value::test_bool(true), - Value::test_bool(true), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Create mask indicating duplicated rows in a dataframe", - example: - "[[a, b]; [1 2] [1 2] [3 3] [3 3] [1 1]] | dfr into-df | dfr is-duplicated", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "is_duplicated".to_string(), - vec![ - Value::test_bool(true), - Value::test_bool(true), - Value::test_bool(true), - Value::test_bool(true), - Value::test_bool(false), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let mut res = df - .as_ref() - .is_duplicated() - .map_err(|e| ShellError::GenericError { - error: "Error finding duplicates".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })? - .into_series(); - - res.rename("is_duplicated"); - - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(IsDuplicated {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/masks/is_in.rs b/crates/nu-cmd-dataframe/src/dataframe/series/masks/is_in.rs deleted file mode 100644 index 0792d3fddf..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/masks/is_in.rs +++ /dev/null @@ -1,104 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -use polars::prelude::{is_in, IntoSeries}; - -#[derive(Clone)] -pub struct IsIn; - -impl Command for IsIn { - fn name(&self) -> &str { - "dfr is-in" - } - - fn usage(&self) -> &str { - "Checks if elements from a series are contained in right series." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("other", SyntaxShape::Any, "right series") - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Checks if elements from a series are contained in right series", - example: r#"let other = ([1 3 6] | dfr into-df); - [5 6 6 6 8 8 8] | dfr into-df | dfr is-in $other"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "is_in".to_string(), - vec![ - Value::test_bool(false), - Value::test_bool(true), - Value::test_bool(true), - Value::test_bool(true), - Value::test_bool(false), - Value::test_bool(false), - Value::test_bool(false), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?.as_series(call.head)?; - - let other_value: Value = call.req(engine_state, stack, 0)?; - let other_span = other_value.span(); - let other_df = NuDataFrame::try_from_value(other_value)?; - let other = other_df.as_series(other_span)?; - - let mut res = is_in(&df, &other) - .map_err(|e| ShellError::GenericError { - error: "Error finding in other".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })? - .into_series(); - - res.rename("is_in"); - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(IsIn {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/masks/is_not_null.rs b/crates/nu-cmd-dataframe/src/dataframe/series/masks/is_not_null.rs deleted file mode 100644 index 4ed33ce951..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/masks/is_not_null.rs +++ /dev/null @@ -1,122 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression}; -use nu_engine::command_prelude::*; -use polars::prelude::IntoSeries; - -#[derive(Clone)] -pub struct IsNotNull; - -impl Command for IsNotNull { - fn name(&self) -> &str { - "dfr is-not-null" - } - - fn usage(&self) -> &str { - "Creates mask where value is not null." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_types(vec![ - ( - Type::Custom("expression".into()), - Type::Custom("expression".into()), - ), - ( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ), - ]) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Create mask where values are not null", - example: r#"let s = ([5 6 0 8] | dfr into-df); - let res = ($s / $s); - $res | dfr is-not-null"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "is_not_null".to_string(), - vec![ - Value::test_bool(true), - Value::test_bool(true), - Value::test_bool(false), - Value::test_bool(true), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Creates a is not null expression from a column", - example: "dfr col a | dfr is-not-null", - result: None, - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let value = input.into_value(call.head)?; - if NuDataFrame::can_downcast(&value) { - let df = NuDataFrame::try_from_value(value)?; - command(engine_state, stack, call, df) - } else { - let expr = NuExpression::try_from_value(value)?; - let expr: NuExpression = expr.into_polars().is_not_null().into(); - - Ok(PipelineData::Value( - NuExpression::into_value(expr, call.head), - None, - )) - } - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - df: NuDataFrame, -) -> Result { - let mut res = df.as_series(call.head)?.is_not_null(); - res.rename("is_not_null"); - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::*; - use crate::dataframe::lazy::aggregate::LazyAggregate; - use crate::dataframe::lazy::groupby::ToLazyGroupBy; - use crate::dataframe::test_dataframe::{build_test_engine_state, test_dataframe_example}; - - #[test] - fn test_examples_dataframe() { - let mut engine_state = build_test_engine_state(vec![Box::new(IsNotNull {})]); - test_dataframe_example(&mut engine_state, &IsNotNull.examples()[0]); - } - - #[test] - fn test_examples_expression() { - let mut engine_state = build_test_engine_state(vec![ - Box::new(IsNotNull {}), - Box::new(LazyAggregate {}), - Box::new(ToLazyGroupBy {}), - ]); - test_dataframe_example(&mut engine_state, &IsNotNull.examples()[1]); - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/masks/is_null.rs b/crates/nu-cmd-dataframe/src/dataframe/series/masks/is_null.rs deleted file mode 100644 index b99d48af66..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/masks/is_null.rs +++ /dev/null @@ -1,122 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression}; -use nu_engine::command_prelude::*; -use polars::prelude::IntoSeries; - -#[derive(Clone)] -pub struct IsNull; - -impl Command for IsNull { - fn name(&self) -> &str { - "dfr is-null" - } - - fn usage(&self) -> &str { - "Creates mask where value is null." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_types(vec![ - ( - Type::Custom("expression".into()), - Type::Custom("expression".into()), - ), - ( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ), - ]) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Create mask where values are null", - example: r#"let s = ([5 6 0 8] | dfr into-df); - let res = ($s / $s); - $res | dfr is-null"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "is_null".to_string(), - vec![ - Value::test_bool(false), - Value::test_bool(false), - Value::test_bool(true), - Value::test_bool(false), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Creates a is null expression from a column", - example: "dfr col a | dfr is-null", - result: None, - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let value = input.into_value(call.head)?; - if NuDataFrame::can_downcast(&value) { - let df = NuDataFrame::try_from_value(value)?; - command(engine_state, stack, call, df) - } else { - let expr = NuExpression::try_from_value(value)?; - let expr: NuExpression = expr.into_polars().is_null().into(); - - Ok(PipelineData::Value( - NuExpression::into_value(expr, call.head), - None, - )) - } - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - df: NuDataFrame, -) -> Result { - let mut res = df.as_series(call.head)?.is_null(); - res.rename("is_null"); - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::*; - use crate::dataframe::lazy::aggregate::LazyAggregate; - use crate::dataframe::lazy::groupby::ToLazyGroupBy; - use crate::dataframe::test_dataframe::{build_test_engine_state, test_dataframe_example}; - - #[test] - fn test_examples_dataframe() { - let mut engine_state = build_test_engine_state(vec![Box::new(IsNull {})]); - test_dataframe_example(&mut engine_state, &IsNull.examples()[0]); - } - - #[test] - fn test_examples_expression() { - let mut engine_state = build_test_engine_state(vec![ - Box::new(IsNull {}), - Box::new(LazyAggregate {}), - Box::new(ToLazyGroupBy {}), - ]); - test_dataframe_example(&mut engine_state, &IsNull.examples()[1]); - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/masks/is_unique.rs b/crates/nu-cmd-dataframe/src/dataframe/series/masks/is_unique.rs deleted file mode 100644 index 8e313abca7..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/masks/is_unique.rs +++ /dev/null @@ -1,121 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::IntoSeries; - -#[derive(Clone)] -pub struct IsUnique; - -impl Command for IsUnique { - fn name(&self) -> &str { - "dfr is-unique" - } - - fn usage(&self) -> &str { - "Creates mask indicating unique values." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Create mask indicating unique values", - example: "[5 6 6 6 8 8 8] | dfr into-df | dfr is-unique", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "is_unique".to_string(), - vec![ - Value::test_bool(true), - Value::test_bool(false), - Value::test_bool(false), - Value::test_bool(false), - Value::test_bool(false), - Value::test_bool(false), - Value::test_bool(false), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Create mask indicating duplicated rows in a dataframe", - example: "[[a, b]; [1 2] [1 2] [3 3] [3 3] [1 1]] | dfr into-df | dfr is-unique", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "is_unique".to_string(), - vec![ - Value::test_bool(false), - Value::test_bool(false), - Value::test_bool(false), - Value::test_bool(false), - Value::test_bool(true), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let mut res = df - .as_ref() - .is_unique() - .map_err(|e| ShellError::GenericError { - error: "Error finding unique values".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })? - .into_series(); - - res.rename("is_unique"); - - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(IsUnique {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/masks/mod.rs b/crates/nu-cmd-dataframe/src/dataframe/series/masks/mod.rs deleted file mode 100644 index 80c98b5ef0..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/masks/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -mod is_duplicated; -mod is_in; -mod is_not_null; -mod is_null; -mod is_unique; -mod not; -mod set; - -pub use is_duplicated::IsDuplicated; -pub use is_in::IsIn; -pub use is_not_null::IsNotNull; -pub use is_null::IsNull; -pub use is_unique::IsUnique; -pub use not::NotSeries; -pub use set::SetSeries; diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/masks/not.rs b/crates/nu-cmd-dataframe/src/dataframe/series/masks/not.rs deleted file mode 100644 index 081a3c3b23..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/masks/not.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::IntoSeries; - -use std::ops::Not; - -#[derive(Clone)] -pub struct NotSeries; - -impl Command for NotSeries { - fn name(&self) -> &str { - "dfr not" - } - - fn usage(&self) -> &str { - "Inverts boolean mask." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Inverts boolean mask", - example: "[true false true] | dfr into-df | dfr not", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![ - Value::test_bool(false), - Value::test_bool(true), - Value::test_bool(false), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - command(engine_state, stack, call, df) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - df: NuDataFrame, -) -> Result { - let series = df.as_series(call.head)?; - - let bool = series.bool().map_err(|e| ShellError::GenericError { - error: "Error inverting mask".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let res = bool.not(); - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(NotSeries {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/masks/set.rs b/crates/nu-cmd-dataframe/src/dataframe/series/masks/set.rs deleted file mode 100644 index 4dacb7117b..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/masks/set.rs +++ /dev/null @@ -1,201 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -use polars::prelude::{ChunkSet, DataType, IntoSeries}; - -#[derive(Clone)] -pub struct SetSeries; - -impl Command for SetSeries { - fn name(&self) -> &str { - "dfr set" - } - - fn usage(&self) -> &str { - "Sets value where given mask is true." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("value", SyntaxShape::Any, "value to be inserted in series") - .required_named( - "mask", - SyntaxShape::Any, - "mask indicating insertions", - Some('m'), - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Shifts the values by a given period", - example: r#"let s = ([1 2 2 3 3] | dfr into-df | dfr shift 2); - let mask = ($s | dfr is-null); - $s | dfr set 0 --mask $mask"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![ - Value::test_int(0), - Value::test_int(0), - Value::test_int(1), - Value::test_int(2), - Value::test_int(2), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let value: Value = call.req(engine_state, stack, 0)?; - - let mask_value: Value = call - .get_flag(engine_state, stack, "mask")? - .expect("required named value"); - let mask_span = mask_value.span(); - let mask = NuDataFrame::try_from_value(mask_value)?.as_series(mask_span)?; - - let bool_mask = match mask.dtype() { - DataType::Boolean => mask.bool().map_err(|e| ShellError::GenericError { - error: "Error casting to bool".into(), - msg: e.to_string(), - span: Some(mask_span), - help: None, - inner: vec![], - }), - _ => Err(ShellError::GenericError { - error: "Incorrect type".into(), - msg: "can only use bool series as mask".into(), - span: Some(mask_span), - help: None, - inner: vec![], - }), - }?; - - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - let span = value.span(); - let res = match value { - Value::Int { val, .. } => { - let chunked = series.i64().map_err(|e| ShellError::GenericError { - error: "Error casting to i64".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - })?; - - let res = chunked - .set(bool_mask, Some(val)) - .map_err(|e| ShellError::GenericError { - error: "Error setting value".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - })?; - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - } - Value::Float { val, .. } => { - let chunked = series.f64().map_err(|e| ShellError::GenericError { - error: "Error casting to f64".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - })?; - - let res = chunked - .set(bool_mask, Some(val)) - .map_err(|e| ShellError::GenericError { - error: "Error setting value".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - })?; - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - } - Value::String { val, .. } => { - let chunked = series.str().map_err(|e| ShellError::GenericError { - error: "Error casting to string".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - })?; - - let res = chunked.set(bool_mask, Some(val.as_ref())).map_err(|e| { - ShellError::GenericError { - error: "Error setting value".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - } - })?; - - let mut res = res.into_series(); - res.rename("string"); - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - } - _ => Err(ShellError::GenericError { - error: "Incorrect value type".into(), - msg: format!( - "this value cannot be set in a series of type '{}'", - series.dtype() - ), - span: Some(span), - help: None, - inner: vec![], - }), - }; - - res.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::super::super::{IsNull, Shift}; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![ - Box::new(SetSeries {}), - Box::new(IsNull {}), - Box::new(Shift {}), - ]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/mod.rs b/crates/nu-cmd-dataframe/src/dataframe/series/mod.rs deleted file mode 100644 index e1b9bc1087..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/mod.rs +++ /dev/null @@ -1,95 +0,0 @@ -mod date; -pub use date::*; - -mod string; -pub use string::*; - -mod masks; -pub use masks::*; - -mod indexes; -pub use indexes::*; - -mod all_false; -mod all_true; -mod arg_max; -mod arg_min; -mod cumulative; -mod n_null; -mod n_unique; -mod rolling; -mod shift; -mod unique; -mod value_counts; - -use nu_protocol::engine::StateWorkingSet; - -pub use all_false::AllFalse; -pub use all_true::AllTrue; -pub use arg_max::ArgMax; -pub use arg_min::ArgMin; -pub use cumulative::Cumulative; -pub use n_null::NNull; -pub use n_unique::NUnique; -pub use rolling::Rolling; -pub use shift::Shift; -pub use unique::Unique; -pub use value_counts::ValueCount; - -pub fn add_series_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!( - AllFalse, - AllTrue, - ArgMax, - ArgMin, - ArgSort, - ArgTrue, - ArgUnique, - AsDate, - AsDateTime, - Concatenate, - Contains, - Cumulative, - GetDay, - GetHour, - GetMinute, - GetMonth, - GetNanosecond, - GetOrdinal, - GetSecond, - GetWeek, - GetWeekDay, - GetYear, - IsDuplicated, - IsIn, - IsNotNull, - IsNull, - IsUnique, - NNull, - NUnique, - NotSeries, - Replace, - ReplaceAll, - Rolling, - SetSeries, - SetWithIndex, - Shift, - StrLengths, - StrSlice, - StrFTime, - ToLowerCase, - ToUpperCase, - Unique, - ValueCount - ); -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/n_null.rs b/crates/nu-cmd-dataframe/src/dataframe/series/n_null.rs deleted file mode 100644 index 6c9909da07..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/n_null.rs +++ /dev/null @@ -1,82 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct NNull; - -impl Command for NNull { - fn name(&self) -> &str { - "dfr count-null" - } - - fn usage(&self) -> &str { - "Counts null values." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Counts null values", - example: r#"let s = ([1 1 0 0 3 3 4] | dfr into-df); - ($s / $s) | dfr count-null"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "count_null".to_string(), - vec![Value::test_int(2)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let res = df.as_series(call.head)?.null_count(); - let value = Value::int(res as i64, call.head); - - NuDataFrame::try_from_columns( - vec![Column::new("count_null".to_string(), vec![value])], - None, - ) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(NNull {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/n_unique.rs b/crates/nu-cmd-dataframe/src/dataframe/series/n_unique.rs deleted file mode 100644 index c6d6e829f8..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/n_unique.rs +++ /dev/null @@ -1,127 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression}; -use nu_engine::command_prelude::*; - -#[derive(Clone)] -pub struct NUnique; - -impl Command for NUnique { - fn name(&self) -> &str { - "dfr n-unique" - } - - fn usage(&self) -> &str { - "Counts unique values." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_types(vec![ - ( - Type::Custom("expression".into()), - Type::Custom("expression".into()), - ), - ( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ), - ]) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Counts unique values", - example: "[1 1 2 2 3 3 4] | dfr into-df | dfr n-unique", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "count_unique".to_string(), - vec![Value::test_int(4)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Creates a is n-unique expression from a column", - example: "dfr col a | dfr n-unique", - result: None, - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let value = input.into_value(call.head)?; - if NuDataFrame::can_downcast(&value) { - let df = NuDataFrame::try_from_value(value)?; - command(engine_state, stack, call, df) - } else { - let expr = NuExpression::try_from_value(value)?; - let expr: NuExpression = expr.into_polars().n_unique().into(); - - Ok(PipelineData::Value( - NuExpression::into_value(expr, call.head), - None, - )) - } - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - df: NuDataFrame, -) -> Result { - let res = df - .as_series(call.head)? - .n_unique() - .map_err(|e| ShellError::GenericError { - error: "Error counting unique values".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let value = Value::int(res as i64, call.head); - - NuDataFrame::try_from_columns( - vec![Column::new("count_unique".to_string(), vec![value])], - None, - ) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::{build_test_engine_state, test_dataframe_example}; - use super::*; - use crate::dataframe::lazy::aggregate::LazyAggregate; - use crate::dataframe::lazy::groupby::ToLazyGroupBy; - - #[test] - fn test_examples_dataframe() { - let mut engine_state = build_test_engine_state(vec![Box::new(NUnique {})]); - test_dataframe_example(&mut engine_state, &NUnique.examples()[0]); - } - - #[test] - fn test_examples_expression() { - let mut engine_state = build_test_engine_state(vec![ - Box::new(NUnique {}), - Box::new(LazyAggregate {}), - Box::new(ToLazyGroupBy {}), - ]); - test_dataframe_example(&mut engine_state, &NUnique.examples()[1]); - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/rolling.rs b/crates/nu-cmd-dataframe/src/dataframe/series/rolling.rs deleted file mode 100644 index b659462298..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/rolling.rs +++ /dev/null @@ -1,186 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -use polars::prelude::{DataType, Duration, IntoSeries, RollingOptionsImpl, SeriesOpsTime}; - -enum RollType { - Min, - Max, - Sum, - Mean, -} - -impl RollType { - fn from_str(roll_type: &str, span: Span) -> Result { - match roll_type { - "min" => Ok(Self::Min), - "max" => Ok(Self::Max), - "sum" => Ok(Self::Sum), - "mean" => Ok(Self::Mean), - _ => Err(ShellError::GenericError { - error: "Wrong operation".into(), - msg: "Operation not valid for cumulative".into(), - span: Some(span), - help: Some("Allowed values: min, max, sum, mean".into()), - inner: vec![], - }), - } - } - - fn to_str(&self) -> &'static str { - match self { - RollType::Min => "rolling_min", - RollType::Max => "rolling_max", - RollType::Sum => "rolling_sum", - RollType::Mean => "rolling_mean", - } - } -} - -#[derive(Clone)] -pub struct Rolling; - -impl Command for Rolling { - fn name(&self) -> &str { - "dfr rolling" - } - - fn usage(&self) -> &str { - "Rolling calculation for a series." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("type", SyntaxShape::String, "rolling operation") - .required("window", SyntaxShape::Int, "Window size for rolling") - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Rolling sum for a series", - example: "[1 2 3 4 5] | dfr into-df | dfr rolling sum 2 | dfr drop-nulls", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0_rolling_sum".to_string(), - vec![ - Value::test_int(3), - Value::test_int(5), - Value::test_int(7), - Value::test_int(9), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Rolling max for a series", - example: "[1 2 3 4 5] | dfr into-df | dfr rolling max 2 | dfr drop-nulls", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0_rolling_max".to_string(), - vec![ - Value::test_int(2), - Value::test_int(3), - Value::test_int(4), - Value::test_int(5), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let roll_type: Spanned = call.req(engine_state, stack, 0)?; - let window_size: i64 = call.req(engine_state, stack, 1)?; - - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - if let DataType::Object(..) = series.dtype() { - return Err(ShellError::GenericError { - error: "Found object series".into(), - msg: "Series of type object cannot be used for rolling operation".into(), - span: Some(call.head), - help: None, - inner: vec![], - }); - } - - let roll_type = RollType::from_str(&roll_type.item, roll_type.span)?; - - let rolling_opts = RollingOptionsImpl { - window_size: Duration::new(window_size), - min_periods: window_size as usize, - weights: None, - center: false, - by: None, - closed_window: None, - tu: None, - tz: None, - fn_params: None, - }; - let res = match roll_type { - RollType::Max => series.rolling_max(rolling_opts), - RollType::Min => series.rolling_min(rolling_opts), - RollType::Sum => series.rolling_sum(rolling_opts), - RollType::Mean => series.rolling_mean(rolling_opts), - }; - - let mut res = res.map_err(|e| ShellError::GenericError { - error: "Error calculating rolling values".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let name = format!("{}_{}", series.name(), roll_type.to_str()); - res.rename(&name); - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::eager::DropNulls; - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(Rolling {}), Box::new(DropNulls {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/shift.rs b/crates/nu-cmd-dataframe/src/dataframe/series/shift.rs deleted file mode 100644 index 2f40cf0a45..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/shift.rs +++ /dev/null @@ -1,115 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame, NuExpression, NuLazyFrame}; -use nu_engine::command_prelude::*; - -use polars_plan::prelude::lit; - -#[derive(Clone)] -pub struct Shift; - -impl Command for Shift { - fn name(&self) -> &str { - "dfr shift" - } - - fn usage(&self) -> &str { - "Shifts the values by a given period." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("period", SyntaxShape::Int, "shift period") - .named( - "fill", - SyntaxShape::Any, - "Expression used to fill the null values (lazy df)", - Some('f'), - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe or lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Shifts the values by a given period", - example: "[1 2 2 3 3] | dfr into-df | dfr shift 2 | dfr drop-nulls", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![Value::test_int(1), Value::test_int(2), Value::test_int(2)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let value = input.into_value(call.head)?; - if NuLazyFrame::can_downcast(&value) { - let df = NuLazyFrame::try_from_value(value)?; - command_lazy(engine_state, stack, call, df) - } else { - let df = NuDataFrame::try_from_value(value)?; - command_eager(engine_state, stack, call, df) - } - } -} - -fn command_eager( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - df: NuDataFrame, -) -> Result { - let period: i64 = call.req(engine_state, stack, 0)?; - let series = df.as_series(call.head)?.shift(period); - - NuDataFrame::try_from_series(vec![series], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -fn command_lazy( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - lazy: NuLazyFrame, -) -> Result { - let shift: i64 = call.req(engine_state, stack, 0)?; - let fill: Option = call.get_flag(engine_state, stack, "fill")?; - - let lazy = lazy.into_polars(); - - let lazy: NuLazyFrame = match fill { - Some(fill) => { - let expr = NuExpression::try_from_value(fill)?.into_polars(); - lazy.shift_and_fill(lit(shift), expr).into() - } - None => lazy.shift(shift).into(), - }; - - Ok(PipelineData::Value(lazy.into_value(call.head)?, None)) -} - -#[cfg(test)] -mod test { - use super::super::super::eager::DropNulls; - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(Shift {}), Box::new(DropNulls {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/string/concatenate.rs b/crates/nu-cmd-dataframe/src/dataframe/series/string/concatenate.rs deleted file mode 100644 index d7589bd3b1..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/string/concatenate.rs +++ /dev/null @@ -1,113 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -use polars::prelude::{IntoSeries, StringNameSpaceImpl}; - -#[derive(Clone)] -pub struct Concatenate; - -impl Command for Concatenate { - fn name(&self) -> &str { - "dfr concatenate" - } - - fn usage(&self) -> &str { - "Concatenates strings with other array." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "other", - SyntaxShape::Any, - "Other array with string to be concatenated", - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Concatenate string", - example: r#"let other = ([za xs cd] | dfr into-df); - [abc abc abc] | dfr into-df | dfr concatenate $other"#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![ - Value::test_string("abcza"), - Value::test_string("abcxs"), - Value::test_string("abccd"), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - - let other: Value = call.req(engine_state, stack, 0)?; - let other_span = other.span(); - let other_df = NuDataFrame::try_from_value(other)?; - - let other_series = other_df.as_series(other_span)?; - let other_chunked = other_series.str().map_err(|e| ShellError::GenericError { - error: "The concatenate only with string columns".into(), - msg: e.to_string(), - span: Some(other_span), - help: None, - inner: vec![], - })?; - - let series = df.as_series(call.head)?; - let chunked = series.str().map_err(|e| ShellError::GenericError { - error: "The concatenate only with string columns".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let mut res = chunked.concat(other_chunked); - - res.rename(series.name()); - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(Concatenate {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/string/contains.rs b/crates/nu-cmd-dataframe/src/dataframe/series/string/contains.rs deleted file mode 100644 index 9c1d92681e..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/string/contains.rs +++ /dev/null @@ -1,106 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -use polars::prelude::{IntoSeries, StringNameSpaceImpl}; - -#[derive(Clone)] -pub struct Contains; - -impl Command for Contains { - fn name(&self) -> &str { - "dfr contains" - } - - fn usage(&self) -> &str { - "Checks if a pattern is contained in a string." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required( - "pattern", - SyntaxShape::String, - "Regex pattern to be searched", - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Returns boolean indicating if pattern was found", - example: "[abc acb acb] | dfr into-df | dfr contains ab", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![ - Value::test_bool(true), - Value::test_bool(false), - Value::test_bool(false), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let pattern: String = call.req(engine_state, stack, 0)?; - - let series = df.as_series(call.head)?; - let chunked = series.str().map_err(|e| ShellError::GenericError { - error: "The contains command only with string columns".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let res = chunked - .contains(&pattern, false) - .map_err(|e| ShellError::GenericError { - error: "Error searching in series".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(Contains {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/string/mod.rs b/crates/nu-cmd-dataframe/src/dataframe/series/string/mod.rs deleted file mode 100644 index f2fa19cbaf..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/string/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -mod concatenate; -mod contains; -mod replace; -mod replace_all; -mod str_lengths; -mod str_slice; -mod strftime; -mod to_lowercase; -mod to_uppercase; - -pub use concatenate::Concatenate; -pub use contains::Contains; -pub use replace::Replace; -pub use replace_all::ReplaceAll; -pub use str_lengths::StrLengths; -pub use str_slice::StrSlice; -pub use strftime::StrFTime; -pub use to_lowercase::ToLowerCase; -pub use to_uppercase::ToUpperCase; diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/string/replace.rs b/crates/nu-cmd-dataframe/src/dataframe/series/string/replace.rs deleted file mode 100644 index d954e20b66..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/string/replace.rs +++ /dev/null @@ -1,120 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -use polars::prelude::{IntoSeries, StringNameSpaceImpl}; - -#[derive(Clone)] -pub struct Replace; - -impl Command for Replace { - fn name(&self) -> &str { - "dfr replace" - } - - fn usage(&self) -> &str { - "Replace the leftmost (sub)string by a regex pattern." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required_named( - "pattern", - SyntaxShape::String, - "Regex pattern to be matched", - Some('p'), - ) - .required_named( - "replace", - SyntaxShape::String, - "replacing string", - Some('r'), - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Replaces string", - example: "[abc abc abc] | dfr into-df | dfr replace --pattern ab --replace AB", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![ - Value::test_string("ABc"), - Value::test_string("ABc"), - Value::test_string("ABc"), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let pattern: String = call - .get_flag(engine_state, stack, "pattern")? - .expect("required value"); - let replace: String = call - .get_flag(engine_state, stack, "replace")? - .expect("required value"); - - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - let chunked = series.str().map_err(|e| ShellError::GenericError { - error: "Error conversion to string".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let mut res = chunked - .replace(&pattern, &replace) - .map_err(|e| ShellError::GenericError { - error: "Error finding pattern other".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - res.rename(series.name()); - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(Replace {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/string/replace_all.rs b/crates/nu-cmd-dataframe/src/dataframe/series/string/replace_all.rs deleted file mode 100644 index f329cbca73..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/string/replace_all.rs +++ /dev/null @@ -1,121 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -use polars::prelude::{IntoSeries, StringNameSpaceImpl}; - -#[derive(Clone)] -pub struct ReplaceAll; - -impl Command for ReplaceAll { - fn name(&self) -> &str { - "dfr replace-all" - } - - fn usage(&self) -> &str { - "Replace all (sub)strings by a regex pattern." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required_named( - "pattern", - SyntaxShape::String, - "Regex pattern to be matched", - Some('p'), - ) - .required_named( - "replace", - SyntaxShape::String, - "replacing string", - Some('r'), - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Replaces string", - example: "[abac abac abac] | dfr into-df | dfr replace-all --pattern a --replace A", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![ - Value::test_string("AbAc"), - Value::test_string("AbAc"), - Value::test_string("AbAc"), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let pattern: String = call - .get_flag(engine_state, stack, "pattern")? - .expect("required value"); - let replace: String = call - .get_flag(engine_state, stack, "replace")? - .expect("required value"); - - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - let chunked = series.str().map_err(|e| ShellError::GenericError { - error: "Error conversion to string".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - let mut res = - chunked - .replace_all(&pattern, &replace) - .map_err(|e| ShellError::GenericError { - error: "Error finding pattern other".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })?; - - res.rename(series.name()); - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(ReplaceAll {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/string/str_lengths.rs b/crates/nu-cmd-dataframe/src/dataframe/series/string/str_lengths.rs deleted file mode 100644 index 6889cef387..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/string/str_lengths.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::{IntoSeries, StringNameSpaceImpl}; - -#[derive(Clone)] -pub struct StrLengths; - -impl Command for StrLengths { - fn name(&self) -> &str { - "dfr str-lengths" - } - - fn usage(&self) -> &str { - "Get lengths of all strings." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Returns string lengths", - example: "[a ab abc] | dfr into-df | dfr str-lengths", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![Value::test_int(1), Value::test_int(2), Value::test_int(3)], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let chunked = series.str().map_err(|e| ShellError::GenericError { - error: "Error casting to string".into(), - msg: e.to_string(), - span: Some(call.head), - help: Some("The str-lengths command can only be used with string columns".into()), - inner: vec![], - })?; - - let res = chunked.as_ref().str_len_bytes().into_series(); - - NuDataFrame::try_from_series(vec![res], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(StrLengths {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/string/str_slice.rs b/crates/nu-cmd-dataframe/src/dataframe/series/string/str_slice.rs deleted file mode 100644 index 6a5c8364c2..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/string/str_slice.rs +++ /dev/null @@ -1,136 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -use polars::{ - prelude::{IntoSeries, NamedFrom, StringNameSpaceImpl}, - series::Series, -}; - -#[derive(Clone)] -pub struct StrSlice; - -impl Command for StrSlice { - fn name(&self) -> &str { - "dfr str-slice" - } - - fn usage(&self) -> &str { - "Slices the string from the start position until the selected length." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("start", SyntaxShape::Int, "start of slice") - .named("length", SyntaxShape::Int, "optional length", Some('l')) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Creates slices from the strings", - example: "[abcded abc321 abc123] | dfr into-df | dfr str-slice 1 --length 2", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![ - Value::test_string("bc"), - Value::test_string("bc"), - Value::test_string("bc"), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Creates slices from the strings without length", - example: "[abcded abc321 abc123] | dfr into-df | dfr str-slice 1", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![ - Value::test_string("bcded"), - Value::test_string("bc321"), - Value::test_string("bc123"), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let start: i64 = call.req(engine_state, stack, 0)?; - let start = Series::new("", &[start]); - - let length: Option = call.get_flag(engine_state, stack, "length")?; - let length = match length { - Some(v) => Series::new("", &[v as u64]), - None => Series::new_null("", 1), - }; - - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let chunked = series.str().map_err(|e| ShellError::GenericError { - error: "Error casting to string".into(), - msg: e.to_string(), - span: Some(call.head), - help: Some("The str-slice command can only be used with string columns".into()), - inner: vec![], - })?; - - let res = chunked - .str_slice(&start, &length) - .map_err(|e| ShellError::GenericError { - error: "Dataframe Error".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })? - .with_name(series.name()); - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(StrSlice {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/string/strftime.rs b/crates/nu-cmd-dataframe/src/dataframe/series/string/strftime.rs deleted file mode 100644 index 3cdfa84f8e..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/string/strftime.rs +++ /dev/null @@ -1,105 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; - -use polars::prelude::IntoSeries; - -#[derive(Clone)] -pub struct StrFTime; - -impl Command for StrFTime { - fn name(&self) -> &str { - "dfr strftime" - } - - fn usage(&self) -> &str { - "Formats date based on string rule." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("fmt", SyntaxShape::String, "Format rule") - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Formats date", - example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime --timezone 'UTC'); - let df = ([$dt $dt] | dfr into-df); - $df | dfr strftime "%Y/%m/%d""#, - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![ - Value::test_string("2020/08/04"), - Value::test_string("2020/08/04"), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let fmt: String = call.req(engine_state, stack, 0)?; - - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let casted = series.datetime().map_err(|e| ShellError::GenericError { - error: "Error casting to date".into(), - msg: e.to_string(), - span: Some(call.head), - help: Some("The str-slice command can only be used with string columns".into()), - inner: vec![], - })?; - - let res = casted - .strftime(&fmt) - .map_err(|e| ShellError::GenericError { - error: "Error formatting datetime".into(), - msg: e.to_string(), - span: Some(call.head), - help: None, - inner: vec![], - })? - .into_series(); - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(explore_refactor_IntoDatetime)] -mod test { - use super::super::super::super::super::IntoDatetime; - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(StrFTime {}), Box::new(IntoDatetime {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/string/to_lowercase.rs b/crates/nu-cmd-dataframe/src/dataframe/series/string/to_lowercase.rs deleted file mode 100644 index 2340437e35..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/string/to_lowercase.rs +++ /dev/null @@ -1,92 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::{IntoSeries, StringNameSpaceImpl}; - -#[derive(Clone)] -pub struct ToLowerCase; - -impl Command for ToLowerCase { - fn name(&self) -> &str { - "dfr lowercase" - } - - fn usage(&self) -> &str { - "Lowercase the strings in the column." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Modifies strings to lowercase", - example: "[Abc aBc abC] | dfr into-df | dfr lowercase", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![ - Value::test_string("abc"), - Value::test_string("abc"), - Value::test_string("abc"), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let casted = series.str().map_err(|e| ShellError::GenericError { - error: "Error casting to string".into(), - msg: e.to_string(), - span: Some(call.head), - help: Some("The str-slice command can only be used with string columns".into()), - inner: vec![], - })?; - - let mut res = casted.to_lowercase(); - res.rename(series.name()); - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(ToLowerCase {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/string/to_uppercase.rs b/crates/nu-cmd-dataframe/src/dataframe/series/string/to_uppercase.rs deleted file mode 100644 index 23378f5dc3..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/string/to_uppercase.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::{IntoSeries, StringNameSpaceImpl}; - -#[derive(Clone)] -pub struct ToUpperCase; - -impl Command for ToUpperCase { - fn name(&self) -> &str { - "dfr uppercase" - } - - fn usage(&self) -> &str { - "Uppercase the strings in the column." - } - - fn search_terms(&self) -> Vec<&str> { - vec!["capitalize, caps, capital"] - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Modifies strings to uppercase", - example: "[Abc aBc abC] | dfr into-df | dfr uppercase", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new( - "0".to_string(), - vec![ - Value::test_string("ABC"), - Value::test_string("ABC"), - Value::test_string("ABC"), - ], - )], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let casted = series.str().map_err(|e| ShellError::GenericError { - error: "Error casting to string".into(), - msg: e.to_string(), - span: Some(call.head), - help: Some("The str-slice command can only be used with string columns".into()), - inner: vec![], - })?; - - let mut res = casted.to_uppercase(); - res.rename(series.name()); - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -#[cfg(test)] -mod test { - use super::super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(ToUpperCase {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/unique.rs b/crates/nu-cmd-dataframe/src/dataframe/series/unique.rs deleted file mode 100644 index 1bc2e0dc1b..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/unique.rs +++ /dev/null @@ -1,146 +0,0 @@ -use crate::dataframe::{ - utils::extract_strings, - values::{Column, NuDataFrame, NuLazyFrame}, -}; -use nu_engine::command_prelude::*; - -use polars::prelude::{IntoSeries, UniqueKeepStrategy}; - -#[derive(Clone)] -pub struct Unique; - -impl Command for Unique { - fn name(&self) -> &str { - "dfr unique" - } - - fn usage(&self) -> &str { - "Returns unique values from a dataframe." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .named( - "subset", - SyntaxShape::Any, - "Subset of column(s) to use to maintain rows (lazy df)", - Some('s'), - ) - .switch( - "last", - "Keeps last unique value. Default keeps first value (lazy df)", - Some('l'), - ) - .switch( - "maintain-order", - "Keep the same order as the original DataFrame (lazy df)", - Some('k'), - ) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe or lazyframe".into())) - } - - fn examples(&self) -> Vec { - vec![ - Example { - description: "Returns unique values from a series", - example: "[2 2 2 2 2] | dfr into-df | dfr unique", - result: Some( - NuDataFrame::try_from_columns( - vec![Column::new("0".to_string(), vec![Value::test_int(2)])], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }, - Example { - description: "Creates a is unique expression from a column", - example: "col a | unique", - result: None, - }, - ] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - let value = input.into_value(call.head)?; - if NuLazyFrame::can_downcast(&value) { - let df = NuLazyFrame::try_from_value(value)?; - command_lazy(engine_state, stack, call, df) - } else { - let df = NuDataFrame::try_from_value(value)?; - command_eager(engine_state, stack, call, df) - } - } -} - -fn command_eager( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - df: NuDataFrame, -) -> Result { - let series = df.as_series(call.head)?; - - let res = series.unique().map_err(|e| ShellError::GenericError { - error: "Error calculating unique values".into(), - msg: e.to_string(), - span: Some(call.head), - help: Some("The str-slice command can only be used with string columns".into()), - inner: vec![], - })?; - - NuDataFrame::try_from_series(vec![res.into_series()], call.head) - .map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None)) -} - -fn command_lazy( - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - lazy: NuLazyFrame, -) -> Result { - let last = call.has_flag(engine_state, stack, "last")?; - let maintain = call.has_flag(engine_state, stack, "maintain-order")?; - - let subset: Option = call.get_flag(engine_state, stack, "subset")?; - let subset = match subset { - Some(value) => Some(extract_strings(value)?), - None => None, - }; - - let strategy = if last { - UniqueKeepStrategy::Last - } else { - UniqueKeepStrategy::First - }; - - let lazy = lazy.into_polars(); - let lazy: NuLazyFrame = if maintain { - lazy.unique(subset, strategy).into() - } else { - lazy.unique_stable(subset, strategy).into() - }; - - Ok(PipelineData::Value(lazy.into_value(call.head)?, None)) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(Unique {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/series/value_counts.rs b/crates/nu-cmd-dataframe/src/dataframe/series/value_counts.rs deleted file mode 100644 index 87d3b42b3a..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/series/value_counts.rs +++ /dev/null @@ -1,95 +0,0 @@ -use crate::dataframe::values::{Column, NuDataFrame}; -use nu_engine::command_prelude::*; -use polars::prelude::SeriesMethods; - -#[derive(Clone)] -pub struct ValueCount; - -impl Command for ValueCount { - fn name(&self) -> &str { - "dfr value-counts" - } - - fn usage(&self) -> &str { - "Returns a dataframe with the counts for unique values in series." - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .input_output_type( - Type::Custom("dataframe".into()), - Type::Custom("dataframe".into()), - ) - .category(Category::Custom("dataframe".into())) - } - - fn examples(&self) -> Vec { - vec![Example { - description: "Calculates value counts", - example: "[5 5 5 5 6 6] | dfr into-df | dfr value-counts", - result: Some( - NuDataFrame::try_from_columns( - vec![ - Column::new( - "0".to_string(), - vec![Value::test_int(5), Value::test_int(6)], - ), - Column::new( - "count".to_string(), - vec![Value::test_int(4), Value::test_int(2)], - ), - ], - None, - ) - .expect("simple df for test should not fail") - .into_value(Span::test_data()), - ), - }] - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - input: PipelineData, - ) -> Result { - command(engine_state, stack, call, input) - } -} - -fn command( - _engine_state: &EngineState, - _stack: &mut Stack, - call: &Call, - input: PipelineData, -) -> Result { - let df = NuDataFrame::try_from_pipeline(input, call.head)?; - let series = df.as_series(call.head)?; - - let res = series - .value_counts(false, false) - .map_err(|e| ShellError::GenericError { - error: "Error calculating value counts values".into(), - msg: e.to_string(), - span: Some(call.head), - help: Some("The str-slice command can only be used with string columns".into()), - inner: vec![], - })?; - - Ok(PipelineData::Value( - NuDataFrame::dataframe_into_value(res, call.head), - None, - )) -} - -#[cfg(test)] -mod test { - use super::super::super::test_dataframe::test_dataframe; - use super::*; - - #[test] - fn test_examples() { - test_dataframe(vec![Box::new(ValueCount {})]) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/stub.rs b/crates/nu-cmd-dataframe/src/dataframe/stub.rs deleted file mode 100644 index dfabbe0b82..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/stub.rs +++ /dev/null @@ -1,34 +0,0 @@ -use nu_engine::{command_prelude::*, get_full_help}; - -#[derive(Clone)] -pub struct Dfr; - -impl Command for Dfr { - fn name(&self) -> &str { - "dfr" - } - - fn usage(&self) -> &str { - "Operate with data in a dataframe format." - } - - fn signature(&self) -> nu_protocol::Signature { - Signature::build("dfr") - .category(Category::Custom("dataframe".into())) - .input_output_types(vec![(Type::Nothing, Type::String)]) - } - - fn extra_usage(&self) -> &str { - "You must use one of the following subcommands. Using this command as-is will only produce this help message." - } - - fn run( - &self, - engine_state: &EngineState, - stack: &mut Stack, - call: &Call, - _input: PipelineData, - ) -> Result { - Ok(Value::string(get_full_help(self, engine_state, stack), call.head).into_pipeline_data()) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/test_dataframe.rs b/crates/nu-cmd-dataframe/src/dataframe/test_dataframe.rs deleted file mode 100644 index 39c30be9dd..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/test_dataframe.rs +++ /dev/null @@ -1,98 +0,0 @@ -use super::{ - eager::{SchemaDF, ToDataFrame}, - expressions::ExprCol, - lazy::{LazyCollect, LazyFillNull, ToLazyFrame}, -}; -use nu_cmd_lang::Let; -use nu_engine::{command_prelude::*, eval_block}; -use nu_parser::parse; -use nu_protocol::{debugger::WithoutDebug, engine::StateWorkingSet}; - -pub fn test_dataframe(cmds: Vec>) { - 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 = build_test_engine_state(cmds.clone()); - - for example in examples { - test_dataframe_example(&mut engine_state, &example); - } -} - -pub fn build_test_engine_state(cmds: Vec>) -> Box { - 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(Let)); - working_set.add_decl(Box::new(ToDataFrame)); - working_set.add_decl(Box::new(ToLazyFrame)); - working_set.add_decl(Box::new(LazyCollect)); - working_set.add_decl(Box::new(ExprCol)); - working_set.add_decl(Box::new(SchemaDF)); - working_set.add_decl(Box::new(LazyFillNull)); - - // Adding the command that is being tested to the working set - for cmd in cmds.clone() { - working_set.add_decl(cmd); - } - - working_set.render() - }; - - engine_state - .merge_delta(delta) - .expect("Error merging delta"); - - engine_state -} - -pub fn test_dataframe_example(engine_state: &mut Box, example: &Example) { - // Skip tests that don't have results to compare to - if example.result.is_none() { - return; - } - - let start = std::time::Instant::now(); - - let (block, delta) = { - let mut working_set = StateWorkingSet::new(engine_state); - let output = parse(&mut working_set, None, example.example.as_bytes(), false); - - if let Some(err) = working_set.parse_errors.first() { - panic!("test parse error in `{}`: {:?}", example.example, err) - } - - (output, working_set.render()) - }; - - engine_state - .merge_delta(delta) - .expect("Error merging delta"); - - let mut stack = Stack::new().capture(); - - let result = - eval_block::(engine_state, &mut stack, &block, PipelineData::empty()) - .unwrap_or_else(|err| panic!("test eval error in `{}`: {:?}", example.example, err)) - .into_value(Span::test_data()) - .expect("ok value"); - - 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.clone() { - if result != expected { - panic!("the example result is different to expected value: {result:?} != {expected:?}") - } - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/utils.rs b/crates/nu-cmd-dataframe/src/dataframe/utils.rs deleted file mode 100644 index db99d550a9..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/utils.rs +++ /dev/null @@ -1,16 +0,0 @@ -use nu_protocol::{FromValue, ShellError, Value}; - -pub fn extract_strings(value: Value) -> Result, ShellError> { - let span = value.span(); - match ( - ::from_value(value.clone()), - as FromValue>::from_value(value), - ) { - (Ok(col), Err(_)) => Ok(vec![col]), - (Err(_), Ok(cols)) => Ok(cols), - _ => Err(ShellError::IncompatibleParametersSingle { - msg: "Expected a string or list of strings".into(), - span, - }), - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/mod.rs b/crates/nu-cmd-dataframe/src/dataframe/values/mod.rs deleted file mode 100644 index eaed15aa4b..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/values/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -mod nu_dataframe; -mod nu_expression; -mod nu_lazyframe; -mod nu_lazygroupby; -mod nu_schema; -mod nu_when; -pub mod utils; - -pub use nu_dataframe::{Axis, Column, NuDataFrame}; -pub use nu_expression::NuExpression; -pub use nu_lazyframe::NuLazyFrame; -pub use nu_lazygroupby::NuLazyGroupBy; -pub use nu_schema::{str_to_dtype, NuSchema}; -pub use nu_when::NuWhen; diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/between_values.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/between_values.rs deleted file mode 100644 index 74a484825a..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/between_values.rs +++ /dev/null @@ -1,884 +0,0 @@ -use super::{operations::Axis, NuDataFrame}; -use nu_protocol::{ - ast::{Boolean, Comparison, Math, Operator}, - ShellError, Span, Spanned, Value, -}; -use num::Zero; -use polars::prelude::{ - BooleanType, ChunkCompare, ChunkedArray, DataType, Float64Type, Int64Type, IntoSeries, - NumOpsDispatchChecked, PolarsError, Series, StringNameSpaceImpl, -}; -use std::ops::{Add, BitAnd, BitOr, Div, Mul, Sub}; - -pub(super) fn between_dataframes( - operator: Spanned, - left: &Value, - lhs: &NuDataFrame, - right: &Value, - rhs: &NuDataFrame, -) -> Result { - let operation_span = Span::merge(left.span(), right.span()); - match operator.item { - Operator::Math(Math::Plus) => match lhs.append_df(rhs, Axis::Row, operation_span) { - Ok(df) => Ok(df.into_value(operation_span)), - Err(e) => Err(e), - }, - _ => Err(ShellError::OperatorMismatch { - op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), - }), - } -} - -pub(super) fn compute_between_series( - operator: Spanned, - left: &Value, - lhs: &Series, - right: &Value, - rhs: &Series, -) -> Result { - let operation_span = Span::merge(left.span(), right.span()); - match operator.item { - Operator::Math(Math::Plus) => { - let mut res = lhs + rhs; - let name = format!("sum_{}_{}", lhs.name(), rhs.name()); - res.rename(&name); - NuDataFrame::series_to_value(res, operation_span) - } - Operator::Math(Math::Minus) => { - let mut res = lhs - rhs; - let name = format!("sub_{}_{}", lhs.name(), rhs.name()); - res.rename(&name); - NuDataFrame::series_to_value(res, operation_span) - } - Operator::Math(Math::Multiply) => { - let mut res = lhs * rhs; - let name = format!("mul_{}_{}", lhs.name(), rhs.name()); - res.rename(&name); - NuDataFrame::series_to_value(res, operation_span) - } - Operator::Math(Math::Divide) => { - let res = lhs.checked_div(rhs); - match res { - Ok(mut res) => { - let name = format!("div_{}_{}", lhs.name(), rhs.name()); - res.rename(&name); - NuDataFrame::series_to_value(res, operation_span) - } - Err(e) => Err(ShellError::GenericError { - error: "Division error".into(), - msg: e.to_string(), - span: Some(right.span()), - help: None, - inner: vec![], - }), - } - } - Operator::Comparison(Comparison::Equal) => { - let name = format!("eq_{}_{}", lhs.name(), rhs.name()); - let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::equal)?; - NuDataFrame::series_to_value(res, operation_span) - } - Operator::Comparison(Comparison::NotEqual) => { - let name = format!("neq_{}_{}", lhs.name(), rhs.name()); - let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::not_equal)?; - NuDataFrame::series_to_value(res, operation_span) - } - Operator::Comparison(Comparison::LessThan) => { - let name = format!("lt_{}_{}", lhs.name(), rhs.name()); - let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::lt)?; - NuDataFrame::series_to_value(res, operation_span) - } - Operator::Comparison(Comparison::LessThanOrEqual) => { - let name = format!("lte_{}_{}", lhs.name(), rhs.name()); - let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::lt_eq)?; - NuDataFrame::series_to_value(res, operation_span) - } - Operator::Comparison(Comparison::GreaterThan) => { - let name = format!("gt_{}_{}", lhs.name(), rhs.name()); - let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::gt)?; - NuDataFrame::series_to_value(res, operation_span) - } - Operator::Comparison(Comparison::GreaterThanOrEqual) => { - let name = format!("gte_{}_{}", lhs.name(), rhs.name()); - let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::gt_eq)?; - NuDataFrame::series_to_value(res, operation_span) - } - Operator::Boolean(Boolean::And) => match lhs.dtype() { - DataType::Boolean => { - let lhs_cast = lhs.bool(); - let rhs_cast = rhs.bool(); - - match (lhs_cast, rhs_cast) { - (Ok(l), Ok(r)) => { - let mut res = l.bitand(r).into_series(); - let name = format!("and_{}_{}", lhs.name(), rhs.name()); - res.rename(&name); - NuDataFrame::series_to_value(res, operation_span) - } - _ => Err(ShellError::GenericError { - error: "Incompatible types".into(), - msg: "unable to cast to boolean".into(), - span: Some(right.span()), - help: None, - inner: vec![], - }), - } - } - _ => Err(ShellError::IncompatibleParametersSingle { - msg: format!( - "Operation {} can only be done with boolean values", - operator.item - ), - span: operation_span, - }), - }, - Operator::Boolean(Boolean::Or) => match lhs.dtype() { - DataType::Boolean => { - let lhs_cast = lhs.bool(); - let rhs_cast = rhs.bool(); - - match (lhs_cast, rhs_cast) { - (Ok(l), Ok(r)) => { - let mut res = l.bitor(r).into_series(); - let name = format!("or_{}_{}", lhs.name(), rhs.name()); - res.rename(&name); - NuDataFrame::series_to_value(res, operation_span) - } - _ => Err(ShellError::GenericError { - error: "Incompatible types".into(), - msg: "unable to cast to boolean".into(), - span: Some(right.span()), - help: None, - inner: vec![], - }), - } - } - _ => Err(ShellError::IncompatibleParametersSingle { - msg: format!( - "Operation {} can only be done with boolean values", - operator.item - ), - span: operation_span, - }), - }, - _ => Err(ShellError::OperatorMismatch { - op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), - }), - } -} - -fn compare_series<'s, F>( - lhs: &'s Series, - rhs: &'s Series, - name: &'s str, - span: Span, - f: F, -) -> Result -where - F: Fn(&'s Series, &'s Series) -> Result, PolarsError>, -{ - let mut res = f(lhs, rhs) - .map_err(|e| ShellError::GenericError { - error: "Equality error".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - })? - .into_series(); - - res.rename(name); - Ok(res) -} - -pub(super) fn compute_series_single_value( - operator: Spanned, - left: &Value, - lhs: &NuDataFrame, - right: &Value, -) -> Result { - if !lhs.is_series() { - return Err(ShellError::OperatorMismatch { - op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), - }); - } - - let lhs_span = left.span(); - let lhs = lhs.as_series(lhs_span)?; - - match operator.item { - Operator::Math(Math::Plus) => match &right { - Value::Int { val, .. } => { - compute_series_i64(&lhs, *val, >::add, lhs_span) - } - Value::Float { val, .. } => { - compute_series_float(&lhs, *val, >::add, lhs_span) - } - Value::String { val, .. } => add_string_to_series(&lhs, val, lhs_span), - _ => Err(ShellError::OperatorMismatch { - op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), - }), - }, - Operator::Math(Math::Minus) => match &right { - Value::Int { val, .. } => { - compute_series_i64(&lhs, *val, >::sub, lhs_span) - } - Value::Float { val, .. } => { - compute_series_float(&lhs, *val, >::sub, lhs_span) - } - _ => Err(ShellError::OperatorMismatch { - op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), - }), - }, - Operator::Math(Math::Multiply) => match &right { - Value::Int { val, .. } => { - compute_series_i64(&lhs, *val, >::mul, lhs_span) - } - Value::Float { val, .. } => { - compute_series_float(&lhs, *val, >::mul, lhs_span) - } - _ => Err(ShellError::OperatorMismatch { - op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), - }), - }, - Operator::Math(Math::Divide) => { - let span = right.span(); - match &right { - Value::Int { val, .. } => { - if *val == 0 { - Err(ShellError::DivisionByZero { span }) - } else { - compute_series_i64(&lhs, *val, >::div, lhs_span) - } - } - Value::Float { val, .. } => { - if val.is_zero() { - Err(ShellError::DivisionByZero { span }) - } else { - compute_series_float(&lhs, *val, >::div, lhs_span) - } - } - _ => Err(ShellError::OperatorMismatch { - op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), - }), - } - } - Operator::Comparison(Comparison::Equal) => match &right { - Value::Int { val, .. } => compare_series_i64(&lhs, *val, ChunkedArray::equal, lhs_span), - Value::Float { val, .. } => { - compare_series_float(&lhs, *val, ChunkedArray::equal, lhs_span) - } - Value::String { val, .. } => { - let equal_pattern = format!("^{}$", fancy_regex::escape(val)); - contains_series_pat(&lhs, &equal_pattern, lhs_span) - } - Value::Date { val, .. } => { - compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::equal, lhs_span) - } - _ => Err(ShellError::OperatorMismatch { - op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), - }), - }, - Operator::Comparison(Comparison::NotEqual) => match &right { - Value::Int { val, .. } => { - compare_series_i64(&lhs, *val, ChunkedArray::not_equal, lhs_span) - } - Value::Float { val, .. } => { - compare_series_float(&lhs, *val, ChunkedArray::not_equal, lhs_span) - } - Value::Date { val, .. } => compare_series_i64( - &lhs, - val.timestamp_millis(), - ChunkedArray::not_equal, - lhs_span, - ), - _ => Err(ShellError::OperatorMismatch { - op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), - }), - }, - Operator::Comparison(Comparison::LessThan) => match &right { - Value::Int { val, .. } => compare_series_i64(&lhs, *val, ChunkedArray::lt, lhs_span), - Value::Float { val, .. } => { - compare_series_float(&lhs, *val, ChunkedArray::lt, lhs_span) - } - Value::Date { val, .. } => { - compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::lt, lhs_span) - } - _ => Err(ShellError::OperatorMismatch { - op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), - }), - }, - Operator::Comparison(Comparison::LessThanOrEqual) => match &right { - Value::Int { val, .. } => compare_series_i64(&lhs, *val, ChunkedArray::lt_eq, lhs_span), - Value::Float { val, .. } => { - compare_series_float(&lhs, *val, ChunkedArray::lt_eq, lhs_span) - } - Value::Date { val, .. } => { - compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::lt_eq, lhs_span) - } - _ => Err(ShellError::OperatorMismatch { - op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), - }), - }, - Operator::Comparison(Comparison::GreaterThan) => match &right { - Value::Int { val, .. } => compare_series_i64(&lhs, *val, ChunkedArray::gt, lhs_span), - Value::Float { val, .. } => { - compare_series_float(&lhs, *val, ChunkedArray::gt, lhs_span) - } - Value::Date { val, .. } => { - compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::gt, lhs_span) - } - _ => Err(ShellError::OperatorMismatch { - op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), - }), - }, - Operator::Comparison(Comparison::GreaterThanOrEqual) => match &right { - Value::Int { val, .. } => compare_series_i64(&lhs, *val, ChunkedArray::gt_eq, lhs_span), - Value::Float { val, .. } => { - compare_series_float(&lhs, *val, ChunkedArray::gt_eq, lhs_span) - } - Value::Date { val, .. } => { - compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::gt_eq, lhs_span) - } - _ => Err(ShellError::OperatorMismatch { - op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), - }), - }, - // TODO: update this to do a regex match instead of a simple contains? - Operator::Comparison(Comparison::RegexMatch) => match &right { - Value::String { val, .. } => contains_series_pat(&lhs, val, lhs_span), - _ => Err(ShellError::OperatorMismatch { - op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), - }), - }, - Operator::Comparison(Comparison::StartsWith) => match &right { - Value::String { val, .. } => { - let starts_with_pattern = format!("^{}", fancy_regex::escape(val)); - contains_series_pat(&lhs, &starts_with_pattern, lhs_span) - } - _ => Err(ShellError::OperatorMismatch { - op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), - }), - }, - Operator::Comparison(Comparison::EndsWith) => match &right { - Value::String { val, .. } => { - let ends_with_pattern = format!("{}$", fancy_regex::escape(val)); - contains_series_pat(&lhs, &ends_with_pattern, lhs_span) - } - _ => Err(ShellError::OperatorMismatch { - op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), - }), - }, - _ => Err(ShellError::OperatorMismatch { - op_span: operator.span, - lhs_ty: left.get_type().to_string(), - lhs_span: left.span(), - rhs_ty: right.get_type().to_string(), - rhs_span: right.span(), - }), - } -} - -fn compute_series_i64(series: &Series, val: i64, f: F, span: Span) -> Result -where - F: Fn(ChunkedArray, i64) -> ChunkedArray, -{ - match series.dtype() { - DataType::UInt32 | DataType::Int32 | DataType::UInt64 => { - let to_i64 = series.cast(&DataType::Int64); - - match to_i64 { - Ok(series) => { - let casted = series.i64(); - compute_casted_i64(casted, val, f, span) - } - Err(e) => Err(ShellError::GenericError { - error: "Unable to cast to i64".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - }), - } - } - DataType::Int64 => { - let casted = series.i64(); - compute_casted_i64(casted, val, f, span) - } - _ => Err(ShellError::GenericError { - error: "Incorrect type".into(), - msg: format!( - "Series of type {} can not be used for operations with an i64 value", - series.dtype() - ), - span: Some(span), - help: None, - inner: vec![], - }), - } -} - -fn compute_casted_i64( - casted: Result<&ChunkedArray, PolarsError>, - val: i64, - f: F, - span: Span, -) -> Result -where - F: Fn(ChunkedArray, i64) -> ChunkedArray, -{ - match casted { - Ok(casted) => { - let res = f(casted.clone(), val); - let res = res.into_series(); - NuDataFrame::series_to_value(res, span) - } - Err(e) => Err(ShellError::GenericError { - error: "Unable to cast to i64".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - }), - } -} - -fn compute_series_float(series: &Series, val: f64, f: F, span: Span) -> Result -where - F: Fn(ChunkedArray, f64) -> ChunkedArray, -{ - match series.dtype() { - DataType::Float32 => { - let to_f64 = series.cast(&DataType::Float64); - - match to_f64 { - Ok(series) => { - let casted = series.f64(); - compute_casted_f64(casted, val, f, span) - } - Err(e) => Err(ShellError::GenericError { - error: "Unable to cast to f64".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - }), - } - } - DataType::Float64 => { - let casted = series.f64(); - compute_casted_f64(casted, val, f, span) - } - _ => Err(ShellError::GenericError { - error: "Incorrect type".into(), - msg: format!( - "Series of type {} can not be used for operations with a float value", - series.dtype() - ), - span: Some(span), - help: None, - inner: vec![], - }), - } -} - -fn compute_casted_f64( - casted: Result<&ChunkedArray, PolarsError>, - val: f64, - f: F, - span: Span, -) -> Result -where - F: Fn(ChunkedArray, f64) -> ChunkedArray, -{ - match casted { - Ok(casted) => { - let res = f(casted.clone(), val); - let res = res.into_series(); - NuDataFrame::series_to_value(res, span) - } - Err(e) => Err(ShellError::GenericError { - error: "Unable to cast to f64".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - }), - } -} - -fn compare_series_i64(series: &Series, val: i64, f: F, span: Span) -> Result -where - F: Fn(&ChunkedArray, i64) -> ChunkedArray, -{ - match series.dtype() { - DataType::UInt32 | DataType::Int32 | DataType::UInt64 | DataType::Datetime(_, _) => { - let to_i64 = series.cast(&DataType::Int64); - - match to_i64 { - Ok(series) => { - let casted = series.i64(); - compare_casted_i64(casted, val, f, span) - } - Err(e) => Err(ShellError::GenericError { - error: "Unable to cast to f64".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - }), - } - } - DataType::Date => { - let to_i64 = series.cast(&DataType::Int64); - - match to_i64 { - Ok(series) => { - let nanosecs_per_day: i64 = 24 * 60 * 60 * 1_000_000_000; - let casted = series - .i64() - .map(|chunked| chunked.mul(nanosecs_per_day)) - .expect("already checked for casting"); - compare_casted_i64(Ok(&casted), val, f, span) - } - Err(e) => Err(ShellError::GenericError { - error: "Unable to cast to f64".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - }), - } - } - DataType::Int64 => { - let casted = series.i64(); - compare_casted_i64(casted, val, f, span) - } - _ => Err(ShellError::GenericError { - error: "Incorrect type".into(), - msg: format!( - "Series of type {} can not be used for operations with an i64 value", - series.dtype() - ), - span: Some(span), - help: None, - inner: vec![], - }), - } -} - -fn compare_casted_i64( - casted: Result<&ChunkedArray, PolarsError>, - val: i64, - f: F, - span: Span, -) -> Result -where - F: Fn(&ChunkedArray, i64) -> ChunkedArray, -{ - match casted { - Ok(casted) => { - let res = f(casted, val); - let res = res.into_series(); - NuDataFrame::series_to_value(res, span) - } - Err(e) => Err(ShellError::GenericError { - error: "Unable to cast to i64".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - }), - } -} - -fn compare_series_float(series: &Series, val: f64, f: F, span: Span) -> Result -where - F: Fn(&ChunkedArray, f64) -> ChunkedArray, -{ - match series.dtype() { - DataType::Float32 => { - let to_f64 = series.cast(&DataType::Float64); - - match to_f64 { - Ok(series) => { - let casted = series.f64(); - compare_casted_f64(casted, val, f, span) - } - Err(e) => Err(ShellError::GenericError { - error: "Unable to cast to i64".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - }), - } - } - DataType::Float64 => { - let casted = series.f64(); - compare_casted_f64(casted, val, f, span) - } - _ => Err(ShellError::GenericError { - error: "Incorrect type".into(), - msg: format!( - "Series of type {} can not be used for operations with a float value", - series.dtype() - ), - span: Some(span), - help: None, - inner: vec![], - }), - } -} - -fn compare_casted_f64( - casted: Result<&ChunkedArray, PolarsError>, - val: f64, - f: F, - span: Span, -) -> Result -where - F: Fn(&ChunkedArray, f64) -> ChunkedArray, -{ - match casted { - Ok(casted) => { - let res = f(casted, val); - let res = res.into_series(); - NuDataFrame::series_to_value(res, span) - } - Err(e) => Err(ShellError::GenericError { - error: "Unable to cast to f64".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - }), - } -} - -fn contains_series_pat(series: &Series, pat: &str, span: Span) -> Result { - let casted = series.str(); - match casted { - Ok(casted) => { - let res = casted.contains(pat, false); - - match res { - Ok(res) => { - let res = res.into_series(); - NuDataFrame::series_to_value(res, span) - } - Err(e) => Err(ShellError::GenericError { - error: "Error using contains".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - }), - } - } - Err(e) => Err(ShellError::GenericError { - error: "Unable to cast to string".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - }), - } -} - -fn add_string_to_series(series: &Series, pat: &str, span: Span) -> Result { - let casted = series.str(); - match casted { - Ok(casted) => { - let res = casted + pat; - let res = res.into_series(); - - NuDataFrame::series_to_value(res, span) - } - Err(e) => Err(ShellError::GenericError { - error: "Unable to cast to string".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - }), - } -} - -#[cfg(test)] -mod test { - use super::*; - use nu_protocol::Span; - use polars::{prelude::NamedFrom, series::Series}; - - use crate::dataframe::values::NuDataFrame; - - #[test] - fn test_compute_between_series_comparisons() { - let series = Series::new("c", &[1, 2]); - let df = NuDataFrame::try_from_series(vec![series], Span::test_data()) - .expect("should be able to create a simple dataframe"); - - let c0 = df - .column("c", Span::test_data()) - .expect("should be able to get column c"); - - let c0_series = c0 - .as_series(Span::test_data()) - .expect("should be able to get series"); - - let c0_value = c0.into_value(Span::test_data()); - - let c1 = df - .column("c", Span::test_data()) - .expect("should be able to get column c"); - - let c1_series = c1 - .as_series(Span::test_data()) - .expect("should be able to get series"); - - let c1_value = c1.into_value(Span::test_data()); - - let op = Spanned { - item: Operator::Comparison(Comparison::NotEqual), - span: Span::test_data(), - }; - let result = compute_between_series(op, &c0_value, &c0_series, &c1_value, &c1_series) - .expect("compare should not fail"); - let result = NuDataFrame::try_from_value(result) - .expect("should be able to create a dataframe from a value"); - let result = result - .as_series(Span::test_data()) - .expect("should be convert to a series"); - assert_eq!(result, Series::new("neq_c_c", &[false, false])); - - let op = Spanned { - item: Operator::Comparison(Comparison::Equal), - span: Span::test_data(), - }; - let result = compute_between_series(op, &c0_value, &c0_series, &c1_value, &c1_series) - .expect("compare should not fail"); - let result = NuDataFrame::try_from_value(result) - .expect("should be able to create a dataframe from a value"); - let result = result - .as_series(Span::test_data()) - .expect("should be convert to a series"); - assert_eq!(result, Series::new("eq_c_c", &[true, true])); - - let op = Spanned { - item: Operator::Comparison(Comparison::LessThan), - span: Span::test_data(), - }; - let result = compute_between_series(op, &c0_value, &c0_series, &c1_value, &c1_series) - .expect("compare should not fail"); - let result = NuDataFrame::try_from_value(result) - .expect("should be able to create a dataframe from a value"); - let result = result - .as_series(Span::test_data()) - .expect("should be convert to a series"); - assert_eq!(result, Series::new("lt_c_c", &[false, false])); - - let op = Spanned { - item: Operator::Comparison(Comparison::LessThanOrEqual), - span: Span::test_data(), - }; - let result = compute_between_series(op, &c0_value, &c0_series, &c1_value, &c1_series) - .expect("compare should not fail"); - let result = NuDataFrame::try_from_value(result) - .expect("should be able to create a dataframe from a value"); - let result = result - .as_series(Span::test_data()) - .expect("should be convert to a series"); - assert_eq!(result, Series::new("lte_c_c", &[true, true])); - - let op = Spanned { - item: Operator::Comparison(Comparison::GreaterThan), - span: Span::test_data(), - }; - let result = compute_between_series(op, &c0_value, &c0_series, &c1_value, &c1_series) - .expect("compare should not fail"); - let result = NuDataFrame::try_from_value(result) - .expect("should be able to create a dataframe from a value"); - let result = result - .as_series(Span::test_data()) - .expect("should be convert to a series"); - assert_eq!(result, Series::new("gt_c_c", &[false, false])); - - let op = Spanned { - item: Operator::Comparison(Comparison::GreaterThanOrEqual), - span: Span::test_data(), - }; - let result = compute_between_series(op, &c0_value, &c0_series, &c1_value, &c1_series) - .expect("compare should not fail"); - let result = NuDataFrame::try_from_value(result) - .expect("should be able to create a dataframe from a value"); - let result = result - .as_series(Span::test_data()) - .expect("should be convert to a series"); - assert_eq!(result, Series::new("gte_c_c", &[true, true])); - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/conversion.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/conversion.rs deleted file mode 100644 index 7ab339d78d..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/conversion.rs +++ /dev/null @@ -1,1435 +0,0 @@ -use super::{DataFrameValue, NuDataFrame, NuSchema}; -use chrono::{DateTime, Duration, FixedOffset, NaiveTime, TimeZone, Utc}; -use chrono_tz::Tz; -use indexmap::map::{Entry, IndexMap}; -use nu_protocol::{Record, ShellError, Span, Value}; -use polars::{ - chunked_array::{ - builder::AnonymousOwnedListBuilder, object::builder::ObjectChunkedBuilder, ChunkedArray, - }, - datatypes::AnyValue, - export::arrow::Either, - prelude::{ - DataFrame, DataType, DatetimeChunked, Float32Type, Float64Type, Int16Type, Int32Type, - Int64Type, Int8Type, IntoSeries, ListBooleanChunkedBuilder, ListBuilderTrait, - ListPrimitiveChunkedBuilder, ListStringChunkedBuilder, ListType, NamedFrom, - NewChunkedArray, ObjectType, Schema, Series, StructChunked, TemporalMethods, TimeUnit, - UInt16Type, UInt32Type, UInt64Type, UInt8Type, - }, -}; -use std::ops::{Deref, DerefMut}; - -const NANOS_PER_DAY: i64 = 86_400_000_000_000; - -// The values capacity is for the size of an vec. -// Since this is impossible to determine without traversing every value -// I just picked one. Since this is for converting back and forth -// between nushell tables the values shouldn't be too extremely large for -// practical reasons (~ a few thousand rows). -const VALUES_CAPACITY: usize = 10; - -macro_rules! value_to_primitive { - ($value:ident, u8) => { - $value.as_i64().map(|v| v as u8) - }; - ($value:ident, u16) => { - $value.as_i64().map(|v| v as u16) - }; - ($value:ident, u32) => { - $value.as_i64().map(|v| v as u32) - }; - ($value:ident, u64) => { - $value.as_i64().map(|v| v as u64) - }; - ($value:ident, i8) => { - $value.as_i64().map(|v| v as i8) - }; - ($value:ident, i16) => { - $value.as_i64().map(|v| v as i16) - }; - ($value:ident, i32) => { - $value.as_i64().map(|v| v as i32) - }; - ($value:ident, i64) => { - $value.as_i64() - }; - ($value:ident, f32) => { - $value.as_f64().map(|v| v as f32) - }; - ($value:ident, f64) => { - $value.as_f64() - }; -} - -#[derive(Debug)] -pub struct Column { - name: String, - values: Vec, -} - -impl Column { - pub fn new(name: String, values: Vec) -> Self { - Self { name, values } - } - - pub fn new_empty(name: String) -> Self { - Self { - name, - values: Vec::new(), - } - } - - pub fn name(&self) -> &str { - self.name.as_str() - } -} - -impl IntoIterator for Column { - type Item = Value; - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.values.into_iter() - } -} - -impl Deref for Column { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.values - } -} - -impl DerefMut for Column { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.values - } -} - -#[derive(Debug)] -pub struct TypedColumn { - column: Column, - column_type: Option, -} - -impl TypedColumn { - fn new_empty(name: String) -> Self { - Self { - column: Column::new_empty(name), - column_type: None, - } - } -} - -impl Deref for TypedColumn { - type Target = Column; - - fn deref(&self) -> &Self::Target { - &self.column - } -} - -impl DerefMut for TypedColumn { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.column - } -} - -pub type ColumnMap = IndexMap; - -pub fn create_column( - series: &Series, - from_row: usize, - to_row: usize, - span: Span, -) -> Result { - let size = to_row - from_row; - let values = series_to_values(series, Some(from_row), Some(size), span)?; - Ok(Column::new(series.name().into(), values)) -} - -// Adds a separator to the vector of values using the column names from the -// dataframe to create the Values Row -pub fn add_separator(values: &mut Vec, df: &DataFrame, span: Span) { - let mut record = Record::new(); - - record.push("index", Value::string("...", span)); - - for name in df.get_column_names() { - record.push(name, Value::string("...", span)) - } - - values.push(Value::record(record, span)); -} - -// Inserting the values found in a Value::List or Value::Record -pub fn insert_record( - column_values: &mut ColumnMap, - record: Record, - maybe_schema: &Option, -) -> Result<(), ShellError> { - for (col, value) in record { - insert_value(value, col, column_values, maybe_schema)?; - } - - Ok(()) -} - -pub fn insert_value( - value: Value, - key: String, - column_values: &mut ColumnMap, - maybe_schema: &Option, -) -> Result<(), ShellError> { - let col_val = match column_values.entry(key.clone()) { - Entry::Vacant(entry) => entry.insert(TypedColumn::new_empty(key.clone())), - Entry::Occupied(entry) => entry.into_mut(), - }; - - // Checking that the type for the value is the same - // for the previous value in the column - if col_val.values.is_empty() { - if let Some(schema) = maybe_schema { - if let Some(field) = schema.schema.get_field(&key) { - col_val.column_type = Some(field.data_type().clone()); - } - } - - if col_val.column_type.is_none() { - col_val.column_type = Some(value_to_data_type(&value)); - } - - col_val.values.push(value); - } else { - let prev_value = &col_val.values[col_val.values.len() - 1]; - - match (&prev_value, &value) { - (Value::Int { .. }, Value::Int { .. }) - | (Value::Float { .. }, Value::Float { .. }) - | (Value::String { .. }, Value::String { .. }) - | (Value::Bool { .. }, Value::Bool { .. }) - | (Value::Date { .. }, Value::Date { .. }) - | (Value::Filesize { .. }, Value::Filesize { .. }) - | (Value::Duration { .. }, Value::Duration { .. }) => col_val.values.push(value), - (Value::List { .. }, _) => { - col_val.column_type = Some(value_to_data_type(&value)); - col_val.values.push(value); - } - _ => { - col_val.column_type = Some(DataType::Object("Value", None)); - col_val.values.push(value); - } - } - } - - Ok(()) -} - -fn value_to_data_type(value: &Value) -> DataType { - match &value { - Value::Int { .. } => DataType::Int64, - Value::Float { .. } => DataType::Float64, - Value::String { .. } => DataType::String, - Value::Bool { .. } => DataType::Boolean, - Value::Date { .. } => DataType::Date, - Value::Duration { .. } => DataType::Duration(TimeUnit::Nanoseconds), - Value::Filesize { .. } => DataType::Int64, - Value::List { vals, .. } => { - // We need to determined the type inside of the list. - // Since Value::List does not have any kind of - // type information, we need to look inside the list. - // This will cause errors if lists have inconsistent types. - // Basically, if a list column needs to be converted to dataframe, - // needs to have consistent types. - let list_type = vals - .iter() - .filter(|v| !matches!(v, Value::Nothing { .. })) - .map(value_to_data_type) - .nth(1) - .unwrap_or(DataType::Object("Value", None)); - - DataType::List(Box::new(list_type)) - } - _ => DataType::Object("Value", None), - } -} - -fn typed_column_to_series(name: &str, column: TypedColumn) -> Result { - if let Some(column_type) = &column.column_type { - match column_type { - DataType::Float32 => { - let series_values: Result, _> = column - .values - .iter() - .map(|v| v.as_f64().map(|v| v as f32)) - .collect(); - Ok(Series::new(name, series_values?)) - } - DataType::Float64 => { - let series_values: Result, _> = - column.values.iter().map(|v| v.as_f64()).collect(); - Ok(Series::new(name, series_values?)) - } - DataType::UInt8 => { - let series_values: Result, _> = column - .values - .iter() - .map(|v| v.as_i64().map(|v| v as u8)) - .collect(); - Ok(Series::new(name, series_values?)) - } - DataType::UInt16 => { - let series_values: Result, _> = column - .values - .iter() - .map(|v| v.as_i64().map(|v| v as u16)) - .collect(); - Ok(Series::new(name, series_values?)) - } - DataType::UInt32 => { - let series_values: Result, _> = column - .values - .iter() - .map(|v| v.as_i64().map(|v| v as u32)) - .collect(); - Ok(Series::new(name, series_values?)) - } - DataType::UInt64 => { - let series_values: Result, _> = column - .values - .iter() - .map(|v| v.as_i64().map(|v| v as u64)) - .collect(); - Ok(Series::new(name, series_values?)) - } - DataType::Int8 => { - let series_values: Result, _> = column - .values - .iter() - .map(|v| v.as_i64().map(|v| v as i8)) - .collect(); - Ok(Series::new(name, series_values?)) - } - DataType::Int16 => { - let series_values: Result, _> = column - .values - .iter() - .map(|v| v.as_i64().map(|v| v as i16)) - .collect(); - Ok(Series::new(name, series_values?)) - } - DataType::Int32 => { - let series_values: Result, _> = column - .values - .iter() - .map(|v| v.as_i64().map(|v| v as i32)) - .collect(); - Ok(Series::new(name, series_values?)) - } - DataType::Int64 => { - let series_values: Result, _> = - column.values.iter().map(|v| v.as_i64()).collect(); - Ok(Series::new(name, series_values?)) - } - DataType::Boolean => { - let series_values: Result, _> = - column.values.iter().map(|v| v.as_bool()).collect(); - Ok(Series::new(name, series_values?)) - } - DataType::String => { - let series_values: Result, _> = - column.values.iter().map(|v| v.coerce_string()).collect(); - Ok(Series::new(name, series_values?)) - } - DataType::Object(_, _) => value_to_series(name, &column.values), - DataType::Duration(time_unit) => { - //todo - finish type conversion - let series_values: Result, _> = column - .values - .iter() - .map(|v| v.as_i64().map(|v| nanos_from_timeunit(v, *time_unit))) - .collect(); - Ok(Series::new(name, series_values?)) - } - DataType::List(list_type) => { - match input_type_list_to_series(name, list_type.as_ref(), &column.values) { - Ok(series) => Ok(series), - Err(_) => { - // An error case will occur when there are lists of mixed types. - // If this happens, fallback to object list - input_type_list_to_series( - name, - &DataType::Object("unknown", None), - &column.values, - ) - } - } - } - DataType::Date => { - let it = column.values.iter().map(|v| { - if let Value::Date { val, .. } = &v { - Some(val.timestamp_nanos_opt().unwrap_or_default()) - } else { - None - } - }); - - let res: DatetimeChunked = ChunkedArray::::from_iter_options(name, it) - .into_datetime(TimeUnit::Nanoseconds, None); - - Ok(res.into_series()) - } - DataType::Datetime(tu, maybe_tz) => { - let dates = column - .values - .iter() - .map(|v| { - if let Value::Date { val, .. } = &v { - // If there is a timezone specified, make sure - // the value is converted to it - Ok(maybe_tz - .as_ref() - .map(|tz| tz.parse::().map(|tz| val.with_timezone(&tz))) - .transpose() - .map_err(|e| ShellError::GenericError { - error: "Error parsing timezone".into(), - msg: "".into(), - span: None, - help: Some(e.to_string()), - inner: vec![], - })? - .and_then(|dt| dt.timestamp_nanos_opt()) - .map(|nanos| nanos_from_timeunit(nanos, *tu))) - } else { - Ok(None) - } - }) - .collect::>, ShellError>>()?; - - let res: DatetimeChunked = - ChunkedArray::::from_iter_options(name, dates.into_iter()) - .into_datetime(*tu, maybe_tz.clone()); - - Ok(res.into_series()) - } - DataType::Struct(fields) => { - let schema = Some(NuSchema::new(Schema::from_iter(fields.clone()))); - let mut structs: Vec = Vec::new(); - - for v in column.values.iter() { - let mut column_values: ColumnMap = IndexMap::new(); - let record = v.as_record()?; - insert_record(&mut column_values, record.clone(), &schema)?; - let df = from_parsed_columns(column_values)?; - structs.push(df.as_series(Span::unknown())?); - } - - let chunked = StructChunked::new(column.name(), structs.as_ref()).map_err(|e| { - ShellError::GenericError { - error: format!("Error creating struct: {e}"), - msg: "".into(), - span: None, - help: None, - inner: vec![], - } - })?; - Ok(chunked.into_series()) - } - _ => Err(ShellError::GenericError { - error: format!("Error creating dataframe: Unsupported type: {column_type:?}"), - msg: "".into(), - span: None, - help: None, - inner: vec![], - }), - } - } else { - Err(ShellError::GenericError { - error: "Passed a type column with no type".into(), - msg: "".into(), - span: None, - help: None, - inner: vec![], - }) - } -} - -// The ColumnMap has the parsed data from the StreamInput -// This data can be used to create a Series object that can initialize -// the dataframe based on the type of data that is found -pub fn from_parsed_columns(column_values: ColumnMap) -> Result { - let mut df_series: Vec = Vec::new(); - for (name, column) in column_values { - let series = typed_column_to_series(&name, column)?; - df_series.push(series); - } - - DataFrame::new(df_series) - .map(|df| NuDataFrame::new(false, df)) - .map_err(|e| ShellError::GenericError { - error: "Error creating dataframe".into(), - msg: e.to_string(), - span: None, - help: None, - inner: vec![], - }) -} - -fn value_to_series(name: &str, values: &[Value]) -> Result { - let mut builder = ObjectChunkedBuilder::::new(name, values.len()); - - for v in values { - builder.append_value(DataFrameValue::new(v.clone())); - } - - let res = builder.finish(); - Ok(res.into_series()) -} - -fn input_type_list_to_series( - name: &str, - data_type: &DataType, - values: &[Value], -) -> Result { - let inconsistent_error = |_| ShellError::GenericError { - error: format!( - "column {name} contains a list with inconsistent types: Expecting: {data_type:?}" - ), - msg: "".into(), - span: None, - help: None, - inner: vec![], - }; - - macro_rules! primitive_list_series { - ($list_type:ty, $vec_type:tt) => {{ - let mut builder = ListPrimitiveChunkedBuilder::<$list_type>::new( - name, - values.len(), - VALUES_CAPACITY, - data_type.clone(), - ); - - for v in values { - let value_list = v - .as_list()? - .iter() - .map(|v| value_to_primitive!(v, $vec_type)) - .collect::, _>>() - .map_err(inconsistent_error)?; - builder.append_iter_values(value_list.iter().copied()); - } - let res = builder.finish(); - Ok(res.into_series()) - }}; - } - - match *data_type { - // list of boolean values - DataType::Boolean => { - let mut builder = ListBooleanChunkedBuilder::new(name, values.len(), VALUES_CAPACITY); - for v in values { - let value_list = v - .as_list()? - .iter() - .map(|v| v.as_bool()) - .collect::, _>>() - .map_err(inconsistent_error)?; - builder.append_iter(value_list.iter().map(|v| Some(*v))); - } - let res = builder.finish(); - Ok(res.into_series()) - } - DataType::Duration(_) => primitive_list_series!(Int64Type, i64), - DataType::UInt8 => primitive_list_series!(UInt8Type, u8), - DataType::UInt16 => primitive_list_series!(UInt16Type, u16), - DataType::UInt32 => primitive_list_series!(UInt32Type, u32), - DataType::UInt64 => primitive_list_series!(UInt64Type, u64), - DataType::Int8 => primitive_list_series!(Int8Type, i8), - DataType::Int16 => primitive_list_series!(Int16Type, i16), - DataType::Int32 => primitive_list_series!(Int32Type, i32), - DataType::Int64 => primitive_list_series!(Int64Type, i64), - DataType::Float32 => primitive_list_series!(Float32Type, f32), - DataType::Float64 => primitive_list_series!(Float64Type, f64), - DataType::String => { - let mut builder = ListStringChunkedBuilder::new(name, values.len(), VALUES_CAPACITY); - for v in values { - let value_list = v - .as_list()? - .iter() - .map(|v| v.coerce_string()) - .collect::, _>>() - .map_err(inconsistent_error)?; - builder.append_values_iter(value_list.iter().map(AsRef::as_ref)); - } - let res = builder.finish(); - Ok(res.into_series()) - } - DataType::Date => { - let mut builder = AnonymousOwnedListBuilder::new( - name, - values.len(), - Some(DataType::Datetime(TimeUnit::Nanoseconds, None)), - ); - for (i, v) in values.iter().enumerate() { - let list_name = i.to_string(); - - let it = v.as_list()?.iter().map(|v| { - if let Value::Date { val, .. } = &v { - Some(val.timestamp_nanos_opt().unwrap_or_default()) - } else { - None - } - }); - let dt_chunked = ChunkedArray::::from_iter_options(&list_name, it) - .into_datetime(TimeUnit::Nanoseconds, None); - - builder - .append_series(&dt_chunked.into_series()) - .map_err(|e| ShellError::GenericError { - error: "Error appending to series".into(), - msg: "".into(), - span: None, - help: Some(e.to_string()), - inner: vec![], - })? - } - let res = builder.finish(); - Ok(res.into_series()) - } - DataType::List(ref sub_list_type) => { - Ok(input_type_list_to_series(name, sub_list_type, values)?) - } - // treat everything else as an object - _ => Ok(value_to_series(name, values)?), - } -} - -fn series_to_values( - series: &Series, - maybe_from_row: Option, - maybe_size: Option, - span: Span, -) -> Result, ShellError> { - match series.dtype() { - DataType::Null => { - let it = std::iter::repeat(Value::nothing(span)); - let values = if let Some(size) = maybe_size { - Either::Left(it.take(size)) - } else { - Either::Right(it) - } - .collect::>(); - - Ok(values) - } - DataType::UInt8 => { - let casted = series.u8().map_err(|e| ShellError::GenericError { - error: "Error casting column to u8".into(), - msg: "".into(), - span: None, - help: Some(e.to_string()), - inner: vec![], - })?; - - let it = casted.into_iter(); - let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|v| match v { - Some(a) => Value::int(a as i64, span), - None => Value::nothing(span), - }) - .collect::>(); - - Ok(values) - } - DataType::UInt16 => { - let casted = series.u16().map_err(|e| ShellError::GenericError { - error: "Error casting column to u16".into(), - msg: "".into(), - span: None, - help: Some(e.to_string()), - inner: vec![], - })?; - - let it = casted.into_iter(); - let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|v| match v { - Some(a) => Value::int(a as i64, span), - None => Value::nothing(span), - }) - .collect::>(); - - Ok(values) - } - DataType::UInt32 => { - let casted = series.u32().map_err(|e| ShellError::GenericError { - error: "Error casting column to u32".into(), - msg: "".into(), - span: None, - help: Some(e.to_string()), - inner: vec![], - })?; - - let it = casted.into_iter(); - let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|v| match v { - Some(a) => Value::int(a as i64, span), - None => Value::nothing(span), - }) - .collect::>(); - - Ok(values) - } - DataType::UInt64 => { - let casted = series.u64().map_err(|e| ShellError::GenericError { - error: "Error casting column to u64".into(), - msg: "".into(), - span: None, - help: Some(e.to_string()), - inner: vec![], - })?; - - let it = casted.into_iter(); - let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|v| match v { - Some(a) => Value::int(a as i64, span), - None => Value::nothing(span), - }) - .collect::>(); - - Ok(values) - } - DataType::Int8 => { - let casted = series.i8().map_err(|e| ShellError::GenericError { - error: "Error casting column to i8".into(), - msg: "".into(), - span: None, - help: Some(e.to_string()), - inner: vec![], - })?; - - let it = casted.into_iter(); - let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|v| match v { - Some(a) => Value::int(a as i64, span), - None => Value::nothing(span), - }) - .collect::>(); - - Ok(values) - } - DataType::Int16 => { - let casted = series.i16().map_err(|e| ShellError::GenericError { - error: "Error casting column to i16".into(), - msg: "".into(), - span: None, - help: Some(e.to_string()), - inner: vec![], - })?; - - let it = casted.into_iter(); - let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|v| match v { - Some(a) => Value::int(a as i64, span), - None => Value::nothing(span), - }) - .collect::>(); - - Ok(values) - } - DataType::Int32 => { - let casted = series.i32().map_err(|e| ShellError::GenericError { - error: "Error casting column to i32".into(), - msg: "".into(), - span: None, - help: Some(e.to_string()), - inner: vec![], - })?; - - let it = casted.into_iter(); - let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|v| match v { - Some(a) => Value::int(a as i64, span), - None => Value::nothing(span), - }) - .collect::>(); - - Ok(values) - } - DataType::Int64 => { - let casted = series.i64().map_err(|e| ShellError::GenericError { - error: "Error casting column to i64".into(), - msg: "".into(), - span: None, - help: Some(e.to_string()), - inner: vec![], - })?; - - let it = casted.into_iter(); - let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|v| match v { - Some(a) => Value::int(a, span), - None => Value::nothing(span), - }) - .collect::>(); - - Ok(values) - } - DataType::Float32 => { - let casted = series.f32().map_err(|e| ShellError::GenericError { - error: "Error casting column to f32".into(), - msg: "".into(), - span: None, - help: Some(e.to_string()), - inner: vec![], - })?; - - let it = casted.into_iter(); - let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|v| match v { - Some(a) => Value::float(a as f64, span), - None => Value::nothing(span), - }) - .collect::>(); - - Ok(values) - } - DataType::Float64 => { - let casted = series.f64().map_err(|e| ShellError::GenericError { - error: "Error casting column to f64".into(), - msg: "".into(), - span: None, - help: Some(e.to_string()), - inner: vec![], - })?; - - let it = casted.into_iter(); - let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|v| match v { - Some(a) => Value::float(a, span), - None => Value::nothing(span), - }) - .collect::>(); - - Ok(values) - } - DataType::Boolean => { - let casted = series.bool().map_err(|e| ShellError::GenericError { - error: "Error casting column to bool".into(), - msg: "".into(), - span: None, - help: Some(e.to_string()), - inner: vec![], - })?; - - let it = casted.into_iter(); - let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|v| match v { - Some(a) => Value::bool(a, span), - None => Value::nothing(span), - }) - .collect::>(); - - Ok(values) - } - DataType::String => { - let casted = series.str().map_err(|e| ShellError::GenericError { - error: "Error casting column to string".into(), - msg: "".into(), - span: None, - help: Some(e.to_string()), - inner: vec![], - })?; - - let it = casted.into_iter(); - let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|v| match v { - Some(a) => Value::string(a.to_string(), span), - None => Value::nothing(span), - }) - .collect::>(); - - Ok(values) - } - DataType::Object(x, _) => { - let casted = series - .as_any() - .downcast_ref::>>(); - - match casted { - None => Err(ShellError::GenericError { - error: "Error casting object from series".into(), - msg: "".into(), - span: None, - help: Some(format!("Object not supported for conversion: {x}")), - inner: vec![], - }), - Some(ca) => { - let it = ca.into_iter(); - let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) - { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|v| match v { - Some(a) => a.get_value(), - None => Value::nothing(span), - }) - .collect::>(); - - Ok(values) - } - } - } - DataType::List(x) => { - let casted = series.as_any().downcast_ref::>(); - match casted { - None => Err(ShellError::GenericError { - error: "Error casting list from series".into(), - msg: "".into(), - span: None, - help: Some(format!("List not supported for conversion: {x}")), - inner: vec![], - }), - Some(ca) => { - let it = ca.into_iter(); - if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|ca| { - let sublist: Vec = if let Some(ref s) = ca { - series_to_values(s, None, None, Span::unknown())? - } else { - // empty item - vec![] - }; - Ok(Value::list(sublist, span)) - }) - .collect::, ShellError>>() - } - } - } - DataType::Date => { - let casted = series.date().map_err(|e| ShellError::GenericError { - error: "Error casting column to date".into(), - msg: "".into(), - span: None, - help: Some(e.to_string()), - inner: vec![], - })?; - - let it = casted.into_iter(); - let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|v| match v { - Some(a) => { - let nanos = nanos_per_day(a); - let datetime = datetime_from_epoch_nanos(nanos, &None, span)?; - Ok(Value::date(datetime, span)) - } - None => Ok(Value::nothing(span)), - }) - .collect::, ShellError>>()?; - Ok(values) - } - DataType::Datetime(time_unit, tz) => { - let casted = series.datetime().map_err(|e| ShellError::GenericError { - error: "Error casting column to datetime".into(), - msg: "".into(), - span: None, - help: Some(e.to_string()), - inner: vec![], - })?; - - let it = casted.into_iter(); - let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|v| match v { - Some(a) => { - // elapsed time in nano/micro/milliseconds since 1970-01-01 - let nanos = nanos_from_timeunit(a, *time_unit); - let datetime = datetime_from_epoch_nanos(nanos, tz, span)?; - Ok(Value::date(datetime, span)) - } - None => Ok(Value::nothing(span)), - }) - .collect::, ShellError>>()?; - Ok(values) - } - DataType::Struct(polar_fields) => { - let casted = series.struct_().map_err(|e| ShellError::GenericError { - error: "Error casting column to struct".into(), - msg: "".to_string(), - span: None, - help: Some(e.to_string()), - inner: Vec::new(), - })?; - let it = casted.into_iter(); - let values: Result, ShellError> = - if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|any_values| { - let record = polar_fields - .iter() - .zip(any_values) - .map(|(field, val)| { - any_value_to_value(val, span).map(|val| (field.name.to_string(), val)) - }) - .collect::>()?; - - Ok(Value::record(record, span)) - }) - .collect(); - values - } - DataType::Time => { - let casted = - series - .timestamp(TimeUnit::Nanoseconds) - .map_err(|e| ShellError::GenericError { - error: "Error casting column to time".into(), - msg: "".into(), - span: None, - help: Some(e.to_string()), - inner: vec![], - })?; - - let it = casted.into_iter(); - let values = if let (Some(size), Some(from_row)) = (maybe_size, maybe_from_row) { - Either::Left(it.skip(from_row).take(size)) - } else { - Either::Right(it) - } - .map(|v| match v { - Some(nanoseconds) => Value::duration(nanoseconds, span), - None => Value::nothing(span), - }) - .collect::>(); - - Ok(values) - } - e => Err(ShellError::GenericError { - error: "Error creating Dataframe".into(), - msg: "".to_string(), - span: None, - help: Some(format!("Value not supported in nushell: {e}")), - inner: vec![], - }), - } -} - -fn any_value_to_value(any_value: &AnyValue, span: Span) -> Result { - match any_value { - AnyValue::Null => Ok(Value::nothing(span)), - AnyValue::Boolean(b) => Ok(Value::bool(*b, span)), - AnyValue::String(s) => Ok(Value::string(s.to_string(), span)), - AnyValue::UInt8(i) => Ok(Value::int(*i as i64, span)), - AnyValue::UInt16(i) => Ok(Value::int(*i as i64, span)), - AnyValue::UInt32(i) => Ok(Value::int(*i as i64, span)), - AnyValue::UInt64(i) => Ok(Value::int(*i as i64, span)), - AnyValue::Int8(i) => Ok(Value::int(*i as i64, span)), - AnyValue::Int16(i) => Ok(Value::int(*i as i64, span)), - AnyValue::Int32(i) => Ok(Value::int(*i as i64, span)), - AnyValue::Int64(i) => Ok(Value::int(*i, span)), - AnyValue::Float32(f) => Ok(Value::float(*f as f64, span)), - AnyValue::Float64(f) => Ok(Value::float(*f, span)), - AnyValue::Date(d) => { - let nanos = nanos_per_day(*d); - datetime_from_epoch_nanos(nanos, &None, span) - .map(|datetime| Value::date(datetime, span)) - } - AnyValue::Datetime(a, time_unit, tz) => { - let nanos = nanos_from_timeunit(*a, *time_unit); - datetime_from_epoch_nanos(nanos, tz, span).map(|datetime| Value::date(datetime, span)) - } - AnyValue::Duration(a, time_unit) => { - let nanos = match time_unit { - TimeUnit::Nanoseconds => *a, - TimeUnit::Microseconds => *a * 1_000, - TimeUnit::Milliseconds => *a * 1_000_000, - }; - Ok(Value::duration(nanos, span)) - } - // AnyValue::Time represents the current time since midnight. - // Unfortunately, there is no timezone related information. - // Given this, calculate the current date from UTC and add the time. - AnyValue::Time(nanos) => time_from_midnight(*nanos, span), - AnyValue::List(series) => { - series_to_values(series, None, None, span).map(|values| Value::list(values, span)) - } - AnyValue::Struct(_idx, _struct_array, _s_fields) => { - // This should convert to a StructOwned object. - let static_value = - any_value - .clone() - .into_static() - .map_err(|e| ShellError::GenericError { - error: "Cannot convert polars struct to static value".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: Vec::new(), - })?; - any_value_to_value(&static_value, span) - } - AnyValue::StructOwned(struct_tuple) => { - let record = struct_tuple - .1 - .iter() - .zip(&struct_tuple.0) - .map(|(field, val)| { - any_value_to_value(val, span).map(|val| (field.name.to_string(), val)) - }) - .collect::>()?; - - Ok(Value::record(record, span)) - } - AnyValue::StringOwned(s) => Ok(Value::string(s.to_string(), span)), - AnyValue::Binary(bytes) => Ok(Value::binary(*bytes, span)), - AnyValue::BinaryOwned(bytes) => Ok(Value::binary(bytes.to_owned(), span)), - e => Err(ShellError::GenericError { - error: "Error creating Value".into(), - msg: "".to_string(), - span: None, - help: Some(format!("Value not supported in nushell: {e}")), - inner: Vec::new(), - }), - } -} - -fn nanos_per_day(days: i32) -> i64 { - days as i64 * NANOS_PER_DAY -} - -fn nanos_from_timeunit(a: i64, time_unit: TimeUnit) -> i64 { - a * match time_unit { - TimeUnit::Microseconds => 1_000, // Convert microseconds to nanoseconds - TimeUnit::Milliseconds => 1_000_000, // Convert milliseconds to nanoseconds - TimeUnit::Nanoseconds => 1, // Already in nanoseconds - } -} - -fn datetime_from_epoch_nanos( - nanos: i64, - timezone: &Option, - span: Span, -) -> Result, ShellError> { - let tz: Tz = if let Some(polars_tz) = timezone { - polars_tz - .parse::() - .map_err(|_| ShellError::GenericError { - error: format!("Could not parse polars timezone: {polars_tz}"), - msg: "".to_string(), - span: Some(span), - help: None, - inner: vec![], - })? - } else { - Tz::UTC - }; - - Ok(tz.timestamp_nanos(nanos).fixed_offset()) -} - -fn time_from_midnight(nanos: i64, span: Span) -> Result { - let today = Utc::now().date_naive(); - NaiveTime::from_hms_opt(0, 0, 0) // midnight - .map(|time| time + Duration::nanoseconds(nanos)) // current time - .map(|time| today.and_time(time)) // current date and time - .and_then(|datetime| { - FixedOffset::east_opt(0) // utc - .map(|offset| { - DateTime::::from_naive_utc_and_offset(datetime, offset) - }) - }) - .map(|datetime| Value::date(datetime, span)) // current date and time - .ok_or(ShellError::CantConvert { - to_type: "datetime".to_string(), - from_type: "polars time".to_string(), - span, - help: Some("Could not convert polars time of {nanos} to datetime".to_string()), - }) -} - -#[cfg(test)] -mod tests { - use indexmap::indexmap; - use nu_protocol::record; - use polars::export::arrow::array::{BooleanArray, PrimitiveArray}; - use polars::prelude::Field; - use polars_io::prelude::StructArray; - - use super::*; - - #[test] - fn test_parsed_column_string_list() -> Result<(), Box> { - let values = vec![ - Value::list( - vec![Value::string("bar".to_string(), Span::test_data())], - Span::test_data(), - ), - Value::list( - vec![Value::string("baz".to_string(), Span::test_data())], - Span::test_data(), - ), - ]; - let column = Column { - name: "foo".to_string(), - values: values.clone(), - }; - let typed_column = TypedColumn { - column, - column_type: Some(DataType::List(Box::new(DataType::String))), - }; - - let column_map = indexmap!("foo".to_string() => typed_column); - let parsed_df = from_parsed_columns(column_map)?; - let parsed_columns = parsed_df.columns(Span::test_data())?; - assert_eq!(parsed_columns.len(), 1); - let column = parsed_columns - .first() - .expect("There should be a first value in columns"); - assert_eq!(column.name(), "foo"); - assert_eq!(column.values, values); - - Ok(()) - } - - #[test] - fn test_any_value_to_value() -> Result<(), Box> { - let span = Span::test_data(); - assert_eq!( - any_value_to_value(&AnyValue::Null, span)?, - Value::nothing(span) - ); - - let test_bool = true; - assert_eq!( - any_value_to_value(&AnyValue::Boolean(test_bool), span)?, - Value::bool(test_bool, span) - ); - - let test_str = "foo"; - assert_eq!( - any_value_to_value(&AnyValue::String(test_str), span)?, - Value::string(test_str.to_string(), span) - ); - assert_eq!( - any_value_to_value(&AnyValue::StringOwned(test_str.into()), span)?, - Value::string(test_str.to_owned(), span) - ); - - let tests_uint8 = 4; - assert_eq!( - any_value_to_value(&AnyValue::UInt8(tests_uint8), span)?, - Value::int(tests_uint8 as i64, span) - ); - - let tests_uint16 = 233; - assert_eq!( - any_value_to_value(&AnyValue::UInt16(tests_uint16), span)?, - Value::int(tests_uint16 as i64, span) - ); - - let tests_uint32 = 897688233; - assert_eq!( - any_value_to_value(&AnyValue::UInt32(tests_uint32), span)?, - Value::int(tests_uint32 as i64, span) - ); - - let tests_uint64 = 903225135897388233; - assert_eq!( - any_value_to_value(&AnyValue::UInt64(tests_uint64), span)?, - Value::int(tests_uint64 as i64, span) - ); - - let tests_float32 = 903225135897388233.3223353; - assert_eq!( - any_value_to_value(&AnyValue::Float32(tests_float32), span)?, - Value::float(tests_float32 as f64, span) - ); - - let tests_float64 = 9064251358973882322333.64233533232; - assert_eq!( - any_value_to_value(&AnyValue::Float64(tests_float64), span)?, - Value::float(tests_float64, span) - ); - - let test_days = 10_957; - let comparison_date = Utc - .with_ymd_and_hms(2000, 1, 1, 0, 0, 0) - .unwrap() - .fixed_offset(); - assert_eq!( - any_value_to_value(&AnyValue::Date(test_days), span)?, - Value::date(comparison_date, span) - ); - - let test_millis = 946_684_800_000; - assert_eq!( - any_value_to_value( - &AnyValue::Datetime(test_millis, TimeUnit::Milliseconds, &None), - span - )?, - Value::date(comparison_date, span) - ); - - let test_duration_millis = 99_999; - let test_duration_micros = 99_999_000; - let test_duration_nanos = 99_999_000_000; - assert_eq!( - any_value_to_value( - &AnyValue::Duration(test_duration_nanos, TimeUnit::Nanoseconds), - span - )?, - Value::duration(test_duration_nanos, span) - ); - assert_eq!( - any_value_to_value( - &AnyValue::Duration(test_duration_micros, TimeUnit::Microseconds), - span - )?, - Value::duration(test_duration_nanos, span) - ); - assert_eq!( - any_value_to_value( - &AnyValue::Duration(test_duration_millis, TimeUnit::Milliseconds), - span - )?, - Value::duration(test_duration_nanos, span) - ); - - let test_binary = b"sdf2332f32q3f3afwaf3232f32"; - assert_eq!( - any_value_to_value(&AnyValue::Binary(test_binary), span)?, - Value::binary(test_binary.to_vec(), span) - ); - assert_eq!( - any_value_to_value(&AnyValue::BinaryOwned(test_binary.to_vec()), span)?, - Value::binary(test_binary.to_vec(), span) - ); - - let test_time_nanos = 54_000_000_000_000; - let test_time = DateTime::::from_naive_utc_and_offset( - Utc::now() - .date_naive() - .and_time(NaiveTime::from_hms_opt(15, 00, 00).unwrap()), - FixedOffset::east_opt(0).unwrap(), - ); - assert_eq!( - any_value_to_value(&AnyValue::Time(test_time_nanos), span)?, - Value::date(test_time, span) - ); - - let test_list_series = Series::new("int series", &[1, 2, 3]); - let comparison_list_series = Value::list( - vec![ - Value::int(1, span), - Value::int(2, span), - Value::int(3, span), - ], - span, - ); - assert_eq!( - any_value_to_value(&AnyValue::List(test_list_series), span)?, - comparison_list_series - ); - - let field_value_0 = AnyValue::Int32(1); - let field_value_1 = AnyValue::Boolean(true); - let values = vec![field_value_0, field_value_1]; - let field_name_0 = "num_field"; - let field_name_1 = "bool_field"; - let fields = vec![ - Field::new(field_name_0, DataType::Int32), - Field::new(field_name_1, DataType::Boolean), - ]; - let test_owned_struct = AnyValue::StructOwned(Box::new((values, fields.clone()))); - let comparison_owned_record = Value::test_record(record!( - field_name_0 => Value::int(1, span), - field_name_1 => Value::bool(true, span), - )); - assert_eq!( - any_value_to_value(&test_owned_struct, span)?, - comparison_owned_record.clone() - ); - - let test_int_arr = PrimitiveArray::from([Some(1_i32)]); - let test_bool_arr = BooleanArray::from([Some(true)]); - let test_struct_arr = StructArray::new( - DataType::Struct(fields.clone()).to_arrow(true), - vec![Box::new(test_int_arr), Box::new(test_bool_arr)], - None, - ); - assert_eq!( - any_value_to_value( - &AnyValue::Struct(0, &test_struct_arr, fields.as_slice()), - span - )?, - comparison_owned_record - ); - - Ok(()) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/custom_value.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/custom_value.rs deleted file mode 100644 index da8b27398b..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/custom_value.rs +++ /dev/null @@ -1,79 +0,0 @@ -use super::NuDataFrame; -use nu_protocol::{ast::Operator, CustomValue, ShellError, Span, Value}; - -// CustomValue implementation for NuDataFrame -impl CustomValue for NuDataFrame { - fn typetag_name(&self) -> &'static str { - "dataframe" - } - - fn typetag_deserialize(&self) { - unimplemented!("typetag_deserialize") - } - - fn clone_value(&self, span: nu_protocol::Span) -> Value { - let cloned = NuDataFrame { - df: self.df.clone(), - from_lazy: false, - }; - - Value::custom(Box::new(cloned), span) - } - - fn type_name(&self) -> String { - self.typetag_name().to_string() - } - - fn to_base_value(&self, span: Span) -> Result { - let vals = self.print(span)?; - - Ok(Value::list(vals, span)) - } - - fn as_any(&self) -> &dyn std::any::Any { - self - } - - fn as_mut_any(&mut self) -> &mut dyn std::any::Any { - self - } - - fn follow_path_int( - &self, - _self_span: Span, - count: usize, - path_span: Span, - ) -> Result { - self.get_value(count, path_span) - } - - fn follow_path_string( - &self, - _self_span: Span, - column_name: String, - path_span: Span, - ) -> Result { - let column = self.column(&column_name, path_span)?; - Ok(column.into_value(path_span)) - } - - fn partial_cmp(&self, other: &Value) -> Option { - match other { - Value::Custom { val, .. } => val - .as_any() - .downcast_ref::() - .and_then(|other| self.is_equal(other)), - _ => None, - } - } - - fn operation( - &self, - lhs_span: Span, - operator: Operator, - op: Span, - right: &Value, - ) -> Result { - self.compute_with_value(lhs_span, operator, op, right) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/mod.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/mod.rs deleted file mode 100644 index 967e03580f..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/mod.rs +++ /dev/null @@ -1,580 +0,0 @@ -mod between_values; -mod conversion; -mod custom_value; -mod operations; - -pub use conversion::{Column, ColumnMap}; -pub use operations::Axis; - -use super::{nu_schema::NuSchema, utils::DEFAULT_ROWS, NuLazyFrame}; -use indexmap::IndexMap; -use nu_protocol::{did_you_mean, PipelineData, Record, ShellError, Span, Value}; -use polars::{ - chunked_array::ops::SortMultipleOptions, - prelude::{DataFrame, DataType, IntoLazy, LazyFrame, PolarsObject, Series}, -}; -use polars_plan::prelude::{lit, Expr, Null}; -use polars_utils::total_ord::{TotalEq, TotalHash}; -use serde::{Deserialize, Serialize}; -use std::{ - cmp::Ordering, - collections::HashSet, - fmt::Display, - hash::{Hash, Hasher}, -}; - -// DataFrameValue is an encapsulation of Nushell Value that can be used -// to define the PolarsObject Trait. The polars object trait allows to -// create dataframes with mixed datatypes -#[derive(Clone, Debug)] -pub struct DataFrameValue(Value); - -impl DataFrameValue { - fn new(value: Value) -> Self { - Self(value) - } - - fn get_value(&self) -> Value { - self.0.clone() - } -} - -impl TotalHash for DataFrameValue { - fn tot_hash(&self, state: &mut H) - where - H: Hasher, - { - (*self).hash(state) - } -} - -impl Display for DataFrameValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0.get_type()) - } -} - -impl Default for DataFrameValue { - fn default() -> Self { - Self(Value::nothing(Span::unknown())) - } -} - -impl PartialEq for DataFrameValue { - fn eq(&self, other: &Self) -> bool { - self.0.partial_cmp(&other.0).map_or(false, Ordering::is_eq) - } -} -impl Eq for DataFrameValue {} - -impl Hash for DataFrameValue { - fn hash(&self, state: &mut H) { - match &self.0 { - Value::Nothing { .. } => 0.hash(state), - Value::Int { val, .. } => val.hash(state), - Value::String { val, .. } => val.hash(state), - // TODO. Define hash for the rest of types - _ => {} - } - } -} - -impl TotalEq for DataFrameValue { - fn tot_eq(&self, other: &Self) -> bool { - self == other - } -} - -impl PolarsObject for DataFrameValue { - fn type_name() -> &'static str { - "object" - } -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct NuDataFrame { - pub df: DataFrame, - pub from_lazy: bool, -} - -impl AsRef for NuDataFrame { - fn as_ref(&self) -> &polars::prelude::DataFrame { - &self.df - } -} - -impl AsMut for NuDataFrame { - fn as_mut(&mut self) -> &mut polars::prelude::DataFrame { - &mut self.df - } -} - -impl From for NuDataFrame { - fn from(df: DataFrame) -> Self { - Self { - df, - from_lazy: false, - } - } -} - -impl NuDataFrame { - pub fn new(from_lazy: bool, df: DataFrame) -> Self { - Self { df, from_lazy } - } - - pub fn lazy(&self) -> LazyFrame { - self.df.clone().lazy() - } - - fn default_value(span: Span) -> Value { - let dataframe = DataFrame::default(); - NuDataFrame::dataframe_into_value(dataframe, span) - } - - pub fn dataframe_into_value(dataframe: DataFrame, span: Span) -> Value { - Value::custom(Box::new(Self::new(false, dataframe)), span) - } - - pub fn into_value(self, span: Span) -> Value { - if self.from_lazy { - let lazy = NuLazyFrame::from_dataframe(self); - Value::custom(Box::new(lazy), span) - } else { - Value::custom(Box::new(self), span) - } - } - - pub fn series_to_value(series: Series, span: Span) -> Result { - match DataFrame::new(vec![series]) { - Ok(dataframe) => Ok(NuDataFrame::dataframe_into_value(dataframe, span)), - Err(e) => Err(ShellError::GenericError { - error: "Error creating dataframe".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - }), - } - } - - pub fn try_from_iter(iter: T, maybe_schema: Option) -> Result - where - T: Iterator, - { - // Dictionary to store the columnar data extracted from - // the input. During the iteration we check if the values - // have different type - let mut column_values: ColumnMap = IndexMap::new(); - - for value in iter { - match value { - Value::Custom { .. } => return Self::try_from_value(value), - Value::List { vals, .. } => { - let record = vals - .into_iter() - .enumerate() - .map(|(i, val)| (format!("{i}"), val)) - .collect(); - - conversion::insert_record(&mut column_values, record, &maybe_schema)? - } - Value::Record { val: record, .. } => conversion::insert_record( - &mut column_values, - record.into_owned(), - &maybe_schema, - )?, - _ => { - let key = "0".to_string(); - conversion::insert_value(value, key, &mut column_values, &maybe_schema)? - } - } - } - - let df = conversion::from_parsed_columns(column_values)?; - add_missing_columns(df, &maybe_schema, Span::unknown()) - } - - pub fn try_from_series(columns: Vec, span: Span) -> Result { - let dataframe = DataFrame::new(columns).map_err(|e| ShellError::GenericError { - error: "Error creating dataframe".into(), - msg: format!("Unable to create DataFrame: {e}"), - span: Some(span), - help: None, - inner: vec![], - })?; - - Ok(Self::new(false, dataframe)) - } - - pub fn try_from_columns( - columns: Vec, - maybe_schema: Option, - ) -> Result { - let mut column_values: ColumnMap = IndexMap::new(); - - for column in columns { - let name = column.name().to_string(); - for value in column { - conversion::insert_value(value, name.clone(), &mut column_values, &maybe_schema)?; - } - } - - let df = conversion::from_parsed_columns(column_values)?; - add_missing_columns(df, &maybe_schema, Span::unknown()) - } - - pub fn fill_list_nan(list: Vec, list_span: Span, fill: Value) -> Value { - let newlist = list - .into_iter() - .map(|value| { - let span = value.span(); - match value { - Value::Float { val, .. } => { - if val.is_nan() { - fill.clone() - } else { - value - } - } - Value::List { vals, .. } => Self::fill_list_nan(vals, span, fill.clone()), - _ => value, - } - }) - .collect::>(); - Value::list(newlist, list_span) - } - - pub fn columns(&self, span: Span) -> Result, ShellError> { - let height = self.df.height(); - self.df - .get_columns() - .iter() - .map(|col| conversion::create_column(col, 0, height, span)) - .collect::, ShellError>>() - } - - pub fn try_from_value(value: Value) -> Result { - if Self::can_downcast(&value) { - Ok(Self::get_df(value)?) - } else if NuLazyFrame::can_downcast(&value) { - let span = value.span(); - let lazy = NuLazyFrame::try_from_value(value)?; - let df = lazy.collect(span)?; - Ok(df) - } else { - Err(ShellError::CantConvert { - to_type: "lazy or eager dataframe".into(), - from_type: value.get_type().to_string(), - span: value.span(), - help: None, - }) - } - } - - pub fn get_df(value: Value) -> Result { - let span = value.span(); - match value { - Value::Custom { val, .. } => match val.as_any().downcast_ref::() { - Some(df) => Ok(NuDataFrame { - df: df.df.clone(), - from_lazy: false, - }), - None => Err(ShellError::CantConvert { - to_type: "dataframe".into(), - from_type: "non-dataframe".into(), - span, - help: None, - }), - }, - x => Err(ShellError::CantConvert { - to_type: "dataframe".into(), - from_type: x.get_type().to_string(), - span: x.span(), - help: None, - }), - } - } - - pub fn try_from_pipeline(input: PipelineData, span: Span) -> Result { - let value = input.into_value(span)?; - Self::try_from_value(value) - } - - pub fn can_downcast(value: &Value) -> bool { - if let Value::Custom { val, .. } = value { - val.as_any().downcast_ref::().is_some() - } else { - false - } - } - - pub fn column(&self, column: &str, span: Span) -> Result { - let s = self.df.column(column).map_err(|_| { - let possibilities = self - .df - .get_column_names() - .iter() - .map(|name| name.to_string()) - .collect::>(); - - let option = did_you_mean(&possibilities, column).unwrap_or_else(|| column.to_string()); - ShellError::DidYouMean { - suggestion: option, - span, - } - })?; - - let df = DataFrame::new(vec![s.clone()]).map_err(|e| ShellError::GenericError { - error: "Error creating dataframe".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - })?; - - Ok(Self { - df, - from_lazy: false, - }) - } - - pub fn is_series(&self) -> bool { - self.df.width() == 1 - } - - pub fn as_series(&self, span: Span) -> Result { - if !self.is_series() { - return Err(ShellError::GenericError { - error: "Error using as series".into(), - msg: "dataframe has more than one column".into(), - span: Some(span), - help: None, - inner: vec![], - }); - } - - let series = self - .df - .get_columns() - .first() - .expect("We have already checked that the width is 1"); - - Ok(series.clone()) - } - - pub fn get_value(&self, row: usize, span: Span) -> Result { - let series = self.as_series(span)?; - let column = conversion::create_column(&series, row, row + 1, span)?; - - if column.len() == 0 { - Err(ShellError::AccessEmptyContent { span }) - } else { - let value = column - .into_iter() - .next() - .expect("already checked there is a value"); - Ok(value) - } - } - - // Print is made out a head and if the dataframe is too large, then a tail - pub fn print(&self, span: Span) -> Result, ShellError> { - let df = &self.df; - let size: usize = 20; - - if df.height() > size { - let sample_size = size / 2; - let mut values = self.head(Some(sample_size), span)?; - conversion::add_separator(&mut values, df, span); - let remaining = df.height() - sample_size; - let tail_size = remaining.min(sample_size); - let mut tail_values = self.tail(Some(tail_size), span)?; - values.append(&mut tail_values); - - Ok(values) - } else { - Ok(self.head(Some(size), span)?) - } - } - - pub fn height(&self) -> usize { - self.df.height() - } - - pub fn head(&self, rows: Option, span: Span) -> Result, ShellError> { - let to_row = rows.unwrap_or(5); - let values = self.to_rows(0, to_row, span)?; - - Ok(values) - } - - pub fn tail(&self, rows: Option, span: Span) -> Result, ShellError> { - let df = &self.df; - let to_row = df.height(); - let size = rows.unwrap_or(DEFAULT_ROWS); - let from_row = to_row.saturating_sub(size); - - let values = self.to_rows(from_row, to_row, span)?; - - Ok(values) - } - - pub fn to_rows( - &self, - from_row: usize, - to_row: usize, - span: Span, - ) -> Result, ShellError> { - let df = &self.df; - let upper_row = to_row.min(df.height()); - - let mut size: usize = 0; - let columns = self - .df - .get_columns() - .iter() - .map( - |col| match conversion::create_column(col, from_row, upper_row, span) { - Ok(col) => { - size = col.len(); - Ok(col) - } - Err(e) => Err(e), - }, - ) - .collect::, ShellError>>()?; - - let mut iterators = columns - .into_iter() - .map(|col| (col.name().to_string(), col.into_iter())) - .collect::)>>(); - - let values = (0..size) - .map(|i| { - let mut record = Record::new(); - - record.push("index", Value::int((i + from_row) as i64, span)); - - for (name, col) in &mut iterators { - record.push(name.clone(), col.next().unwrap_or(Value::nothing(span))); - } - - Value::record(record, span) - }) - .collect::>(); - - Ok(values) - } - - // Dataframes are considered equal if they have the same shape, column name and values - pub fn is_equal(&self, other: &Self) -> Option { - if self.as_ref().width() == 0 { - // checking for empty dataframe - return None; - } - - if self.as_ref().get_column_names() != other.as_ref().get_column_names() { - // checking both dataframes share the same names - return None; - } - - if self.as_ref().height() != other.as_ref().height() { - // checking both dataframes have the same row size - return None; - } - - // sorting dataframe by the first column - let column_names = self.as_ref().get_column_names(); - let first_col = column_names - .first() - .expect("already checked that dataframe is different than 0"); - - // if unable to sort, then unable to compare - let lhs = match self - .as_ref() - .sort(vec![*first_col], SortMultipleOptions::default()) - { - Ok(df) => df, - Err(_) => return None, - }; - - let rhs = match other - .as_ref() - .sort(vec![*first_col], SortMultipleOptions::default()) - { - Ok(df) => df, - Err(_) => return None, - }; - - for name in self.as_ref().get_column_names() { - let self_series = lhs.column(name).expect("name from dataframe names"); - - let other_series = rhs - .column(name) - .expect("already checked that name in other"); - - let self_series = match self_series.dtype() { - // Casting needed to compare other numeric types with nushell numeric type. - // In nushell we only have i64 integer numeric types and any array created - // with nushell untagged primitives will be of type i64 - DataType::UInt32 | DataType::Int32 => match self_series.cast(&DataType::Int64) { - Ok(series) => series, - Err(_) => return None, - }, - _ => self_series.clone(), - }; - - if !self_series.equals(other_series) { - return None; - } - } - - Some(Ordering::Equal) - } - - pub fn schema(&self) -> NuSchema { - NuSchema::new(self.df.schema()) - } -} - -fn add_missing_columns( - df: NuDataFrame, - maybe_schema: &Option, - span: Span, -) -> Result { - // If there are fields that are in the schema, but not in the dataframe - // add them to the dataframe. - if let Some(schema) = maybe_schema { - let fields = df.df.fields(); - let df_field_names: HashSet<&str> = fields.iter().map(|f| f.name().as_str()).collect(); - - let missing: Vec<(&str, &DataType)> = schema - .schema - .iter() - .filter_map(|(name, dtype)| { - let name = name.as_str(); - if !df_field_names.contains(name) { - Some((name, dtype)) - } else { - None - } - }) - .collect(); - - let missing_exprs: Vec = missing - .iter() - .map(|(name, dtype)| lit(Null {}).cast((*dtype).to_owned()).alias(name)) - .collect(); - - let df = if !missing.is_empty() { - let with_columns = df.lazy().with_columns(missing_exprs); - NuLazyFrame::new(true, with_columns).collect(span)? - } else { - df - }; - Ok(df) - } else { - Ok(df) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/operations.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/operations.rs deleted file mode 100644 index ff2f7b7604..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_dataframe/operations.rs +++ /dev/null @@ -1,206 +0,0 @@ -use super::{ - between_values::{between_dataframes, compute_between_series, compute_series_single_value}, - NuDataFrame, -}; -use nu_protocol::{ast::Operator, ShellError, Span, Spanned, Value}; -use polars::prelude::{DataFrame, Series}; - -pub enum Axis { - Row, - Column, -} - -impl NuDataFrame { - pub fn compute_with_value( - &self, - lhs_span: Span, - operator: Operator, - op_span: Span, - right: &Value, - ) -> Result { - let rhs_span = right.span(); - match right { - Value::Custom { val: rhs, .. } => { - let rhs = rhs.as_any().downcast_ref::().ok_or_else(|| { - ShellError::DowncastNotPossible { - msg: "Unable to create dataframe".to_string(), - span: rhs_span, - } - })?; - - match (self.is_series(), rhs.is_series()) { - (true, true) => { - let lhs = &self - .as_series(lhs_span) - .expect("Already checked that is a series"); - let rhs = &rhs - .as_series(rhs_span) - .expect("Already checked that is a series"); - - if lhs.dtype() != rhs.dtype() { - return Err(ShellError::IncompatibleParameters { - left_message: format!("datatype {}", lhs.dtype()), - left_span: lhs_span, - right_message: format!("datatype {}", lhs.dtype()), - right_span: rhs_span, - }); - } - - if lhs.len() != rhs.len() { - return Err(ShellError::IncompatibleParameters { - left_message: format!("len {}", lhs.len()), - left_span: lhs_span, - right_message: format!("len {}", rhs.len()), - right_span: rhs_span, - }); - } - - let op = Spanned { - item: operator, - span: op_span, - }; - - compute_between_series( - op, - &NuDataFrame::default_value(lhs_span), - lhs, - right, - rhs, - ) - } - _ => { - if self.df.height() != rhs.df.height() { - return Err(ShellError::IncompatibleParameters { - left_message: format!("rows {}", self.df.height()), - left_span: lhs_span, - right_message: format!("rows {}", rhs.df.height()), - right_span: rhs_span, - }); - } - - let op = Spanned { - item: operator, - span: op_span, - }; - - between_dataframes( - op, - &NuDataFrame::default_value(lhs_span), - self, - right, - rhs, - ) - } - } - } - _ => { - let op = Spanned { - item: operator, - span: op_span, - }; - - compute_series_single_value(op, &NuDataFrame::default_value(lhs_span), self, right) - } - } - } - - pub fn append_df( - &self, - other: &NuDataFrame, - axis: Axis, - span: Span, - ) -> Result { - match axis { - Axis::Row => { - let mut columns: Vec<&str> = Vec::new(); - - let new_cols = self - .df - .get_columns() - .iter() - .chain(other.df.get_columns()) - .map(|s| { - let name = if columns.contains(&s.name()) { - format!("{}_{}", s.name(), "x") - } else { - columns.push(s.name()); - s.name().to_string() - }; - - let mut series = s.clone(); - series.rename(&name); - series - }) - .collect::>(); - - let df_new = DataFrame::new(new_cols).map_err(|e| ShellError::GenericError { - error: "Error creating dataframe".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - })?; - - Ok(NuDataFrame::new(false, df_new)) - } - Axis::Column => { - if self.df.width() != other.df.width() { - return Err(ShellError::IncompatibleParametersSingle { - msg: "Dataframes with different number of columns".into(), - span, - }); - } - - if !self - .df - .get_column_names() - .iter() - .all(|col| other.df.get_column_names().contains(col)) - { - return Err(ShellError::IncompatibleParametersSingle { - msg: "Dataframes with different columns names".into(), - span, - }); - } - - let new_cols = self - .df - .get_columns() - .iter() - .map(|s| { - let other_col = other - .df - .column(s.name()) - .expect("Already checked that dataframes have same columns"); - - let mut tmp = s.clone(); - let res = tmp.append(other_col); - - match res { - Ok(s) => Ok(s.clone()), - Err(e) => Err({ - ShellError::GenericError { - error: "Error appending dataframe".into(), - msg: format!("Unable to append: {e}"), - span: Some(span), - help: None, - inner: vec![], - } - }), - } - }) - .collect::, ShellError>>()?; - - let df_new = DataFrame::new(new_cols).map_err(|e| ShellError::GenericError { - error: "Error appending dataframe".into(), - msg: format!("Unable to append dataframes: {e}"), - span: Some(span), - help: None, - inner: vec![], - })?; - - Ok(NuDataFrame::new(false, df_new)) - } - } - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_expression/custom_value.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_expression/custom_value.rs deleted file mode 100644 index 7a7f59e648..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_expression/custom_value.rs +++ /dev/null @@ -1,147 +0,0 @@ -use super::NuExpression; -use nu_protocol::{ - ast::{Comparison, Math, Operator}, - CustomValue, ShellError, Span, Type, Value, -}; -use polars::prelude::Expr; -use std::ops::{Add, Div, Mul, Rem, Sub}; - -// CustomValue implementation for NuDataFrame -impl CustomValue for NuExpression { - fn typetag_name(&self) -> &'static str { - "expression" - } - - fn typetag_deserialize(&self) { - unimplemented!("typetag_deserialize") - } - - fn clone_value(&self, span: nu_protocol::Span) -> Value { - let cloned = NuExpression(self.0.clone()); - - Value::custom(Box::new(cloned), span) - } - - fn type_name(&self) -> String { - self.typetag_name().to_string() - } - - fn to_base_value(&self, span: Span) -> Result { - self.to_value(span) - } - - fn as_any(&self) -> &dyn std::any::Any { - self - } - - fn as_mut_any(&mut self) -> &mut dyn std::any::Any { - self - } - - fn operation( - &self, - lhs_span: Span, - operator: Operator, - op: Span, - right: &Value, - ) -> Result { - compute_with_value(self, lhs_span, operator, op, right) - } -} - -fn compute_with_value( - left: &NuExpression, - lhs_span: Span, - operator: Operator, - op: Span, - right: &Value, -) -> Result { - let rhs_span = right.span(); - match right { - Value::Custom { val: rhs, .. } => { - let rhs = rhs.as_any().downcast_ref::().ok_or_else(|| { - ShellError::DowncastNotPossible { - msg: "Unable to create expression".into(), - span: rhs_span, - } - })?; - - match rhs.as_ref() { - polars::prelude::Expr::Literal(..) => { - with_operator(operator, left, rhs, lhs_span, right.span(), op) - } - _ => Err(ShellError::TypeMismatch { - err_message: "Only literal expressions or number".into(), - span: right.span(), - }), - } - } - _ => { - let rhs = NuExpression::try_from_value(right.clone())?; - with_operator(operator, left, &rhs, lhs_span, right.span(), op) - } - } -} - -fn with_operator( - operator: Operator, - left: &NuExpression, - right: &NuExpression, - lhs_span: Span, - rhs_span: Span, - op_span: Span, -) -> Result { - match operator { - Operator::Math(Math::Plus) => apply_arithmetic(left, right, lhs_span, Add::add), - Operator::Math(Math::Minus) => apply_arithmetic(left, right, lhs_span, Sub::sub), - Operator::Math(Math::Multiply) => apply_arithmetic(left, right, lhs_span, Mul::mul), - Operator::Math(Math::Divide) => apply_arithmetic(left, right, lhs_span, Div::div), - Operator::Math(Math::Modulo) => apply_arithmetic(left, right, lhs_span, Rem::rem), - Operator::Math(Math::FloorDivision) => apply_arithmetic(left, right, lhs_span, Div::div), - Operator::Comparison(Comparison::Equal) => Ok(left - .clone() - .apply_with_expr(right.clone(), Expr::eq) - .into_value(lhs_span)), - Operator::Comparison(Comparison::NotEqual) => Ok(left - .clone() - .apply_with_expr(right.clone(), Expr::neq) - .into_value(lhs_span)), - Operator::Comparison(Comparison::GreaterThan) => Ok(left - .clone() - .apply_with_expr(right.clone(), Expr::gt) - .into_value(lhs_span)), - Operator::Comparison(Comparison::GreaterThanOrEqual) => Ok(left - .clone() - .apply_with_expr(right.clone(), Expr::gt_eq) - .into_value(lhs_span)), - Operator::Comparison(Comparison::LessThan) => Ok(left - .clone() - .apply_with_expr(right.clone(), Expr::lt) - .into_value(lhs_span)), - Operator::Comparison(Comparison::LessThanOrEqual) => Ok(left - .clone() - .apply_with_expr(right.clone(), Expr::lt_eq) - .into_value(lhs_span)), - _ => Err(ShellError::OperatorMismatch { - op_span, - lhs_ty: Type::Custom(left.typetag_name().into()).to_string(), - lhs_span, - rhs_ty: Type::Custom(right.typetag_name().into()).to_string(), - rhs_span, - }), - } -} - -fn apply_arithmetic( - left: &NuExpression, - right: &NuExpression, - span: Span, - f: F, -) -> Result -where - F: Fn(Expr, Expr) -> Expr, -{ - let expr: NuExpression = f(left.as_ref().clone(), right.as_ref().clone()).into(); - - Ok(expr.into_value(span)) -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_expression/mod.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_expression/mod.rs deleted file mode 100644 index cee31d7b53..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_expression/mod.rs +++ /dev/null @@ -1,443 +0,0 @@ -mod custom_value; - -use nu_protocol::{record, PipelineData, ShellError, Span, Value}; -use polars::prelude::{col, AggExpr, Expr, Literal}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -// Polars Expression wrapper for Nushell operations -// Object is behind and Option to allow easy implementation of -// the Deserialize trait -#[derive(Default, Clone, Debug)] -pub struct NuExpression(Option); - -// Mocked serialization of the LazyFrame object -impl Serialize for NuExpression { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_none() - } -} - -// Mocked deserialization of the LazyFrame object -impl<'de> Deserialize<'de> for NuExpression { - fn deserialize(_deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Ok(NuExpression::default()) - } -} - -// Referenced access to the real LazyFrame -impl AsRef for NuExpression { - fn as_ref(&self) -> &polars::prelude::Expr { - // The only case when there cannot be an expr is if it is created - // using the default function or if created by deserializing something - self.0.as_ref().expect("there should always be a frame") - } -} - -impl AsMut for NuExpression { - fn as_mut(&mut self) -> &mut polars::prelude::Expr { - // The only case when there cannot be an expr is if it is created - // using the default function or if created by deserializing something - self.0.as_mut().expect("there should always be a frame") - } -} - -impl From for NuExpression { - fn from(expr: Expr) -> Self { - Self(Some(expr)) - } -} - -impl NuExpression { - pub fn into_value(self, span: Span) -> Value { - Value::custom(Box::new(self), span) - } - - pub fn try_from_value(value: Value) -> Result { - let span = value.span(); - match value { - Value::Custom { val, .. } => match val.as_any().downcast_ref::() { - Some(expr) => Ok(NuExpression(expr.0.clone())), - None => Err(ShellError::CantConvert { - to_type: "lazy expression".into(), - from_type: "non-dataframe".into(), - span, - help: None, - }), - }, - Value::String { val, .. } => Ok(val.lit().into()), - Value::Int { val, .. } => Ok(val.lit().into()), - Value::Bool { val, .. } => Ok(val.lit().into()), - Value::Float { val, .. } => Ok(val.lit().into()), - x => Err(ShellError::CantConvert { - to_type: "lazy expression".into(), - from_type: x.get_type().to_string(), - span: x.span(), - help: None, - }), - } - } - - pub fn try_from_pipeline(input: PipelineData, span: Span) -> Result { - let value = input.into_value(span)?; - Self::try_from_value(value) - } - - pub fn can_downcast(value: &Value) -> bool { - match value { - Value::Custom { val, .. } => val.as_any().downcast_ref::().is_some(), - Value::List { vals, .. } => vals.iter().all(Self::can_downcast), - Value::String { .. } | Value::Int { .. } | Value::Bool { .. } | Value::Float { .. } => { - true - } - _ => false, - } - } - - pub fn into_polars(self) -> Expr { - self.0.expect("Expression cannot be none to convert") - } - - pub fn apply_with_expr(self, other: NuExpression, f: F) -> Self - where - F: Fn(Expr, Expr) -> Expr, - { - let expr = self.0.expect("Lazy expression must not be empty to apply"); - let other = other.0.expect("Lazy expression must not be empty to apply"); - - f(expr, other).into() - } - - pub fn to_value(&self, span: Span) -> Result { - expr_to_value(self.as_ref(), span) - } - - // Convenient function to extract multiple Expr that could be inside a nushell Value - pub fn extract_exprs(value: Value) -> Result, ShellError> { - ExtractedExpr::extract_exprs(value).map(ExtractedExpr::into_exprs) - } -} - -#[derive(Debug)] -// Enum to represent the parsing of the expressions from Value -enum ExtractedExpr { - Single(Expr), - List(Vec), -} - -impl ExtractedExpr { - fn into_exprs(self) -> Vec { - match self { - Self::Single(expr) => vec![expr], - Self::List(expressions) => expressions - .into_iter() - .flat_map(ExtractedExpr::into_exprs) - .collect(), - } - } - - fn extract_exprs(value: Value) -> Result { - match value { - Value::String { val, .. } => Ok(ExtractedExpr::Single(col(val.as_str()))), - Value::Custom { .. } => NuExpression::try_from_value(value) - .map(NuExpression::into_polars) - .map(ExtractedExpr::Single), - Value::List { vals, .. } => vals - .into_iter() - .map(Self::extract_exprs) - .collect::, ShellError>>() - .map(ExtractedExpr::List), - x => Err(ShellError::CantConvert { - to_type: "expression".into(), - from_type: x.get_type().to_string(), - span: x.span(), - help: None, - }), - } - } -} - -pub fn expr_to_value(expr: &Expr, span: Span) -> Result { - match expr { - Expr::Alias(expr, alias) => Ok(Value::record( - record! { - "expr" => expr_to_value(expr.as_ref(), span)?, - "alias" => Value::string(alias.as_ref(), span), - }, - span, - )), - Expr::Column(name) => Ok(Value::record( - record! { - "expr" => Value::string("column", span), - "value" => Value::string(name.to_string(), span), - }, - span, - )), - Expr::Columns(columns) => { - let value = columns.iter().map(|col| Value::string(col, span)).collect(); - Ok(Value::record( - record! { - "expr" => Value::string("columns", span), - "value" => Value::list(value, span), - }, - span, - )) - } - Expr::Literal(literal) => Ok(Value::record( - record! { - "expr" => Value::string("literal", span), - "value" => Value::string(format!("{literal:?}"), span), - }, - span, - )), - Expr::BinaryExpr { left, op, right } => Ok(Value::record( - record! { - "left" => expr_to_value(left, span)?, - "op" => Value::string(format!("{op:?}"), span), - "right" => expr_to_value(right, span)?, - }, - span, - )), - Expr::Ternary { - predicate, - truthy, - falsy, - } => Ok(Value::record( - record! { - "predicate" => expr_to_value(predicate.as_ref(), span)?, - "truthy" => expr_to_value(truthy.as_ref(), span)?, - "falsy" => expr_to_value(falsy.as_ref(), span)?, - }, - span, - )), - Expr::Agg(agg_expr) => { - let value = match agg_expr { - AggExpr::Min { input: expr, .. } - | AggExpr::Max { input: expr, .. } - | AggExpr::Median(expr) - | AggExpr::NUnique(expr) - | AggExpr::First(expr) - | AggExpr::Last(expr) - | AggExpr::Mean(expr) - | AggExpr::Implode(expr) - | AggExpr::Count(expr, _) - | AggExpr::Sum(expr) - | AggExpr::AggGroups(expr) - | AggExpr::Std(expr, _) - | AggExpr::Var(expr, _) => expr_to_value(expr.as_ref(), span), - AggExpr::Quantile { - expr, - quantile, - interpol, - } => Ok(Value::record( - record! { - "expr" => expr_to_value(expr.as_ref(), span)?, - "quantile" => expr_to_value(quantile.as_ref(), span)?, - "interpol" => Value::string(format!("{interpol:?}"), span), - }, - span, - )), - }; - - Ok(Value::record( - record! { - "expr" => Value::string("agg", span), - "value" => value?, - }, - span, - )) - } - Expr::Len => Ok(Value::record( - record! { "expr" => Value::string("count", span) }, - span, - )), - Expr::Wildcard => Ok(Value::record( - record! { "expr" => Value::string("wildcard", span) }, - span, - )), - Expr::Explode(expr) => Ok(Value::record( - record! { "expr" => expr_to_value(expr.as_ref(), span)? }, - span, - )), - Expr::KeepName(expr) => Ok(Value::record( - record! { "expr" => expr_to_value(expr.as_ref(), span)? }, - span, - )), - Expr::Nth(i) => Ok(Value::record( - record! { "expr" => Value::int(*i, span) }, - span, - )), - Expr::DtypeColumn(dtypes) => { - let vals = dtypes - .iter() - .map(|d| Value::string(format!("{d}"), span)) - .collect(); - - Ok(Value::list(vals, span)) - } - Expr::Sort { expr, options } => Ok(Value::record( - record! { - "expr" => expr_to_value(expr.as_ref(), span)?, - "options" => Value::string(format!("{options:?}"), span), - }, - span, - )), - Expr::Cast { - expr, - data_type, - strict, - } => Ok(Value::record( - record! { - "expr" => expr_to_value(expr.as_ref(), span)?, - "dtype" => Value::string(format!("{data_type:?}"), span), - "strict" => Value::bool(*strict, span), - }, - span, - )), - Expr::Gather { - expr, - idx, - returns_scalar: _, - } => Ok(Value::record( - record! { - "expr" => expr_to_value(expr.as_ref(), span)?, - "idx" => expr_to_value(idx.as_ref(), span)?, - }, - span, - )), - Expr::SortBy { - expr, - by, - sort_options, - } => { - let by: Result, ShellError> = - by.iter().map(|b| expr_to_value(b, span)).collect(); - let descending: Vec = sort_options - .descending - .iter() - .map(|r| Value::bool(*r, span)) - .collect(); - - Ok(Value::record( - record! { - "expr" => expr_to_value(expr.as_ref(), span)?, - "by" => Value::list(by?, span), - "descending" => Value::list(descending, span), - }, - span, - )) - } - Expr::Filter { input, by } => Ok(Value::record( - record! { - "input" => expr_to_value(input.as_ref(), span)?, - "by" => expr_to_value(by.as_ref(), span)?, - }, - span, - )), - Expr::Slice { - input, - offset, - length, - } => Ok(Value::record( - record! { - "input" => expr_to_value(input.as_ref(), span)?, - "offset" => expr_to_value(offset.as_ref(), span)?, - "length" => expr_to_value(length.as_ref(), span)?, - }, - span, - )), - Expr::Exclude(expr, excluded) => { - let excluded = excluded - .iter() - .map(|e| Value::string(format!("{e:?}"), span)) - .collect(); - - Ok(Value::record( - record! { - "expr" => expr_to_value(expr.as_ref(), span)?, - "excluded" => Value::list(excluded, span), - }, - span, - )) - } - Expr::RenameAlias { expr, function } => Ok(Value::record( - record! { - "expr" => expr_to_value(expr.as_ref(), span)?, - "function" => Value::string(format!("{function:?}"), span), - }, - span, - )), - Expr::AnonymousFunction { - input, - function, - output_type, - options, - } => { - let input: Result, ShellError> = - input.iter().map(|e| expr_to_value(e, span)).collect(); - Ok(Value::record( - record! { - "input" => Value::list(input?, span), - "function" => Value::string(format!("{function:?}"), span), - "output_type" => Value::string(format!("{output_type:?}"), span), - "options" => Value::string(format!("{options:?}"), span), - }, - span, - )) - } - Expr::Function { - input, - function, - options, - } => { - let input: Result, ShellError> = - input.iter().map(|e| expr_to_value(e, span)).collect(); - Ok(Value::record( - record! { - "input" => Value::list(input?, span), - "function" => Value::string(format!("{function:?}"), span), - "options" => Value::string(format!("{options:?}"), span), - }, - span, - )) - } - Expr::Window { - function, - partition_by, - options, - } => { - let partition_by: Result, ShellError> = partition_by - .iter() - .map(|e| expr_to_value(e, span)) - .collect(); - - Ok(Value::record( - record! { - "function" => expr_to_value(function, span)?, - "partition_by" => Value::list(partition_by?, span), - "options" => Value::string(format!("{options:?}"), span), - }, - span, - )) - } - Expr::SubPlan(_, _) => Err(ShellError::UnsupportedInput { - msg: "Expressions of type SubPlan are not yet supported".to_string(), - input: format!("Expression is {expr:?}"), - msg_span: span, - input_span: Span::unknown(), - }), - // the parameter polars_plan::dsl::selector::Selector is not publicly exposed. - // I am not sure what we can meaningfully do with this at this time. - Expr::Selector(_) => Err(ShellError::UnsupportedInput { - msg: "Expressions of type Selector to Nu Values is not yet supported".to_string(), - input: format!("Expression is {expr:?}"), - msg_span: span, - input_span: Span::unknown(), - }), - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_lazyframe/custom_value.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_lazyframe/custom_value.rs deleted file mode 100644 index f747ae4d18..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_lazyframe/custom_value.rs +++ /dev/null @@ -1,50 +0,0 @@ -use super::NuLazyFrame; -use nu_protocol::{record, CustomValue, ShellError, Span, Value}; - -// CustomValue implementation for NuDataFrame -impl CustomValue for NuLazyFrame { - fn typetag_name(&self) -> &'static str { - "lazyframe" - } - - fn typetag_deserialize(&self) { - unimplemented!("typetag_deserialize") - } - - fn clone_value(&self, span: nu_protocol::Span) -> Value { - let cloned = NuLazyFrame { - lazy: self.lazy.clone(), - from_eager: self.from_eager, - schema: self.schema.clone(), - }; - - Value::custom(Box::new(cloned), span) - } - - fn type_name(&self) -> String { - self.typetag_name().to_string() - } - - fn to_base_value(&self, span: Span) -> Result { - let optimized_plan = self - .as_ref() - .describe_optimized_plan() - .unwrap_or_else(|_| "".to_string()); - - Ok(Value::record( - record! { - "plan" => Value::string(self.as_ref().describe_plan(), span), - "optimized_plan" => Value::string(optimized_plan, span), - }, - span, - )) - } - - fn as_any(&self) -> &dyn std::any::Any { - self - } - - fn as_mut_any(&mut self) -> &mut dyn std::any::Any { - self - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_lazyframe/mod.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_lazyframe/mod.rs deleted file mode 100644 index 355516d340..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_lazyframe/mod.rs +++ /dev/null @@ -1,188 +0,0 @@ -mod custom_value; - -use super::{NuDataFrame, NuExpression}; -use core::fmt; -use nu_protocol::{PipelineData, ShellError, Span, Value}; -use polars::prelude::{Expr, IntoLazy, LazyFrame, Schema}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -// Lazyframe wrapper for Nushell operations -// Polars LazyFrame is behind and Option to allow easy implementation of -// the Deserialize trait -#[derive(Default)] -pub struct NuLazyFrame { - pub lazy: Option, - pub schema: Option, - pub from_eager: bool, -} - -// Mocked serialization of the LazyFrame object -impl Serialize for NuLazyFrame { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_none() - } -} - -// Mocked deserialization of the LazyFrame object -impl<'de> Deserialize<'de> for NuLazyFrame { - fn deserialize(_deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Ok(NuLazyFrame::default()) - } -} - -impl fmt::Debug for NuLazyFrame { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "NuLazyframe") - } -} - -// Referenced access to the real LazyFrame -impl AsRef for NuLazyFrame { - fn as_ref(&self) -> &polars::prelude::LazyFrame { - // The only case when there cannot be a lazy frame is if it is created - // using the default function or if created by deserializing something - self.lazy.as_ref().expect("there should always be a frame") - } -} - -impl AsMut for NuLazyFrame { - fn as_mut(&mut self) -> &mut polars::prelude::LazyFrame { - // The only case when there cannot be a lazy frame is if it is created - // using the default function or if created by deserializing something - self.lazy.as_mut().expect("there should always be a frame") - } -} - -impl From for NuLazyFrame { - fn from(lazy_frame: LazyFrame) -> Self { - Self { - lazy: Some(lazy_frame), - from_eager: false, - schema: None, - } - } -} - -impl NuLazyFrame { - pub fn new(from_eager: bool, lazy: LazyFrame) -> Self { - Self { - lazy: Some(lazy), - from_eager, - schema: None, - } - } - - pub fn from_dataframe(df: NuDataFrame) -> Self { - let lazy = df.as_ref().clone().lazy(); - Self { - lazy: Some(lazy), - from_eager: true, - schema: Some(df.as_ref().schema()), - } - } - - pub fn into_value(self, span: Span) -> Result { - if self.from_eager { - let df = self.collect(span)?; - Ok(Value::custom(Box::new(df), span)) - } else { - Ok(Value::custom(Box::new(self), span)) - } - } - - pub fn into_polars(self) -> LazyFrame { - self.lazy.expect("lazyframe cannot be none to convert") - } - - pub fn collect(self, span: Span) -> Result { - self.lazy - .expect("No empty lazy for collect") - .collect() - .map_err(|e| ShellError::GenericError { - error: "Error collecting lazy frame".into(), - msg: e.to_string(), - span: Some(span), - help: None, - inner: vec![], - }) - .map(|df| NuDataFrame { - df, - from_lazy: !self.from_eager, - }) - } - - pub fn try_from_value(value: Value) -> Result { - if Self::can_downcast(&value) { - Ok(Self::get_lazy_df(value)?) - } else if NuDataFrame::can_downcast(&value) { - let df = NuDataFrame::try_from_value(value)?; - Ok(NuLazyFrame::from_dataframe(df)) - } else { - Err(ShellError::CantConvert { - to_type: "lazy or eager dataframe".into(), - from_type: value.get_type().to_string(), - span: value.span(), - help: None, - }) - } - } - - pub fn try_from_pipeline(input: PipelineData, span: Span) -> Result { - let value = input.into_value(span)?; - Self::try_from_value(value) - } - - pub fn get_lazy_df(value: Value) -> Result { - let span = value.span(); - match value { - Value::Custom { val, .. } => match val.as_any().downcast_ref::() { - Some(expr) => Ok(Self { - lazy: expr.lazy.clone(), - from_eager: false, - schema: None, - }), - None => Err(ShellError::CantConvert { - to_type: "lazy frame".into(), - from_type: "non-dataframe".into(), - span, - help: None, - }), - }, - x => Err(ShellError::CantConvert { - to_type: "lazy frame".into(), - from_type: x.get_type().to_string(), - span: x.span(), - help: None, - }), - } - } - - pub fn can_downcast(value: &Value) -> bool { - if let Value::Custom { val, .. } = value { - val.as_any().downcast_ref::().is_some() - } else { - false - } - } - - pub fn apply_with_expr(self, expr: NuExpression, f: F) -> Self - where - F: Fn(LazyFrame, Expr) -> LazyFrame, - { - let df = self.lazy.expect("Lazy frame must not be empty to apply"); - let expr = expr.into_polars(); - let new_frame = f(df, expr); - - Self { - from_eager: self.from_eager, - lazy: Some(new_frame), - schema: None, - } - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_lazygroupby/custom_value.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_lazygroupby/custom_value.rs deleted file mode 100644 index 6ac6cc6046..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_lazygroupby/custom_value.rs +++ /dev/null @@ -1,44 +0,0 @@ -use super::NuLazyGroupBy; -use nu_protocol::{record, CustomValue, ShellError, Span, Value}; - -// CustomValue implementation for NuDataFrame -impl CustomValue for NuLazyGroupBy { - fn typetag_name(&self) -> &'static str { - "lazygroupby" - } - - fn typetag_deserialize(&self) { - unimplemented!("typetag_deserialize") - } - - fn clone_value(&self, span: nu_protocol::Span) -> Value { - let cloned = NuLazyGroupBy { - group_by: self.group_by.clone(), - schema: self.schema.clone(), - from_eager: self.from_eager, - }; - - Value::custom(Box::new(cloned), span) - } - - fn type_name(&self) -> String { - self.typetag_name().to_string() - } - - fn to_base_value(&self, span: Span) -> Result { - Ok(Value::record( - record! { - "LazyGroupBy" => Value::string("apply aggregation to complete execution plan", span) - }, - span, - )) - } - - fn as_any(&self) -> &dyn std::any::Any { - self - } - - fn as_mut_any(&mut self) -> &mut dyn std::any::Any { - self - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_lazygroupby/mod.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_lazygroupby/mod.rs deleted file mode 100644 index e1bcb30069..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_lazygroupby/mod.rs +++ /dev/null @@ -1,113 +0,0 @@ -mod custom_value; - -use core::fmt; -use nu_protocol::{PipelineData, ShellError, Span, Value}; -use polars::prelude::{LazyGroupBy, Schema}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -// Lazyframe wrapper for Nushell operations -// Polars LazyFrame is behind and Option to allow easy implementation of -// the Deserialize trait -#[derive(Default)] -pub struct NuLazyGroupBy { - pub group_by: Option, - pub schema: Option, - pub from_eager: bool, -} - -// Mocked serialization of the LazyFrame object -impl Serialize for NuLazyGroupBy { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_none() - } -} - -// Mocked deserialization of the LazyFrame object -impl<'de> Deserialize<'de> for NuLazyGroupBy { - fn deserialize(_deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Ok(NuLazyGroupBy::default()) - } -} - -impl fmt::Debug for NuLazyGroupBy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "NuLazyGroupBy") - } -} - -// Referenced access to the real LazyFrame -impl AsRef for NuLazyGroupBy { - fn as_ref(&self) -> &polars::prelude::LazyGroupBy { - // The only case when there cannot be a lazy frame is if it is created - // using the default function or if created by deserializing something - self.group_by - .as_ref() - .expect("there should always be a frame") - } -} - -impl AsMut for NuLazyGroupBy { - fn as_mut(&mut self) -> &mut polars::prelude::LazyGroupBy { - // The only case when there cannot be a lazy frame is if it is created - // using the default function or if created by deserializing something - self.group_by - .as_mut() - .expect("there should always be a frame") - } -} - -impl From for NuLazyGroupBy { - fn from(group_by: LazyGroupBy) -> Self { - Self { - group_by: Some(group_by), - from_eager: false, - schema: None, - } - } -} - -impl NuLazyGroupBy { - pub fn into_value(self, span: Span) -> Value { - Value::custom(Box::new(self), span) - } - - pub fn into_polars(self) -> LazyGroupBy { - self.group_by.expect("GroupBy cannot be none to convert") - } - - pub fn try_from_value(value: Value) -> Result { - let span = value.span(); - match value { - Value::Custom { val, .. } => match val.as_any().downcast_ref::() { - Some(group) => Ok(Self { - group_by: group.group_by.clone(), - schema: group.schema.clone(), - from_eager: group.from_eager, - }), - None => Err(ShellError::CantConvert { - to_type: "lazy groupby".into(), - from_type: "custom value".into(), - span, - help: None, - }), - }, - x => Err(ShellError::CantConvert { - to_type: "lazy groupby".into(), - from_type: x.get_type().to_string(), - span: x.span(), - help: None, - }), - } - } - - pub fn try_from_pipeline(input: PipelineData, span: Span) -> Result { - let value = input.into_value(span)?; - Self::try_from_value(value) - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_schema.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_schema.rs deleted file mode 100644 index 3c2f689b85..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_schema.rs +++ /dev/null @@ -1,376 +0,0 @@ -use nu_protocol::{ShellError, Span, Value}; -use polars::prelude::{DataType, Field, Schema, SchemaRef, TimeUnit}; -use std::sync::Arc; - -#[derive(Debug, Clone)] -pub struct NuSchema { - pub schema: SchemaRef, -} - -impl NuSchema { - pub fn new(schema: Schema) -> Self { - Self { - schema: Arc::new(schema), - } - } -} - -impl TryFrom<&Value> for NuSchema { - type Error = ShellError; - fn try_from(value: &Value) -> Result { - let schema = value_to_schema(value, Span::unknown())?; - Ok(Self::new(schema)) - } -} - -impl From for Value { - fn from(schema: NuSchema) -> Self { - fields_to_value(schema.schema.iter_fields(), Span::unknown()) - } -} - -impl From for SchemaRef { - fn from(val: NuSchema) -> Self { - Arc::clone(&val.schema) - } -} - -fn fields_to_value(fields: impl Iterator, span: Span) -> Value { - let record = fields - .map(|field| { - let col = field.name().to_string(); - let val = dtype_to_value(field.data_type(), span); - (col, val) - }) - .collect(); - - Value::record(record, Span::unknown()) -} - -fn dtype_to_value(dtype: &DataType, span: Span) -> Value { - match dtype { - DataType::Struct(fields) => fields_to_value(fields.iter().cloned(), span), - _ => Value::string(dtype.to_string().replace('[', "<").replace(']', ">"), span), - } -} - -fn value_to_schema(value: &Value, span: Span) -> Result { - let fields = value_to_fields(value, span)?; - let schema = Schema::from_iter(fields); - Ok(schema) -} - -fn value_to_fields(value: &Value, span: Span) -> Result, ShellError> { - let fields = value - .as_record()? - .into_iter() - .map(|(col, val)| match val { - Value::Record { .. } => { - let fields = value_to_fields(val, span)?; - let dtype = DataType::Struct(fields); - Ok(Field::new(col, dtype)) - } - _ => { - let dtype = str_to_dtype(&val.coerce_string()?, span)?; - Ok(Field::new(col, dtype)) - } - }) - .collect::, ShellError>>()?; - Ok(fields) -} - -pub fn str_to_dtype(dtype: &str, span: Span) -> Result { - match dtype { - "bool" => Ok(DataType::Boolean), - "u8" => Ok(DataType::UInt8), - "u16" => Ok(DataType::UInt16), - "u32" => Ok(DataType::UInt32), - "u64" => Ok(DataType::UInt64), - "i8" => Ok(DataType::Int8), - "i16" => Ok(DataType::Int16), - "i32" => Ok(DataType::Int32), - "i64" => Ok(DataType::Int64), - "f32" => Ok(DataType::Float32), - "f64" => Ok(DataType::Float64), - "str" => Ok(DataType::String), - "binary" => Ok(DataType::Binary), - "date" => Ok(DataType::Date), - "time" => Ok(DataType::Time), - "null" => Ok(DataType::Null), - "unknown" => Ok(DataType::Unknown), - "object" => Ok(DataType::Object("unknown", None)), - _ if dtype.starts_with("list") => { - let dtype = dtype - .trim_start_matches("list") - .trim_start_matches('<') - .trim_end_matches('>') - .trim(); - let dtype = str_to_dtype(dtype, span)?; - Ok(DataType::List(Box::new(dtype))) - } - _ if dtype.starts_with("datetime") => { - let dtype = dtype - .trim_start_matches("datetime") - .trim_start_matches('<') - .trim_end_matches('>'); - let mut split = dtype.split(','); - let next = split - .next() - .ok_or_else(|| ShellError::GenericError { - error: "Invalid polars data type".into(), - msg: "Missing time unit".into(), - span: Some(span), - help: None, - inner: vec![], - })? - .trim(); - let time_unit = str_to_time_unit(next, span)?; - let next = split - .next() - .ok_or_else(|| ShellError::GenericError { - error: "Invalid polars data type".into(), - msg: "Missing time zone".into(), - span: Some(span), - help: None, - inner: vec![], - })? - .trim(); - let timezone = if "*" == next { - None - } else { - Some(next.to_string()) - }; - Ok(DataType::Datetime(time_unit, timezone)) - } - _ if dtype.starts_with("duration") => { - let inner = dtype.trim_start_matches("duration<").trim_end_matches('>'); - let next = inner - .split(',') - .next() - .ok_or_else(|| ShellError::GenericError { - error: "Invalid polars data type".into(), - msg: "Missing time unit".into(), - span: Some(span), - help: None, - inner: vec![], - })? - .trim(); - let time_unit = str_to_time_unit(next, span)?; - Ok(DataType::Duration(time_unit)) - } - _ => Err(ShellError::GenericError { - error: "Invalid polars data type".into(), - msg: format!("Unknown type: {dtype}"), - span: Some(span), - help: None, - inner: vec![], - }), - } -} - -fn str_to_time_unit(ts_string: &str, span: Span) -> Result { - match ts_string { - "ms" => Ok(TimeUnit::Milliseconds), - "us" | "μs" => Ok(TimeUnit::Microseconds), - "ns" => Ok(TimeUnit::Nanoseconds), - _ => Err(ShellError::GenericError { - error: "Invalid polars data type".into(), - msg: "Invalid time unit".into(), - span: Some(span), - help: None, - inner: vec![], - }), - } -} - -#[cfg(test)] -mod test { - - use nu_protocol::record; - - use super::*; - - #[test] - fn test_value_to_schema() { - let address = record! { - "street" => Value::test_string("str"), - "city" => Value::test_string("str"), - }; - - let value = Value::test_record(record! { - "name" => Value::test_string("str"), - "age" => Value::test_string("i32"), - "address" => Value::test_record(address) - }); - - let schema = value_to_schema(&value, Span::unknown()).unwrap(); - let expected = Schema::from_iter(vec![ - Field::new("name", DataType::String), - Field::new("age", DataType::Int32), - Field::new( - "address", - DataType::Struct(vec![ - Field::new("street", DataType::String), - Field::new("city", DataType::String), - ]), - ), - ]); - assert_eq!(schema, expected); - } - - #[test] - fn test_dtype_str_to_schema_simple_types() { - let dtype = "bool"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Boolean; - assert_eq!(schema, expected); - - let dtype = "u8"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::UInt8; - assert_eq!(schema, expected); - - let dtype = "u16"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::UInt16; - assert_eq!(schema, expected); - - let dtype = "u32"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::UInt32; - assert_eq!(schema, expected); - - let dtype = "u64"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::UInt64; - assert_eq!(schema, expected); - - let dtype = "i8"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Int8; - assert_eq!(schema, expected); - - let dtype = "i16"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Int16; - assert_eq!(schema, expected); - - let dtype = "i32"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Int32; - assert_eq!(schema, expected); - - let dtype = "i64"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Int64; - assert_eq!(schema, expected); - - let dtype = "str"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::String; - assert_eq!(schema, expected); - - let dtype = "binary"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Binary; - assert_eq!(schema, expected); - - let dtype = "date"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Date; - assert_eq!(schema, expected); - - let dtype = "time"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Time; - assert_eq!(schema, expected); - - let dtype = "null"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Null; - assert_eq!(schema, expected); - - let dtype = "unknown"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Unknown; - assert_eq!(schema, expected); - - let dtype = "object"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Object("unknown", None); - assert_eq!(schema, expected); - } - - #[test] - fn test_dtype_str_schema_datetime() { - let dtype = "datetime"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Datetime(TimeUnit::Milliseconds, None); - assert_eq!(schema, expected); - - let dtype = "datetime"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Datetime(TimeUnit::Microseconds, None); - assert_eq!(schema, expected); - - let dtype = "datetime<μs, *>"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Datetime(TimeUnit::Microseconds, None); - assert_eq!(schema, expected); - - let dtype = "datetime"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Datetime(TimeUnit::Nanoseconds, None); - assert_eq!(schema, expected); - - let dtype = "datetime"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Datetime(TimeUnit::Milliseconds, Some("UTC".into())); - assert_eq!(schema, expected); - - let dtype = "invalid"; - let schema = str_to_dtype(dtype, Span::unknown()); - assert!(schema.is_err()) - } - - #[test] - fn test_dtype_str_schema_duration() { - let dtype = "duration"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Duration(TimeUnit::Milliseconds); - assert_eq!(schema, expected); - - let dtype = "duration"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Duration(TimeUnit::Microseconds); - assert_eq!(schema, expected); - - let dtype = "duration<μs>"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Duration(TimeUnit::Microseconds); - assert_eq!(schema, expected); - - let dtype = "duration"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::Duration(TimeUnit::Nanoseconds); - assert_eq!(schema, expected); - } - - #[test] - fn test_dtype_str_to_schema_list_types() { - let dtype = "list"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::List(Box::new(DataType::Int32)); - assert_eq!(schema, expected); - - let dtype = "list>"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::List(Box::new(DataType::Duration(TimeUnit::Milliseconds))); - assert_eq!(schema, expected); - - let dtype = "list>"; - let schema = str_to_dtype(dtype, Span::unknown()).unwrap(); - let expected = DataType::List(Box::new(DataType::Datetime(TimeUnit::Milliseconds, None))); - assert_eq!(schema, expected); - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_when/custom_value.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_when/custom_value.rs deleted file mode 100644 index e2b73bcef1..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_when/custom_value.rs +++ /dev/null @@ -1,41 +0,0 @@ -use super::NuWhen; -use nu_protocol::{CustomValue, ShellError, Span, Value}; - -// CustomValue implementation for NuDataFrame -impl CustomValue for NuWhen { - fn typetag_name(&self) -> &'static str { - "when" - } - - fn typetag_deserialize(&self) { - unimplemented!("typetag_deserialize") - } - - fn clone_value(&self, span: nu_protocol::Span) -> Value { - let cloned = self.clone(); - - Value::custom(Box::new(cloned), span) - } - - fn type_name(&self) -> String { - self.typetag_name().to_string() - } - - fn to_base_value(&self, span: Span) -> Result { - let val: String = match self { - NuWhen::Then(_) => "whenthen".into(), - NuWhen::ChainedThen(_) => "whenthenthen".into(), - }; - - let value = Value::string(val, span); - Ok(value) - } - - fn as_any(&self) -> &dyn std::any::Any { - self - } - - fn as_mut_any(&mut self) -> &mut dyn std::any::Any { - self - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/nu_when/mod.rs b/crates/nu-cmd-dataframe/src/dataframe/values/nu_when/mod.rs deleted file mode 100644 index b33cde7483..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/values/nu_when/mod.rs +++ /dev/null @@ -1,77 +0,0 @@ -mod custom_value; - -use core::fmt; -use nu_protocol::{ShellError, Span, Value}; -use polars::prelude::{col, when, ChainedThen, Then}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -#[derive(Clone)] -pub enum NuWhen { - Then(Box), - ChainedThen(ChainedThen), -} - -// Mocked serialization of the LazyFrame object -impl Serialize for NuWhen { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_none() - } -} - -// Mocked deserialization of the LazyFrame object -impl<'de> Deserialize<'de> for NuWhen { - fn deserialize(_deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Ok(NuWhen::Then(Box::new(when(col("a")).then(col("b"))))) - } -} - -impl fmt::Debug for NuWhen { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "NuWhen") - } -} - -impl From for NuWhen { - fn from(then: Then) -> Self { - NuWhen::Then(Box::new(then)) - } -} - -impl From for NuWhen { - fn from(chained_when: ChainedThen) -> Self { - NuWhen::ChainedThen(chained_when) - } -} - -impl NuWhen { - pub fn into_value(self, span: Span) -> Value { - Value::custom(Box::new(self), span) - } - - pub fn try_from_value(value: Value) -> Result { - let span = value.span(); - match value { - Value::Custom { val, .. } => match val.as_any().downcast_ref::() { - Some(expr) => Ok(expr.clone()), - None => Err(ShellError::CantConvert { - to_type: "when expression".into(), - from_type: "non when expression".into(), - span, - help: None, - }), - }, - x => Err(ShellError::CantConvert { - to_type: "when expression".into(), - from_type: x.get_type().to_string(), - span: x.span(), - help: None, - }), - } - } -} diff --git a/crates/nu-cmd-dataframe/src/dataframe/values/utils.rs b/crates/nu-cmd-dataframe/src/dataframe/values/utils.rs deleted file mode 100644 index 0dc43399a3..0000000000 --- a/crates/nu-cmd-dataframe/src/dataframe/values/utils.rs +++ /dev/null @@ -1,86 +0,0 @@ -use nu_protocol::{ShellError, Span, Spanned, Value}; - -// Default value used when selecting rows from dataframe -pub const DEFAULT_ROWS: usize = 5; - -// Converts a Vec to a Vec> with a Span marking the whole -// location of the columns for error referencing -pub(crate) fn convert_columns( - columns: Vec, - span: Span, -) -> Result<(Vec>, Span), ShellError> { - // First column span - let mut col_span = columns - .first() - .ok_or_else(|| ShellError::GenericError { - error: "Empty column list".into(), - msg: "Empty list found for command".into(), - span: Some(span), - help: None, - inner: vec![], - }) - .map(|v| v.span())?; - - let res = columns - .into_iter() - .map(|value| { - let span = value.span(); - match value { - Value::String { val, .. } => { - col_span = col_span.merge(span); - Ok(Spanned { item: val, span }) - } - _ => Err(ShellError::GenericError { - error: "Incorrect column format".into(), - msg: "Only string as column name".into(), - span: Some(span), - help: None, - inner: vec![], - }), - } - }) - .collect::>, _>>()?; - - Ok((res, col_span)) -} - -// Converts a Vec to a Vec with a Span marking the whole -// location of the columns for error referencing -pub(crate) fn convert_columns_string( - columns: Vec, - span: Span, -) -> Result<(Vec, Span), ShellError> { - // First column span - let mut col_span = columns - .first() - .ok_or_else(|| ShellError::GenericError { - error: "Empty column list".into(), - msg: "Empty list found for command".into(), - span: Some(span), - help: None, - inner: vec![], - }) - .map(|v| v.span())?; - - let res = columns - .into_iter() - .map(|value| { - let span = value.span(); - match value { - Value::String { val, .. } => { - col_span = col_span.merge(span); - Ok(val) - } - _ => Err(ShellError::GenericError { - error: "Incorrect column format".into(), - msg: "Only string as column name".into(), - span: Some(span), - help: None, - inner: vec![], - }), - } - }) - .collect::, _>>()?; - - Ok((res, col_span)) -} diff --git a/crates/nu-cmd-dataframe/src/lib.rs b/crates/nu-cmd-dataframe/src/lib.rs deleted file mode 100644 index 7e7c8014c6..0000000000 --- a/crates/nu-cmd-dataframe/src/lib.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg(feature = "dataframe")] -pub mod dataframe; -#[cfg(feature = "dataframe")] -pub use dataframe::*; diff --git a/crates/nu-cmd-lang/Cargo.toml b/crates/nu-cmd-lang/Cargo.toml index 7592d4303b..abb89a6991 100644 --- a/crates/nu-cmd-lang/Cargo.toml +++ b/crates/nu-cmd-lang/Cargo.toml @@ -28,6 +28,5 @@ mimalloc = [] which-support = [] trash-support = [] sqlite = [] -dataframe = [] static-link-openssl = [] system-clipboard = [] diff --git a/crates/nu-cmd-lang/README.md b/crates/nu-cmd-lang/README.md index 836fabf6f8..6c7298c17a 100644 --- a/crates/nu-cmd-lang/README.md +++ b/crates/nu-cmd-lang/README.md @@ -8,7 +8,6 @@ top of including: * nu-command * nu-cli -* nu-cmd-dataframe * nu-cmd-extra As time goes on and the nu language develops further in parallel with nushell we will be adding other command crates to the system. diff --git a/crates/nu-cmd-lang/src/core_commands/version.rs b/crates/nu-cmd-lang/src/core_commands/version.rs index 7aaa72b38a..22ef1f2a08 100644 --- a/crates/nu-cmd-lang/src/core_commands/version.rs +++ b/crates/nu-cmd-lang/src/core_commands/version.rs @@ -175,11 +175,6 @@ fn features_enabled() -> Vec { names.push("sqlite".to_string()); } - #[cfg(feature = "dataframe")] - { - names.push("dataframe".to_string()); - } - #[cfg(feature = "static-link-openssl")] { names.push("static-link-openssl".to_string()); diff --git a/crates/nu-command/tests/commands/open.rs b/crates/nu-command/tests/commands/open.rs index f857718c72..ac5e2f99e5 100644 --- a/crates/nu-command/tests/commands/open.rs +++ b/crates/nu-command/tests/commands/open.rs @@ -238,22 +238,6 @@ fn parses_xml() { assert_eq!(actual.out, "https://www.jntrnr.com/off-to-new-adventures/") } -#[cfg(feature = "dataframe")] -#[test] -fn parses_arrow_ipc() { - let actual = nu!( - cwd: "tests/fixtures/formats", pipeline( - " - dfr open caco3_plastics.arrow - | dfr into-nu - | first - | get origin - " - )); - - assert_eq!(actual.out, "SPAIN") -} - #[test] fn errors_if_file_not_found() { let actual = nu!( diff --git a/crates/nu-command/tests/main.rs b/crates/nu-command/tests/main.rs index 72ccee3d85..1039e1a0d7 100644 --- a/crates/nu-command/tests/main.rs +++ b/crates/nu-command/tests/main.rs @@ -151,9 +151,8 @@ fn commands_declare_input_output_types() { let sig_name = cmd.signature().name; let category = cmd.signature().category; - if matches!(category, Category::Removed | Category::Custom(_)) { + if matches!(category, Category::Removed) { // Deprecated/Removed commands don't have to conform - // TODO: also upgrade the `--features dataframe` commands continue; } diff --git a/crates/nu-protocol/src/errors/shell_error.rs b/crates/nu-protocol/src/errors/shell_error.rs index 81139d1a52..a8ca52142c 100644 --- a/crates/nu-protocol/src/errors/shell_error.rs +++ b/crates/nu-protocol/src/errors/shell_error.rs @@ -1042,19 +1042,6 @@ pub enum ShellError { span: Span, }, - /// A custom value could not be converted to a Dataframe. - /// - /// ## Resolution - /// - /// Make sure conversion to a Dataframe is possible for this value or convert it to a type that does, first. - #[error("Casting error")] - #[diagnostic(code(nu::shell::downcast_not_possible))] - DowncastNotPossible { - msg: String, - #[label("{msg}")] - span: Span, - }, - /// The value given for this configuration is not supported. /// /// ## Resolution diff --git a/crates/nu_plugin_polars/Cargo.toml b/crates/nu_plugin_polars/Cargo.toml index 99c95f33e4..df30c71c52 100644 --- a/crates/nu_plugin_polars/Cargo.toml +++ b/crates/nu_plugin_polars/Cargo.toml @@ -4,7 +4,7 @@ description = "Nushell dataframe plugin commands based on polars." edition = "2021" license = "MIT" name = "nu_plugin_polars" -repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-dataframe" +repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_polars" version = "0.93.1" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/devdocs/PLATFORM_SUPPORT.md b/devdocs/PLATFORM_SUPPORT.md index 46efdfbe5c..dd393ec897 100644 --- a/devdocs/PLATFORM_SUPPORT.md +++ b/devdocs/PLATFORM_SUPPORT.md @@ -33,12 +33,8 @@ We will try to provide builds for all of them but a standard configuration for x We have features of Nushell behind flags that can be passed at compilation time. -The design focus of Nushell is primarily expressed by everything accessible without passing additional feature flag. This provides a standard command set and receives the most attention. - -One option feature flag is currently tested in CI but contains a feature that may be moved to a plugin: -- `dataframe` - - This includes dataframe support via `polars` and `arrow2`. Introduces a significant additional compilation and binary size. - - Due to the use of SIMD extensions may not be compatible with every minimal architecture. +The design focus of Nushell is primarily expressed by everything accessible without passing additional feature flag. +This provides a standard command set and receives the most attention. ## Passively supported platforms diff --git a/scripts/build-all-maclin.sh b/scripts/build-all-maclin.sh index 5490695573..4658161874 100755 --- a/scripts/build-all-maclin.sh +++ b/scripts/build-all-maclin.sh @@ -6,7 +6,7 @@ DIR=$(readlink -f $(dirname "${BASH_SOURCE[0]}")) REPO_ROOT=$(dirname $DIR) echo "---------------------------------------------------------------" -echo "Building nushell (nu) with dataframes and all the plugins" +echo "Building nushell (nu) and all the plugins" echo "---------------------------------------------------------------" echo "" @@ -21,7 +21,7 @@ NU_PLUGINS=( echo "Building nushell" ( cd $REPO_ROOT - cargo build --features=dataframe --locked + cargo build --locked ) for plugin in "${NU_PLUGINS[@]}" diff --git a/scripts/build-all-windows.cmd b/scripts/build-all-windows.cmd index 2619a294d0..b8a4c70ea2 100644 --- a/scripts/build-all-windows.cmd +++ b/scripts/build-all-windows.cmd @@ -1,11 +1,11 @@ @echo off echo ------------------------------------------------------------------- -echo Building nushell (nu.exe) with dataframes and all the plugins +echo Building nushell (nu.exe) and all the plugins echo ------------------------------------------------------------------- echo. echo Building nushell.exe -cargo build --features=dataframe --locked +cargo build --locked echo. call :build crates\nu_plugin_example nu_plugin_example.exe diff --git a/scripts/build-all.nu b/scripts/build-all.nu index 2ad7ec467e..92fcc64635 100644 --- a/scripts/build-all.nu +++ b/scripts/build-all.nu @@ -1,7 +1,7 @@ use std log warning print '-------------------------------------------------------------------' -print 'Building nushell (nu) with dataframes and all the plugins' +print 'Building nushell (nu) and all the plugins' print '-------------------------------------------------------------------' warning "./scripts/build-all.nu will be deprecated, please use the `toolkit build` command instead" @@ -13,7 +13,7 @@ def build-nushell [] { print '----------------------------' cd $repo_root - cargo build --features=dataframe --locked + cargo build --locked } def build-plugin [] { diff --git a/scripts/install-all.ps1 b/scripts/install-all.ps1 index 0569de4ad3..1dfc3b2dfd 100644 --- a/scripts/install-all.ps1 +++ b/scripts/install-all.ps1 @@ -2,13 +2,13 @@ # Usage: Just run `powershell install-all.ps1` in nushell root directory Write-Output "-----------------------------------------------------------------" -Write-Output "Installing nushell (nu) with dataframes and all the plugins" +Write-Output "Installing nushell (nu) and all the plugins" Write-Output "-----------------------------------------------------------------" Write-Output "" Write-Output "Install nushell from local..." Write-Output "----------------------------------------------" -cargo install --force --path . --features=dataframe --locked +cargo install --force --path . --locked $NU_PLUGINS = @( 'nu_plugin_example', diff --git a/scripts/install-all.sh b/scripts/install-all.sh index b53d53aa3b..b6c0f1fbfb 100755 --- a/scripts/install-all.sh +++ b/scripts/install-all.sh @@ -6,13 +6,13 @@ DIR=$(readlink -f $(dirname "${BASH_SOURCE[0]}")) REPO_ROOT=$(dirname $DIR) echo "-----------------------------------------------------------------" -echo "Installing nushell (nu) with dataframes and all the plugins" +echo "Installing nushell (nu) and all the plugins" echo "-----------------------------------------------------------------" echo "" echo "Install nushell from local..." echo "----------------------------------------------" -cargo install --force --path "$REPO_ROOT" --features=dataframe --locked +cargo install --force --path "$REPO_ROOT" --locked NU_PLUGINS=( 'nu_plugin_inc' diff --git a/src/main.rs b/src/main.rs index d0fc023b68..bc48a9f7de 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,8 +43,6 @@ fn get_engine_state() -> EngineState { let engine_state = nu_cmd_plugin::add_plugin_command_context(engine_state); let engine_state = nu_command::add_shell_command_context(engine_state); let engine_state = nu_cmd_extra::add_extra_command_context(engine_state); - #[cfg(feature = "dataframe")] - let engine_state = nu_cmd_dataframe::add_dataframe_context(engine_state); let engine_state = nu_cli::add_cli_context(engine_state); nu_explore::add_explore_context(engine_state) } diff --git a/toolkit.nu b/toolkit.nu index 407998c514..6f19900fdb 100644 --- a/toolkit.nu +++ b/toolkit.nu @@ -514,7 +514,7 @@ export def "benchmark-and-log-result" [] { cargo export $"target/($current_branch)" -- bench ^$"./target/($current_branch)/benchmarks" compare -o -s 50 --dump $res_path -} +} # Build all Windows archives and MSIs for release manually # @@ -536,25 +536,14 @@ export def 'release-pkg windows' [ mkdir $artifacts_dir for target in ["aarch64" "x86_64"] { $env.TARGET = $target ++ "-pc-windows-msvc" - for release_type in ["" full] { - $env.RELEASE_TYPE = $release_type - $env.TARGET_RUSTFLAGS = if $release_type == "full" { - "--features=dataframe" - } else { - "" - } - let out_filename = if $release_type == "full" { - $target ++ "-windows-msvc-full" - } else { - $target ++ "-pc-windows-msvc" - } - rm -rf output - _EXTRA_=bin nu .github/workflows/release-pkg.nu - cp $"output/nu-($version)-($out_filename).zip" $artifacts_dir - rm -rf output - _EXTRA_=msi nu .github/workflows/release-pkg.nu - cp $"target/wix/nu-($version)-($out_filename).msi" $artifacts_dir - } + + rm -rf output + _EXTRA_=bin nu .github/workflows/release-pkg.nu + cp $"output/nu-($version)-($target)-pc-windows-msvc.zip" $artifacts_dir + + rm -rf output + _EXTRA_=msi nu .github/workflows/release-pkg.nu + cp $"target/wix/nu-($version)-($target)-pc-windows-msvc.msi" $artifacts_dir } }