move dataframe commands to nu-cmd-dataframe (#9241)

All of the dataframe commands ported over with no issues...

### 11 tests are commented out (for now)

So 100 of the original 111 tests are passing with only 11 tests being
ignored for now..

As per our conversation in the core team meeting on Wednesday
I took @jntrnr  suggestion and just commented out the tests dealing
with
[IntoDatetime](https://github.com/nushell/nushell/blob/main/crates/nu-command/src/conversions/into/mod.rs)

Later on we can move this functionality out of nu-command if we decide
it makes sense...

### The following tests were ignored...

```rust
modified:   crates/nu-cmd-dataframe/src/dataframe/series/date/get_day.rs
modified:   crates/nu-cmd-dataframe/src/dataframe/series/date/get_hour.rs
modified:   crates/nu-cmd-dataframe/src/dataframe/series/date/get_minute.rs

modified:   crates/nu-cmd-dataframe/src/dataframe/series/date/get_month.rs
modified:   crates/nu-cmd-dataframe/src/dataframe/series/date/get_nanosecond.rs
modified:   crates/nu-cmd-dataframe/src/dataframe/series/date/get_ordinal.rs

modified:   crates/nu-cmd-dataframe/src/dataframe/series/date/get_second.rs
modified:   crates/nu-cmd-dataframe/src/dataframe/series/date/get_week.rs
modified:   crates/nu-cmd-dataframe/src/dataframe/series/date/get_weekday.rs

modified:   crates/nu-cmd-dataframe/src/dataframe/series/date/get_year.rs
modified:   crates/nu-cmd-dataframe/src/dataframe/series/string/strftime.rs
```
This commit is contained in:
Michael Angerman
2023-05-19 10:56:08 -07:00
committed by GitHub
parent ca275f59da
commit c55b5c0a55
131 changed files with 128 additions and 51 deletions

View File

@ -0,0 +1,104 @@
use super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
#[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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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)],
)])
.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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 converting to bool".into(),
"all-false only works with series of type bool".into(),
Some(call.head),
None,
Vec::new(),
)
})?;
let value = Value::boolean(!bool.any(), call.head);
NuDataFrame::try_from_columns(vec![Column::new("all_false".to_string(), vec![value])])
.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 {})])
}
}

View File

@ -0,0 +1,104 @@
use super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
#[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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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)],
)])
.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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 converting to bool".into(),
"all-false only works with series of type bool".into(),
Some(call.head),
None,
Vec::new(),
)
})?;
let value = Value::boolean(bool.all(), call.head);
NuDataFrame::try_from_columns(vec![Column::new("all_true".to_string(), vec![value])])
.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 {})])
}
}

View File

@ -0,0 +1,88 @@
use super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 {})])
}
}

View File

@ -0,0 +1,88 @@
use super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 {})])
}
}

View File

@ -0,0 +1,141 @@
use super::super::values::{Column, NuDataFrame};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type,
Value,
};
use polars::prelude::{DataType, IntoSeries};
enum CumType {
Min,
Max,
Sum,
}
impl CumType {
fn from_str(roll_type: &str, span: Span) -> Result<Self, ShellError> {
match roll_type {
"min" => Ok(Self::Min),
"max" => Ok(Self::Max),
"sum" => Ok(Self::Sum),
_ => Err(ShellError::GenericError(
"Wrong operation".into(),
"Operation not valid for cumulative".into(),
Some(span),
Some("Allowed values: max, min, sum".into()),
Vec::new(),
)),
}
}
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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),
],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let cum_type: Spanned<String> = call.req(engine_state, stack, 0)?;
let reverse = call.has_flag("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(
"Found object series".into(),
"Series of type object cannot be used for cumulative operation".into(),
Some(call.head),
None,
Vec::new(),
));
}
let cum_type = CumType::from_str(&cum_type.item, cum_type.span)?;
let mut res = match cum_type {
CumType::Max => series.cummax(reverse),
CumType::Min => series.cummin(reverse),
CumType::Sum => series.cumsum(reverse),
};
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 {})])
}
}

View File

@ -0,0 +1,101 @@
use super::super::super::values::NuDataFrame;
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type,
};
use polars::prelude::{IntoSeries, Utf8Methods};
#[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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let format: String = call.req(engine_state, stack, 0)?;
let not_exact = call.has_flag("not-exact");
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let series = df.as_series(call.head)?;
let casted = series.utf8().map_err(|e| {
ShellError::GenericError(
"Error casting to string".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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 creating datetime".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?
.into_series();
res.rename("date");
NuDataFrame::try_from_series(vec![res], call.head)
.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))
}

View File

@ -0,0 +1,151 @@
use super::super::super::values::{Column, NuDataFrame};
use chrono::DateTime;
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use polars::prelude::{IntoSeries, TimeUnit, Utf8Methods};
#[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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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 {
val: 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: Span::test_data(),
},
Value::Date {
val: 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: 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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let format: String = call.req(engine_state, stack, 0)?;
let not_exact = call.has_flag("not-exact");
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let series = df.as_series(call.head)?;
let casted = series.utf8().map_err(|e| {
ShellError::GenericError(
"Error casting to string".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
let res = if not_exact {
casted.as_datetime_not_exact(Some(format.as_str()), TimeUnit::Milliseconds, None)
} else {
casted.as_datetime(
Some(format.as_str()),
TimeUnit::Milliseconds,
false,
false,
true,
None,
)
};
let mut res = res
.map_err(|e| {
ShellError::GenericError(
"Error creating datetime".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?
.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 {})])
}
}

View File

@ -0,0 +1,92 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Returns day from a date",
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime -z '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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 casting to datetime type".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,92 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Returns hour from a date",
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime -z '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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 casting to datetime type".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,92 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Returns minute from a date",
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime -z '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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 casting to datetime type".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,92 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Returns month from a date",
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime -z '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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 casting to datetime type".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,92 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Returns nanosecond from a date",
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime -z '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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 casting to datetime type".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,92 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Returns ordinal from a date",
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime -z '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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 casting to datetime type".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,92 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Returns second from a date",
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime -z '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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 casting to datetime type".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,92 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Returns week from a date",
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime -z '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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 casting to datetime type".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,92 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Returns weekday from a date",
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime -z '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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 casting to datetime type".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,92 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Returns year from a date",
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime -z '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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 casting to datetime type".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,25 @@
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;

View File

@ -0,0 +1,120 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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'))
.input_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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),
],
)])
.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 -r",
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),
],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let sort_options = SortOptions {
descending: call.has_flag("reverse"),
nulls_last: call.has_flag("nulls-last"),
multithreaded: true,
};
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 {})])
}
}

View File

@ -0,0 +1,112 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 using as series".into(),
"dataframe has more than one column".into(),
Some(call.head),
None,
Vec::new(),
));
}
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 creating index column".into(),
err.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
let value = NuDataFrame::dataframe_into_value(res, call.head);
Ok(PipelineData::Value(value, None))
}
_ => todo!(),
}
}
#[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 {})])
}
}

View File

@ -0,0 +1,95 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 extracting unique values".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?
.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 {})])
}
}

View File

@ -0,0 +1,9 @@
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;

View File

@ -0,0 +1,223 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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 -i $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),
],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 casting indices".into(),
e.to_string(),
Some(indices_span),
None,
Vec::new(),
)
})
}
_ => Err(ShellError::GenericError(
"Incorrect type".into(),
"Series with incorrect type".into(),
Some(indices_span),
Some("Consider using a Series with type int type".into()),
Vec::new(),
)),
}?;
let indices = casted
.u32()
.map_err(|e| {
ShellError::GenericError(
"Error casting indices".into(),
e.to_string(),
Some(indices_span),
None,
Vec::new(),
)
})?
.into_iter()
.flatten();
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let series = df.as_series(call.head)?;
let res = match value {
Value::Int { val, span } => {
let chunked = series.i64().map_err(|e| {
ShellError::GenericError(
"Error casting to i64".into(),
e.to_string(),
Some(span),
None,
Vec::new(),
)
})?;
let res = chunked.set_at_idx(indices, Some(val)).map_err(|e| {
ShellError::GenericError(
"Error setting value".into(),
e.to_string(),
Some(span),
None,
Vec::new(),
)
})?;
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
}
Value::Float { val, span } => {
let chunked = series.f64().map_err(|e| {
ShellError::GenericError(
"Error casting to f64".into(),
e.to_string(),
Some(span),
None,
Vec::new(),
)
})?;
let res = chunked.set_at_idx(indices, Some(val)).map_err(|e| {
ShellError::GenericError(
"Error setting value".into(),
e.to_string(),
Some(span),
None,
Vec::new(),
)
})?;
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
}
Value::String { val, span } => {
let chunked = series.utf8().map_err(|e| {
ShellError::GenericError(
"Error casting to string".into(),
e.to_string(),
Some(span),
None,
Vec::new(),
)
})?;
let res = chunked
.set_at_idx(indices, Some(val.as_ref()))
.map_err(|e| {
ShellError::GenericError(
"Error setting value".into(),
e.to_string(),
Some(span),
None,
Vec::new(),
)
})?;
let mut res = res.into_series();
res.rename("string");
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
}
_ => Err(ShellError::GenericError(
"Incorrect value type".into(),
format!(
"this value cannot be set in a series of type '{}'",
series.dtype()
),
Some(value.span()?),
None,
Vec::new(),
)),
};
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 {})])
}
}

View File

@ -0,0 +1,121 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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),
],
)])
.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),
],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let mut res = df
.as_ref()
.is_duplicated()
.map_err(|e| {
ShellError::GenericError(
"Error finding duplicates".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?
.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 {})])
}
}

View File

@ -0,0 +1,108 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use polars::prelude::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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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),
],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let df = NuDataFrame::try_from_pipeline(input, 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 = df
.as_series(call.head)?
.is_in(&other)
.map_err(|e| {
ShellError::GenericError(
"Error finding in other".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?
.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 {})])
}
}

View File

@ -0,0 +1,84 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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),
],
)])
.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<PipelineData, ShellError> {
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<PipelineData, ShellError> {
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::super::super::super::test_dataframe::test_dataframe;
use super::*;
#[test]
fn test_examples() {
test_dataframe(vec![Box::new(IsNotNull {})])
}
}

View File

@ -0,0 +1,84 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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),
],
)])
.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<PipelineData, ShellError> {
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<PipelineData, ShellError> {
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::super::super::super::test_dataframe::test_dataframe;
use super::*;
#[test]
fn test_examples() {
test_dataframe(vec![Box::new(IsNull {})])
}
}

View File

@ -0,0 +1,120 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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),
],
)])
.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),
],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let mut res = df
.as_ref()
.is_unique()
.map_err(|e| {
ShellError::GenericError(
"Error finding unique values".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?
.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 {})])
}
}

View File

@ -0,0 +1,15 @@
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;

View File

@ -0,0 +1,94 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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),
],
)])
.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<PipelineData, ShellError> {
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<PipelineData, ShellError> {
let series = df.as_series(call.head)?;
let bool = series.bool().map_err(|e| {
ShellError::GenericError(
"Error inverting mask".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,209 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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),
],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 casting to bool".into(),
e.to_string(),
Some(mask_span),
None,
Vec::new(),
)
}),
_ => Err(ShellError::GenericError(
"Incorrect type".into(),
"can only use bool series as mask".into(),
Some(mask_span),
None,
Vec::new(),
)),
}?;
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let series = df.as_series(call.head)?;
let res = match value {
Value::Int { val, span } => {
let chunked = series.i64().map_err(|e| {
ShellError::GenericError(
"Error casting to i64".into(),
e.to_string(),
Some(span),
None,
Vec::new(),
)
})?;
let res = chunked.set(bool_mask, Some(val)).map_err(|e| {
ShellError::GenericError(
"Error setting value".into(),
e.to_string(),
Some(span),
None,
Vec::new(),
)
})?;
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
}
Value::Float { val, span } => {
let chunked = series.f64().map_err(|e| {
ShellError::GenericError(
"Error casting to f64".into(),
e.to_string(),
Some(span),
None,
Vec::new(),
)
})?;
let res = chunked.set(bool_mask, Some(val)).map_err(|e| {
ShellError::GenericError(
"Error setting value".into(),
e.to_string(),
Some(span),
None,
Vec::new(),
)
})?;
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
}
Value::String { val, span } => {
let chunked = series.utf8().map_err(|e| {
ShellError::GenericError(
"Error casting to string".into(),
e.to_string(),
Some(span),
None,
Vec::new(),
)
})?;
let res = chunked.set(bool_mask, Some(val.as_ref())).map_err(|e| {
ShellError::GenericError(
"Error setting value".into(),
e.to_string(),
Some(span),
None,
Vec::new(),
)
})?;
let mut res = res.into_series();
res.rename("string");
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
}
_ => Err(ShellError::GenericError(
"Incorrect value type".into(),
format!(
"this value cannot be set in a series of type '{}'",
series.dtype()
),
Some(value.span()?),
None,
Vec::new(),
)),
};
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 {}),
])
}
}

View File

@ -0,0 +1,95 @@
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
);
}

View File

@ -0,0 +1,79 @@
use super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
#[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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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])])
.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 {})])
}
}

View File

@ -0,0 +1,85 @@
use super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
#[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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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)],
)])
.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<PipelineData, ShellError> {
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<PipelineData, ShellError> {
let res = df.as_series(call.head)?.n_unique().map_err(|e| {
ShellError::GenericError(
"Error counting unique values".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
let value = Value::int(res as i64, call.head);
NuDataFrame::try_from_columns(vec![Column::new("count_unique".to_string(), vec![value])])
.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(NUnique {})])
}
}

View File

@ -0,0 +1,185 @@
use super::super::values::{Column, NuDataFrame};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type,
Value,
};
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<Self, ShellError> {
match roll_type {
"min" => Ok(Self::Min),
"max" => Ok(Self::Max),
"sum" => Ok(Self::Sum),
"mean" => Ok(Self::Mean),
_ => Err(ShellError::GenericError(
"Wrong operation".into(),
"Operation not valid for cumulative".into(),
Some(span),
Some("Allowed values: min, max, sum, mean".into()),
Vec::new(),
)),
}
}
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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),
],
)])
.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),
],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let roll_type: Spanned<String> = 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(
"Found object series".into(),
"Series of type object cannot be used for rolling operation".into(),
Some(call.head),
None,
Vec::new(),
));
}
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,
};
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 calculating rolling values".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,117 @@
use crate::dataframe::values::{NuExpression, NuLazyFrame};
use super::super::values::{Column, NuDataFrame};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
#[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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe or lazyframe".into()))
}
fn examples(&self) -> Vec<Example> {
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)],
)])
.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<PipelineData, ShellError> {
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<PipelineData, ShellError> {
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<PipelineData, ShellError> {
let shift: i64 = call.req(engine_state, stack, 0)?;
let fill: Option<Value> = 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(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 {})])
}
}

View File

@ -0,0 +1,117 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use polars::prelude::{IntoSeries, Utf8NameSpaceImpl};
#[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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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"),
],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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.utf8().map_err(|e| {
ShellError::GenericError(
"The concatenate only with string columns".into(),
e.to_string(),
Some(other_span),
None,
Vec::new(),
)
})?;
let series = df.as_series(call.head)?;
let chunked = series.utf8().map_err(|e| {
ShellError::GenericError(
"The concatenate only with string columns".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,108 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use polars::prelude::{IntoSeries, Utf8NameSpaceImpl};
#[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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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),
],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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.utf8().map_err(|e| {
ShellError::GenericError(
"The contains command only with string columns".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
let res = chunked.contains(&pattern, false).map_err(|e| {
ShellError::GenericError(
"Error searching in series".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,19 @@
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;

View File

@ -0,0 +1,122 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use polars::prelude::{IntoSeries, Utf8NameSpaceImpl};
#[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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Replaces string",
example: "[abc abc abc] | dfr into-df | dfr replace -p ab -r 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"),
],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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.utf8().map_err(|e| {
ShellError::GenericError(
"Error conversion to string".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
let mut res = chunked.replace(&pattern, &replace).map_err(|e| {
ShellError::GenericError(
"Error finding pattern other".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,122 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use polars::prelude::{IntoSeries, Utf8NameSpaceImpl};
#[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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Replaces string",
example: "[abac abac abac] | dfr into-df | dfr replace-all -p a -r 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"),
],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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.utf8().map_err(|e| {
ShellError::GenericError(
"Error conversion to string".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
let mut res = chunked.replace_all(&pattern, &replace).map_err(|e| {
ShellError::GenericError(
"Error finding pattern other".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,89 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
use polars::prelude::{IntoSeries, Utf8NameSpaceImpl};
#[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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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)],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let series = df.as_series(call.head)?;
let chunked = series.utf8().map_err(|e| {
ShellError::GenericError(
"Error casting to string".into(),
e.to_string(),
Some(call.head),
Some("The str-lengths command can only be used with string columns".into()),
Vec::new(),
)
})?;
let res = chunked.as_ref().str_lengths().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 {})])
}
}

View File

@ -0,0 +1,110 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use polars::prelude::{IntoSeries, Utf8NameSpaceImpl};
#[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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Creates slices from the strings",
example: "[abcded abc321 abc123] | dfr into-df | dfr str-slice 1 -l 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"),
],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let start: i64 = call.req(engine_state, stack, 0)?;
let length: Option<i64> = call.get_flag(engine_state, stack, "length")?;
let length = length.map(|v| v as u64);
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let series = df.as_series(call.head)?;
let chunked = series.utf8().map_err(|e| {
ShellError::GenericError(
"Error casting to string".into(),
e.to_string(),
Some(call.head),
Some("The str-slice command can only be used with string columns".into()),
Vec::new(),
)
})?;
let mut res = chunked.str_slice(start, length).map_err(|e| {
ShellError::GenericError(
"Error slicing series".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?;
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(StrSlice {})])
}
}

View File

@ -0,0 +1,109 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Formats date",
example: r#"let dt = ('2020-08-04T16:39:18+00:00' | into datetime -z '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"),
],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 casting to date".into(),
e.to_string(),
Some(call.head),
Some("The str-slice command can only be used with string columns".into()),
Vec::new(),
)
})?;
let res = casted
.strftime(&fmt)
.map_err(|e| {
ShellError::GenericError(
"Error formatting datetime".into(),
e.to_string(),
Some(call.head),
None,
Vec::new(),
)
})?
.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 {})])
}
}

View File

@ -0,0 +1,94 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
use polars::prelude::{IntoSeries, Utf8NameSpaceImpl};
#[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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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"),
],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let series = df.as_series(call.head)?;
let casted = series.utf8().map_err(|e| {
ShellError::GenericError(
"Error casting to string".into(),
e.to_string(),
Some(call.head),
Some("The str-slice command can only be used with string columns".into()),
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,98 @@
use super::super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
use polars::prelude::{IntoSeries, Utf8NameSpaceImpl};
#[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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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"),
],
)])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let series = df.as_series(call.head)?;
let casted = series.utf8().map_err(|e| {
ShellError::GenericError(
"Error casting to string".into(),
e.to_string(),
Some(call.head),
Some("The str-slice command can only be used with string columns".into()),
Vec::new(),
)
})?;
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 {})])
}
}

View File

@ -0,0 +1,151 @@
use crate::dataframe::{utils::extract_strings, values::NuLazyFrame};
use super::super::values::{Column, NuDataFrame};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe or lazyframe".into()))
}
fn examples(&self) -> Vec<Example> {
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)],
)])
.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<PipelineData, ShellError> {
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<PipelineData, ShellError> {
let series = df.as_series(call.head)?;
let res = series.unique().map_err(|e| {
ShellError::GenericError(
"Error calculating unique values".into(),
e.to_string(),
Some(call.head),
Some("The str-slice command can only be used with string columns".into()),
Vec::new(),
)
})?;
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<PipelineData, ShellError> {
let last = call.has_flag("last");
let maintain = call.has_flag("maintain-order");
let subset: Option<Value> = 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 {})])
}
}

View File

@ -0,0 +1,96 @@
use super::super::values::{Column, NuDataFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
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_type(Type::Custom("dataframe".into()))
.output_type(Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
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(
"counts".to_string(),
vec![Value::test_int(4), Value::test_int(2)],
),
])
.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<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 calculating value counts values".into(),
e.to_string(),
Some(call.head),
Some("The str-slice command can only be used with string columns".into()),
Vec::new(),
)
})?;
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 {})])
}
}