forked from extern/nushell
Migration of series commands (#515)
* corrected missing shellerror type * batch dataframe commands * removed option to find declaration with input * ordered dataframe folders * dataframe command name * series commands * date commands * series commands * series commands * clippy correction * rename commands
This commit is contained in:
parent
d8847f1082
commit
46b86f3541
@ -71,7 +71,11 @@ num = { version = "0.4.0", optional = true }
|
||||
[dependencies.polars]
|
||||
version = "0.18.0"
|
||||
optional = true
|
||||
features = ["default", "parquet", "json", "serde", "object", "checked_arithmetic", "strings"]
|
||||
features = [
|
||||
"default", "parquet", "json", "serde", "object",
|
||||
"checked_arithmetic", "strings", "cum_agg", "is_in",
|
||||
"rolling_window", "strings"
|
||||
]
|
||||
|
||||
[features]
|
||||
trash-support = ["trash"]
|
||||
@ -79,4 +83,4 @@ plugin = ["nu-parser/plugin"]
|
||||
dataframe = ["polars", "num"]
|
||||
|
||||
[build-dependencies]
|
||||
shadow-rs = "0.8.1"
|
||||
shadow-rs = "0.8.1"
|
||||
|
@ -12,7 +12,7 @@ pub struct AppendDF;
|
||||
|
||||
impl Command for AppendDF {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe append"
|
||||
"dfr append"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
@ -30,8 +30,8 @@ impl Command for AppendDF {
|
||||
vec![
|
||||
Example {
|
||||
description: "Appends a dataframe as new columns",
|
||||
example: r#"let a = ([[a b]; [1 2] [3 4]] | dataframe to-df);
|
||||
$a | dataframe append $a"#,
|
||||
example: r#"let a = ([[a b]; [1 2] [3 4]] | dfr to-df);
|
||||
$a | dfr append $a"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![
|
||||
Column::new("a".to_string(), vec![1.into(), 3.into()]),
|
||||
@ -45,9 +45,8 @@ $a | dataframe append $a"#,
|
||||
},
|
||||
Example {
|
||||
description: "Appends a dataframe merging at the end of columns",
|
||||
//example: r#"let a = ([[a b]; [1 2] [3 4]] | to df); $a | append-df $a -col"#,
|
||||
example: r#"let a = ([[a b]; [1 2] [3 4]] | dataframe to-df);
|
||||
$a | dataframe append $a --col"#,
|
||||
example: r#"let a = ([[a b]; [1 2] [3 4]] | dfr to-df);
|
||||
$a | dfr append $a --col"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![
|
||||
Column::new(
|
||||
@ -104,6 +103,6 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
test_dataframe(AppendDF {})
|
||||
test_dataframe(vec![Box::new(AppendDF {})])
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ pub struct ColumnDF;
|
||||
|
||||
impl Command for ColumnDF {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe column"
|
||||
"dfr column"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
@ -28,7 +28,7 @@ impl Command for ColumnDF {
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Returns the selected column as series",
|
||||
example: "[[a b]; [1 2] [3 4]] | dataframe to-df | dataframe column a",
|
||||
example: "[[a b]; [1 2] [3 4]] | dfr to-df | dfr column a",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"a".to_string(),
|
||||
@ -76,6 +76,6 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
test_dataframe(ColumnDF {})
|
||||
test_dataframe(vec![Box::new(ColumnDF {})])
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ pub struct Dataframe;
|
||||
|
||||
impl Command for Dataframe {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe"
|
||||
"dfr"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
|
@ -17,7 +17,7 @@ pub struct DescribeDF;
|
||||
|
||||
impl Command for DescribeDF {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe describe"
|
||||
"dfr describe"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
@ -31,7 +31,7 @@ impl Command for DescribeDF {
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "dataframe description",
|
||||
example: "[[a b]; [1 1] [1 1]] | dataframe to-df | dataframe describe",
|
||||
example: "[[a b]; [1 1] [1 1]] | dfr to-df | dfr describe",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![
|
||||
Column::new(
|
||||
@ -236,6 +236,6 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
test_dataframe(DescribeDF {})
|
||||
test_dataframe(vec![Box::new(DescribeDF {})])
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ pub struct DropDF;
|
||||
|
||||
impl Command for DropDF {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe drop"
|
||||
"dfr drop"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
@ -29,7 +29,7 @@ impl Command for DropDF {
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "drop column a",
|
||||
example: "[[a b]; [1 2] [3 4]] | dataframe to-df | dataframe drop a",
|
||||
example: "[[a b]; [1 2] [3 4]] | dfr to-df | dfr drop a",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"b".to_string(),
|
||||
@ -106,6 +106,6 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
test_dataframe(DropDF {})
|
||||
test_dataframe(vec![Box::new(DropDF {})])
|
||||
}
|
||||
}
|
||||
|
120
crates/nu-command/src/dataframe/drop_nulls.rs
Normal file
120
crates/nu-command/src/dataframe/drop_nulls.rs
Normal file
@ -0,0 +1,120 @@
|
||||
use nu_engine::CallExt;
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
|
||||
};
|
||||
|
||||
use super::values::utils::convert_columns;
|
||||
use super::values::{Column, NuDataFrame};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DropNulls;
|
||||
|
||||
impl Command for DropNulls {
|
||||
fn name(&self) -> &str {
|
||||
"dfr drop-nulls"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Drops null values in dataframe"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
.optional(
|
||||
"subset",
|
||||
SyntaxShape::Table,
|
||||
"subset of columns to drop nulls",
|
||||
)
|
||||
.category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "drop null values in dataframe",
|
||||
example: r#"let df = ([[a b]; [1 2] [3 0] [1 2]] | dfr to-df);
|
||||
let res = ($df.b / $df.b);
|
||||
let a = ($df | dfr with-column $res --name res);
|
||||
$a | dfr drop-nulls"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![
|
||||
Column::new("a".to_string(), vec![1.into(), 1.into()]),
|
||||
Column::new("b".to_string(), vec![2.into(), 2.into()]),
|
||||
Column::new("res".to_string(), vec![1.into(), 1.into()]),
|
||||
])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
},
|
||||
Example {
|
||||
description: "drop null values in dataframe",
|
||||
example: r#"let s = ([1 2 0 0 3 4] | dfr to-df);
|
||||
($s / $s) | dfr drop-nulls"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"div_0_0".to_string(),
|
||||
vec![1.into(), 1.into(), 1.into(), 1.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
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: Option<Vec<Value>> = call.opt(engine_state, stack, 0)?;
|
||||
|
||||
let (subset, col_span) = match columns {
|
||||
Some(cols) => {
|
||||
let (agg_string, col_span) = convert_columns(cols, call.head)?;
|
||||
let agg_string = agg_string
|
||||
.into_iter()
|
||||
.map(|col| col.item)
|
||||
.collect::<Vec<String>>();
|
||||
(Some(agg_string), col_span)
|
||||
}
|
||||
None => (None, Span::unknown()),
|
||||
};
|
||||
|
||||
let subset_slice = subset.as_ref().map(|cols| &cols[..]);
|
||||
|
||||
df.as_ref()
|
||||
.drop_nulls(subset_slice)
|
||||
.map_err(|e| {
|
||||
ShellError::SpannedLabeledError("Error dropping nulls".into(), e.to_string(), col_span)
|
||||
})
|
||||
.map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, call.head), None))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::test_dataframe::test_dataframe;
|
||||
use super::super::WithColumn;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
test_dataframe(vec![Box::new(DropNulls {}), Box::new(WithColumn {})])
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ pub struct DataTypes;
|
||||
|
||||
impl Command for DataTypes {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe dtypes"
|
||||
"dfr dtypes"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
@ -24,7 +24,7 @@ impl Command for DataTypes {
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Dataframe dtypes",
|
||||
example: "[[a b]; [1 2] [3 4]] | dataframe to-df | dataframe dtypes",
|
||||
example: "[[a b]; [1 2] [3 4]] | dfr to-df | dfr dtypes",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![
|
||||
Column::new(
|
||||
@ -101,6 +101,6 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
test_dataframe(DataTypes {})
|
||||
test_dataframe(vec![Box::new(DataTypes {})])
|
||||
}
|
||||
}
|
||||
|
@ -6,18 +6,24 @@ mod column;
|
||||
mod command;
|
||||
mod describe;
|
||||
mod drop;
|
||||
mod drop_nulls;
|
||||
mod dtypes;
|
||||
mod open;
|
||||
mod to_df;
|
||||
mod with_column;
|
||||
|
||||
pub use series::*;
|
||||
|
||||
pub use append::AppendDF;
|
||||
pub use column::ColumnDF;
|
||||
pub use command::Dataframe;
|
||||
pub use describe::DescribeDF;
|
||||
pub use drop::DropDF;
|
||||
pub use drop_nulls::DropNulls;
|
||||
pub use dtypes::DataTypes;
|
||||
pub use open::OpenDataFrame;
|
||||
pub use to_df::ToDataFrame;
|
||||
pub use with_column::WithColumn;
|
||||
|
||||
use nu_protocol::engine::StateWorkingSet;
|
||||
|
||||
@ -31,6 +37,53 @@ pub fn add_dataframe_decls(working_set: &mut StateWorkingSet) {
|
||||
};
|
||||
}
|
||||
|
||||
// Series commands
|
||||
bind_command!(
|
||||
AllFalse,
|
||||
AllTrue,
|
||||
ArgMax,
|
||||
ArgMin,
|
||||
ArgSort,
|
||||
ArgTrue,
|
||||
ArgUnique,
|
||||
Concatenate,
|
||||
Contains,
|
||||
Cumulative,
|
||||
GetDay,
|
||||
GetHour,
|
||||
GetMinute,
|
||||
GetMonth,
|
||||
GetNanosecond,
|
||||
GetOrdinal,
|
||||
GetSecond,
|
||||
GetWeek,
|
||||
GetWeekDay,
|
||||
GetYear,
|
||||
IsDuplicated,
|
||||
IsIn,
|
||||
IsNotNull,
|
||||
IsNull,
|
||||
IsUnique,
|
||||
NNull,
|
||||
NUnique,
|
||||
NotSeries,
|
||||
Rename,
|
||||
Replace,
|
||||
ReplaceAll,
|
||||
Rolling,
|
||||
SetSeries,
|
||||
SetWithIndex,
|
||||
Shift,
|
||||
StrLengths,
|
||||
StrSlice,
|
||||
StrFTime,
|
||||
ToLowerCase,
|
||||
ToUpperCase,
|
||||
Unique,
|
||||
ValueCount
|
||||
);
|
||||
|
||||
// Dataframe commands
|
||||
bind_command!(
|
||||
AppendDF,
|
||||
ColumnDF,
|
||||
@ -38,8 +91,10 @@ pub fn add_dataframe_decls(working_set: &mut StateWorkingSet) {
|
||||
DataTypes,
|
||||
DescribeDF,
|
||||
DropDF,
|
||||
DropNulls,
|
||||
OpenDataFrame,
|
||||
ToDataFrame
|
||||
ToDataFrame,
|
||||
WithColumn
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ pub struct OpenDataFrame;
|
||||
|
||||
impl Command for OpenDataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe open"
|
||||
"dfr open"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
@ -63,7 +63,7 @@ impl Command for OpenDataFrame {
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Takes a file name and creates a dataframe",
|
||||
example: "dataframe open test.csv",
|
||||
example: "dfr open test.csv",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
|
102
crates/nu-command/src/dataframe/series/all_false.rs
Normal file
102
crates/nu-command/src/dataframe/series/all_false.rs
Normal file
@ -0,0 +1,102 @@
|
||||
use super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span, 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()).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 to-df | dfr all-false",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"all_false".to_string(),
|
||||
vec![true.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
},
|
||||
Example {
|
||||
description: "Checks the result from a comparison",
|
||||
example: r#"let s = ([5 6 2 10] | dfr to-df);
|
||||
let res = ($s > 9);
|
||||
$res | dfr all-false"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"all_false".to_string(),
|
||||
vec![false.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error converting to bool".into(),
|
||||
"all-false only works with series of type bool".into(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let value = Value::Bool {
|
||||
val: bool.all_false(),
|
||||
span: 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 {})])
|
||||
}
|
||||
}
|
102
crates/nu-command/src/dataframe/series/all_true.rs
Normal file
102
crates/nu-command/src/dataframe/series/all_true.rs
Normal file
@ -0,0 +1,102 @@
|
||||
use super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span, 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()).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 to-df | dfr all-true",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"all_true".to_string(),
|
||||
vec![true.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
},
|
||||
Example {
|
||||
description: "Checks the result from a comparison",
|
||||
example: r#"let s = ([5 6 2 8] | dfr to-df);
|
||||
let res = ($s > 9);
|
||||
$res | dfr all-true"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"all_true".to_string(),
|
||||
vec![false.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error converting to bool".into(),
|
||||
"all-false only works with series of type bool".into(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let value = Value::Bool {
|
||||
val: bool.all_true(),
|
||||
span: 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 {})])
|
||||
}
|
||||
}
|
81
crates/nu-command/src/dataframe/series/arg_max.rs
Normal file
81
crates/nu-command/src/dataframe/series/arg_max.rs
Normal file
@ -0,0 +1,81 @@
|
||||
use super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
use polars::prelude::{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 signature(&self) -> Signature {
|
||||
Signature::build(self.name()).category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Returns index for max value",
|
||||
example: "[1 3 2] | dfr to-df | dfr arg-max",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"arg_max".to_string(),
|
||||
vec![1.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::new_from_slice("arg_max", &[index as u32]),
|
||||
None => UInt32Chunked::new_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 {})])
|
||||
}
|
||||
}
|
81
crates/nu-command/src/dataframe/series/arg_min.rs
Normal file
81
crates/nu-command/src/dataframe/series/arg_min.rs
Normal file
@ -0,0 +1,81 @@
|
||||
use super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
use polars::prelude::{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 signature(&self) -> Signature {
|
||||
Signature::build(self.name()).category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Returns index for min value",
|
||||
example: "[1 3 2] | dfr to-df | dfr arg-min",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"arg_min".to_string(),
|
||||
vec![0.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::new_from_slice("arg_min", &[index as u32]),
|
||||
None => UInt32Chunked::new_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 {})])
|
||||
}
|
||||
}
|
129
crates/nu-command/src/dataframe/series/cumulative.rs
Normal file
129
crates/nu-command/src/dataframe/series/cumulative.rs
Normal file
@ -0,0 +1,129 @@
|
||||
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,
|
||||
};
|
||||
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::SpannedLabeledErrorHelp(
|
||||
"Wrong operation".into(),
|
||||
"Operation not valid for cumulative".into(),
|
||||
span,
|
||||
"Allowed values: max, min, sum".into(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
CumType::Min => "cum_min",
|
||||
CumType::Max => "cum_max",
|
||||
CumType::Sum => "cum_sum",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Cumulative;
|
||||
|
||||
impl Command for Cumulative {
|
||||
fn name(&self) -> &str {
|
||||
"dfr cum"
|
||||
}
|
||||
|
||||
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'))
|
||||
.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 to-df | dfr cum sum",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0_cum_sum".to_string(),
|
||||
vec![1.into(), 3.into(), 6.into(), 10.into(), 15.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Found object series".into(),
|
||||
"Series of type object cannot be used for cumulative operation".into(),
|
||||
call.head,
|
||||
));
|
||||
}
|
||||
|
||||
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 {})])
|
||||
}
|
||||
}
|
87
crates/nu-command/src/dataframe/series/date/get_day.rs
Normal file
87
crates/nu-command/src/dataframe/series/date/get_day.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
use polars::prelude::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()).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 to-df);
|
||||
$df | dfr get-day"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![4.into(), 4.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let res = casted.day().into_series();
|
||||
|
||||
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::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 {})])
|
||||
}
|
||||
}
|
87
crates/nu-command/src/dataframe/series/date/get_hour.rs
Normal file
87
crates/nu-command/src/dataframe/series/date/get_hour.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
use polars::prelude::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()).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 to-df);
|
||||
$df | dfr get-hour"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![16.into(), 16.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let res = casted.hour().into_series();
|
||||
|
||||
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::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 {})])
|
||||
}
|
||||
}
|
87
crates/nu-command/src/dataframe/series/date/get_minute.rs
Normal file
87
crates/nu-command/src/dataframe/series/date/get_minute.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
use polars::prelude::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()).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 to-df);
|
||||
$df | dfr get-minute"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![39.into(), 39.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let res = casted.minute().into_series();
|
||||
|
||||
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::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 {})])
|
||||
}
|
||||
}
|
87
crates/nu-command/src/dataframe/series/date/get_month.rs
Normal file
87
crates/nu-command/src/dataframe/series/date/get_month.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
use polars::prelude::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()).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 to-df);
|
||||
$df | dfr get-month"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![8.into(), 8.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let res = casted.month().into_series();
|
||||
|
||||
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::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 {})])
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
use polars::prelude::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()).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 to-df);
|
||||
$df | dfr get-nanosecond"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![0.into(), 0.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let res = casted.nanosecond().into_series();
|
||||
|
||||
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::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 {})])
|
||||
}
|
||||
}
|
87
crates/nu-command/src/dataframe/series/date/get_ordinal.rs
Normal file
87
crates/nu-command/src/dataframe/series/date/get_ordinal.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
use polars::prelude::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()).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 to-df);
|
||||
$df | dfr get-ordinal"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![217.into(), 217.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let res = casted.ordinal().into_series();
|
||||
|
||||
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::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 {})])
|
||||
}
|
||||
}
|
87
crates/nu-command/src/dataframe/series/date/get_second.rs
Normal file
87
crates/nu-command/src/dataframe/series/date/get_second.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
use polars::prelude::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()).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 to-df);
|
||||
$df | dfr get-second"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![18.into(), 18.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let res = casted.second().into_series();
|
||||
|
||||
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::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 {})])
|
||||
}
|
||||
}
|
87
crates/nu-command/src/dataframe/series/date/get_week.rs
Normal file
87
crates/nu-command/src/dataframe/series/date/get_week.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
use polars::prelude::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()).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 to-df);
|
||||
$df | dfr get-week"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![32.into(), 32.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let res = casted.week().into_series();
|
||||
|
||||
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::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 {})])
|
||||
}
|
||||
}
|
87
crates/nu-command/src/dataframe/series/date/get_weekday.rs
Normal file
87
crates/nu-command/src/dataframe/series/date/get_weekday.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
use polars::prelude::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()).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 to-df);
|
||||
$df | dfr get-weekday"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![1.into(), 1.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let res = casted.weekday().into_series();
|
||||
|
||||
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::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 {})])
|
||||
}
|
||||
}
|
87
crates/nu-command/src/dataframe/series/date/get_year.rs
Normal file
87
crates/nu-command/src/dataframe/series/date/get_year.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
use polars::prelude::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()).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 to-df);
|
||||
$df | dfr get-year"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![2020.into(), 2020.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error casting to datetime type".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let res = casted.year().into_series();
|
||||
|
||||
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::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 {})])
|
||||
}
|
||||
}
|
21
crates/nu-command/src/dataframe/series/date/mod.rs
Normal file
21
crates/nu-command/src/dataframe/series/date/mod.rs
Normal file
@ -0,0 +1,21 @@
|
||||
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 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;
|
95
crates/nu-command/src/dataframe/series/indexes/arg_sort.rs
Normal file
95
crates/nu-command/src/dataframe/series/indexes/arg_sort.rs
Normal 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,
|
||||
};
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
#[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 signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
.switch("reverse", "reverse order", Some('r'))
|
||||
.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 to-df | dfr arg-sort",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"arg_sort".to_string(),
|
||||
vec![0.into(), 1.into(), 2.into(), 3.into(), 4.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
},
|
||||
Example {
|
||||
description: "Returns indexes for a sorted series",
|
||||
example: "[1 2 2 3 3] | dfr to-df | dfr arg-sort -r",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"arg_sort".to_string(),
|
||||
vec![3.into(), 4.into(), 1.into(), 2.into(), 0.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
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)?
|
||||
.argsort(call.has_flag("reverse"))
|
||||
.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 {})])
|
||||
}
|
||||
}
|
85
crates/nu-command/src/dataframe/series/indexes/arg_true.rs
Normal file
85
crates/nu-command/src/dataframe/series/indexes/arg_true.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
#[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 signature(&self) -> Signature {
|
||||
Signature::build(self.name()).category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Returns indexes where values are true",
|
||||
example: "[$false $true $false] | dfr to-df | dfr arg-true",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"arg_true".to_string(),
|
||||
vec![1.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error converting to bool".into(),
|
||||
"all-false only works with series of type bool".into(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let mut res = bool.arg_true().into_series();
|
||||
res.rename("arg_true");
|
||||
|
||||
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(ArgTrue {})])
|
||||
}
|
||||
}
|
86
crates/nu-command/src/dataframe/series/indexes/arg_unique.rs
Normal file
86
crates/nu-command/src/dataframe/series/indexes/arg_unique.rs
Normal file
@ -0,0 +1,86 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
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 signature(&self) -> Signature {
|
||||
Signature::build(self.name()).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 to-df | dfr arg-unique",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"arg_unique".to_string(),
|
||||
vec![0.into(), 1.into(), 3.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error extracting unique values".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?
|
||||
.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 {})])
|
||||
}
|
||||
}
|
9
crates/nu-command/src/dataframe/series/indexes/mod.rs
Normal file
9
crates/nu-command/src/dataframe/series/indexes/mod.rs
Normal 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;
|
179
crates/nu-command/src/dataframe/series/indexes/set_with_idx.rs
Normal file
179
crates/nu-command/src/dataframe/series/indexes/set_with_idx.rs
Normal file
@ -0,0 +1,179 @@
|
||||
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, 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'),
|
||||
)
|
||||
.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 to-df);
|
||||
let indices = ([0 2] | dfr to-df);
|
||||
$series | dfr set-with-idx 6 -i $indices"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![6.into(), 1.into(), 6.into(), 2.into(), 4.into(), 3.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error casting indices".into(),
|
||||
e.to_string(),
|
||||
indices_span,
|
||||
)
|
||||
})
|
||||
}
|
||||
_ => Err(ShellError::SpannedLabeledErrorHelp(
|
||||
"Incorrect type".into(),
|
||||
"Series with incorrect type".into(),
|
||||
indices_span,
|
||||
"Consider using a Series with type int type".into(),
|
||||
)),
|
||||
}?;
|
||||
|
||||
let indices = casted
|
||||
.u32()
|
||||
.map_err(|e| {
|
||||
ShellError::SpannedLabeledError(
|
||||
"Error casting indices".into(),
|
||||
e.to_string(),
|
||||
indices_span,
|
||||
)
|
||||
})?
|
||||
.into_iter()
|
||||
.filter_map(|val| val.map(|v| v as usize));
|
||||
|
||||
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::SpannedLabeledError("Error casting to i64".into(), e.to_string(), span)
|
||||
})?;
|
||||
|
||||
let res = chunked.set_at_idx(indices, Some(val)).map_err(|e| {
|
||||
ShellError::SpannedLabeledError("Error setting value".into(), e.to_string(), span)
|
||||
})?;
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
Value::Float { val, span } => {
|
||||
let chunked = series.as_ref().f64().map_err(|e| {
|
||||
ShellError::SpannedLabeledError("Error casting to f64".into(), e.to_string(), span)
|
||||
})?;
|
||||
|
||||
let res = chunked.set_at_idx(indices, Some(val)).map_err(|e| {
|
||||
ShellError::SpannedLabeledError("Error setting value".into(), e.to_string(), span)
|
||||
})?;
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
Value::String { val, span } => {
|
||||
let chunked = series.as_ref().utf8().map_err(|e| {
|
||||
ShellError::SpannedLabeledError(
|
||||
"Error casting to string".into(),
|
||||
e.to_string(),
|
||||
span,
|
||||
)
|
||||
})?;
|
||||
|
||||
let res = chunked
|
||||
.set_at_idx(indices, Some(val.as_ref()))
|
||||
.map_err(|e| {
|
||||
ShellError::SpannedLabeledError(
|
||||
"Error setting value".into(),
|
||||
e.to_string(),
|
||||
span,
|
||||
)
|
||||
})?;
|
||||
|
||||
let mut res = res.into_series();
|
||||
res.rename("string");
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
_ => Err(ShellError::SpannedLabeledError(
|
||||
"Incorrect value type".into(),
|
||||
format!(
|
||||
"this value cannot be set in a series of type '{}'",
|
||||
series.dtype()
|
||||
),
|
||||
value.span()?,
|
||||
)),
|
||||
};
|
||||
|
||||
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 {})])
|
||||
}
|
||||
}
|
@ -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,
|
||||
};
|
||||
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()).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 to-df | dfr is-duplicated",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"is_duplicated".to_string(),
|
||||
vec![
|
||||
false.into(),
|
||||
true.into(),
|
||||
true.into(),
|
||||
true.into(),
|
||||
true.into(),
|
||||
true.into(),
|
||||
true.into(),
|
||||
],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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)?
|
||||
.is_duplicated()
|
||||
.map_err(|e| {
|
||||
ShellError::SpannedLabeledError(
|
||||
"Error finding duplicates".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?
|
||||
.into_series();
|
||||
|
||||
res.rename("is_duplicated");
|
||||
|
||||
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(IsDuplicated {})])
|
||||
}
|
||||
}
|
104
crates/nu-command/src/dataframe/series/masks/is_in.rs
Normal file
104
crates/nu-command/src/dataframe/series/masks/is_in.rs
Normal file
@ -0,0 +1,104 @@
|
||||
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, 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")
|
||||
.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 to-df);
|
||||
[5 6 6 6 8 8 8] | dfr to-df | dfr is-in $other"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"is_in".to_string(),
|
||||
vec![
|
||||
false.into(),
|
||||
true.into(),
|
||||
true.into(),
|
||||
true.into(),
|
||||
false.into(),
|
||||
false.into(),
|
||||
false.into(),
|
||||
],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error finding in other".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?
|
||||
.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 {})])
|
||||
}
|
||||
}
|
78
crates/nu-command/src/dataframe/series/masks/is_not_null.rs
Normal file
78
crates/nu-command/src/dataframe/series/masks/is_not_null.rs
Normal file
@ -0,0 +1,78 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
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()).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 to-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![true.into(), true.into(), false.into(), true.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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)?.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 {})])
|
||||
}
|
||||
}
|
78
crates/nu-command/src/dataframe/series/masks/is_null.rs
Normal file
78
crates/nu-command/src/dataframe/series/masks/is_null.rs
Normal file
@ -0,0 +1,78 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
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()).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 to-df);
|
||||
let res = ($s / $s);
|
||||
$res | dfr is-null"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"is_null".to_string(),
|
||||
vec![false.into(), false.into(), true.into(), false.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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)?.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 {})])
|
||||
}
|
||||
}
|
90
crates/nu-command/src/dataframe/series/masks/is_unique.rs
Normal file
90
crates/nu-command/src/dataframe/series/masks/is_unique.rs
Normal file
@ -0,0 +1,90 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
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()).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 to-df | dfr is-unique",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"is_unique".to_string(),
|
||||
vec![
|
||||
true.into(),
|
||||
false.into(),
|
||||
false.into(),
|
||||
false.into(),
|
||||
false.into(),
|
||||
false.into(),
|
||||
false.into(),
|
||||
],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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)?.is_unique().map_err(|e| {
|
||||
ShellError::SpannedLabeledError(
|
||||
"Error finding unique values".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
res.rename("is_unique");
|
||||
|
||||
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(IsUnique {})])
|
||||
}
|
||||
}
|
15
crates/nu-command/src/dataframe/series/masks/mod.rs
Normal file
15
crates/nu-command/src/dataframe/series/masks/mod.rs
Normal 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;
|
82
crates/nu-command/src/dataframe/series/masks/not.rs
Normal file
82
crates/nu-command/src/dataframe/series/masks/not.rs
Normal file
@ -0,0 +1,82 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
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()).category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Inverts boolean mask",
|
||||
example: "[$true $false $true] | dfr to-df | dfr not",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![false.into(), true.into(), false.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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(|e| {
|
||||
ShellError::SpannedLabeledError("Error inverting mask".into(), e.to_string(), call.head)
|
||||
})?;
|
||||
|
||||
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 {})])
|
||||
}
|
||||
}
|
163
crates/nu-command/src/dataframe/series/masks/set.rs
Normal file
163
crates/nu-command/src/dataframe/series/masks/set.rs
Normal file
@ -0,0 +1,163 @@
|
||||
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, 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'),
|
||||
)
|
||||
.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 to-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![0.into(), 0.into(), 1.into(), 2.into(), 2.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error casting to bool".into(),
|
||||
e.to_string(),
|
||||
mask_span,
|
||||
)
|
||||
}),
|
||||
_ => Err(ShellError::SpannedLabeledError(
|
||||
"Incorrect type".into(),
|
||||
"can only use bool series as mask".into(),
|
||||
mask_span,
|
||||
)),
|
||||
}?;
|
||||
|
||||
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::SpannedLabeledError("Error casting to i64".into(), e.to_string(), span)
|
||||
})?;
|
||||
|
||||
let res = chunked.set(bool_mask, Some(val)).map_err(|e| {
|
||||
ShellError::SpannedLabeledError("Error setting value".into(), e.to_string(), span)
|
||||
})?;
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
Value::Float { val, span } => {
|
||||
let chunked = series.as_ref().f64().map_err(|e| {
|
||||
ShellError::SpannedLabeledError("Error casting to f64".into(), e.to_string(), span)
|
||||
})?;
|
||||
|
||||
let res = chunked.set(bool_mask, Some(val)).map_err(|e| {
|
||||
ShellError::SpannedLabeledError("Error setting value".into(), e.to_string(), span)
|
||||
})?;
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
Value::String { val, span } => {
|
||||
let chunked = series.as_ref().utf8().map_err(|e| {
|
||||
ShellError::SpannedLabeledError(
|
||||
"Error casting to string".into(),
|
||||
e.to_string(),
|
||||
span,
|
||||
)
|
||||
})?;
|
||||
|
||||
let res = chunked.set(bool_mask, Some(val.as_ref())).map_err(|e| {
|
||||
ShellError::SpannedLabeledError("Error setting value".into(), e.to_string(), span)
|
||||
})?;
|
||||
|
||||
let mut res = res.into_series();
|
||||
res.rename("string");
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
_ => Err(ShellError::SpannedLabeledError(
|
||||
"Incorrect value type".into(),
|
||||
format!(
|
||||
"this value cannot be set in a series of type '{}'",
|
||||
series.dtype()
|
||||
),
|
||||
value.span()?,
|
||||
)),
|
||||
};
|
||||
|
||||
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 {}),
|
||||
])
|
||||
}
|
||||
}
|
@ -1 +1,37 @@
|
||||
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 rename;
|
||||
mod rolling;
|
||||
mod shift;
|
||||
mod unique;
|
||||
mod value_counts;
|
||||
|
||||
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 rename::Rename;
|
||||
pub use rolling::Rolling;
|
||||
pub use shift::Shift;
|
||||
pub use unique::Unique;
|
||||
pub use value_counts::ValueCount;
|
||||
|
79
crates/nu-command/src/dataframe/series/n_null.rs
Normal file
79
crates/nu-command/src/dataframe/series/n_null.rs
Normal 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, 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()).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 to-df);
|
||||
($s / $s) | dfr count-null"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"count_null".to_string(),
|
||||
vec![2.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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 {
|
||||
val: res as i64,
|
||||
span: 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 {})])
|
||||
}
|
||||
}
|
85
crates/nu-command/src/dataframe/series/n_unique.rs
Normal file
85
crates/nu-command/src/dataframe/series/n_unique.rs
Normal 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, Value,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct NUnique;
|
||||
|
||||
impl Command for NUnique {
|
||||
fn name(&self) -> &str {
|
||||
"dfr count-unique"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Counts unique values"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name()).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 to-df | dfr count-unique",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"count_unique".to_string(),
|
||||
vec![4.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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)?.n_unique().map_err(|e| {
|
||||
ShellError::SpannedLabeledError(
|
||||
"Error counting unique values".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let value = Value::Int {
|
||||
val: res as i64,
|
||||
span: 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 {})])
|
||||
}
|
||||
}
|
79
crates/nu-command/src/dataframe/series/rename.rs
Normal file
79
crates/nu-command/src/dataframe/series/rename.rs
Normal file
@ -0,0 +1,79 @@
|
||||
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,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Rename;
|
||||
|
||||
impl Command for Rename {
|
||||
fn name(&self) -> &str {
|
||||
"dfr rename"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Renames a series"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
.required("name", SyntaxShape::String, "new series name")
|
||||
.category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Renames a series",
|
||||
example: "[5 6 7 8] | dfr to-df | dfr rename new_name",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"new_name".to_string(),
|
||||
vec![5.into(), 6.into(), 7.into(), 8.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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 name: String = call.req(engine_state, stack, 0)?;
|
||||
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let mut series = df.as_series(call.head)?;
|
||||
series.rename(&name);
|
||||
|
||||
NuDataFrame::try_from_series(vec![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(Rename {})])
|
||||
}
|
||||
}
|
163
crates/nu-command/src/dataframe/series/rolling.rs
Normal file
163
crates/nu-command/src/dataframe/series/rolling.rs
Normal file
@ -0,0 +1,163 @@
|
||||
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,
|
||||
};
|
||||
use polars::prelude::{DataType, IntoSeries, RollingOptions};
|
||||
|
||||
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::SpannedLabeledErrorHelp(
|
||||
"Wrong operation".into(),
|
||||
"Operation not valid for cumulative".into(),
|
||||
span,
|
||||
"Allowed values: min, max, sum, mean".into(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
.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 to-df | dfr rolling sum 2 | dfr drop-nulls",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0_rolling_sum".to_string(),
|
||||
vec![3.into(), 5.into(), 7.into(), 9.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
},
|
||||
Example {
|
||||
description: "Rolling max for a series",
|
||||
example: "[1 2 3 4 5] | dfr to-df | dfr rolling max 2 | dfr drop-nulls",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0_rolling_max".to_string(),
|
||||
vec![2.into(), 3.into(), 4.into(), 5.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
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: usize = 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::SpannedLabeledError(
|
||||
"Found object series".into(),
|
||||
"Series of type object cannot be used for rolling operation".into(),
|
||||
call.head,
|
||||
));
|
||||
}
|
||||
|
||||
let roll_type = RollType::from_str(&roll_type.item, roll_type.span)?;
|
||||
|
||||
let rolling_opts = RollingOptions {
|
||||
window_size,
|
||||
min_periods: window_size,
|
||||
weights: None,
|
||||
center: false,
|
||||
};
|
||||
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::SpannedLabeledError(
|
||||
"Error calculating rolling values".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
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::test_dataframe::test_dataframe;
|
||||
use super::super::super::DropNulls;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
test_dataframe(vec![Box::new(Rolling {}), Box::new(DropNulls {})])
|
||||
}
|
||||
}
|
79
crates/nu-command/src/dataframe/series/shift.rs
Normal file
79
crates/nu-command/src/dataframe/series/shift.rs
Normal file
@ -0,0 +1,79 @@
|
||||
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,
|
||||
};
|
||||
|
||||
#[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")
|
||||
.category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Shifts the values by a given period",
|
||||
example: "[1 2 2 3 3] | dfr to-df | dfr shift 2 | dfr drop-nulls",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![1.into(), 2.into(), 2.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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 period: i64 = call.req(engine_state, stack, 0)?;
|
||||
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
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))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::super::test_dataframe::test_dataframe;
|
||||
use super::super::super::DropNulls;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
test_dataframe(vec![Box::new(Shift {}), Box::new(DropNulls {})])
|
||||
}
|
||||
}
|
111
crates/nu-command/src/dataframe/series/string/concatenate.rs
Normal file
111
crates/nu-command/src/dataframe/series/string/concatenate.rs
Normal file
@ -0,0 +1,111 @@
|
||||
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, Value,
|
||||
};
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
#[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",
|
||||
)
|
||||
.category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Concatenate string",
|
||||
example: r#"let other = ([za xs cd] | dfr to-df);
|
||||
[abc abc abc] | dfr to-df | dfr concatenate $other"#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![
|
||||
"abcza".to_string().into(),
|
||||
"abcxs".to_string().into(),
|
||||
"abccd".to_string().into(),
|
||||
],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"The concatenate only with string columns".into(),
|
||||
e.to_string(),
|
||||
other_span,
|
||||
)
|
||||
})?;
|
||||
|
||||
let series = df.as_series(call.head)?;
|
||||
let chunked = series.utf8().map_err(|e| {
|
||||
ShellError::SpannedLabeledError(
|
||||
"The concatenate only with string columns".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
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 {})])
|
||||
}
|
||||
}
|
98
crates/nu-command/src/dataframe/series/string/contains.rs
Normal file
98
crates/nu-command/src/dataframe/series/string/contains.rs
Normal file
@ -0,0 +1,98 @@
|
||||
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,
|
||||
};
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
#[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",
|
||||
)
|
||||
.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 to-df | dfr contains ab",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![true.into(), false.into(), false.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"The contains command only with string columns".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let res = chunked.contains(&pattern).map_err(|e| {
|
||||
ShellError::SpannedLabeledError(
|
||||
"Error searching in series".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
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 {})])
|
||||
}
|
||||
}
|
19
crates/nu-command/src/dataframe/series/string/mod.rs
Normal file
19
crates/nu-command/src/dataframe/series/string/mod.rs
Normal 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;
|
116
crates/nu-command/src/dataframe/series/string/replace.rs
Normal file
116
crates/nu-command/src/dataframe/series/string/replace.rs
Normal file
@ -0,0 +1,116 @@
|
||||
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,
|
||||
};
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
#[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'),
|
||||
)
|
||||
.category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Replaces string",
|
||||
example: "[abc abc abc] | dfr to-df | dfr replace -p ab -r AB",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![
|
||||
"ABc".to_string().into(),
|
||||
"ABc".to_string().into(),
|
||||
"ABc".to_string().into(),
|
||||
],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error convertion to string".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let mut res = chunked.replace(&pattern, &replace).map_err(|e| {
|
||||
ShellError::SpannedLabeledError(
|
||||
"Error finding pattern other".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
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 {})])
|
||||
}
|
||||
}
|
116
crates/nu-command/src/dataframe/series/string/replace_all.rs
Normal file
116
crates/nu-command/src/dataframe/series/string/replace_all.rs
Normal file
@ -0,0 +1,116 @@
|
||||
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,
|
||||
};
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
#[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'),
|
||||
)
|
||||
.category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Replaces string",
|
||||
example: "[abac abac abac] | dfr to-df | dfr replace-all -p a -r A",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![
|
||||
"AbAc".to_string().into(),
|
||||
"AbAc".to_string().into(),
|
||||
"AbAc".to_string().into(),
|
||||
],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledError(
|
||||
"Error convertion to string".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let mut res = chunked.replace_all(&pattern, &replace).map_err(|e| {
|
||||
ShellError::SpannedLabeledError(
|
||||
"Error finding pattern other".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
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 {})])
|
||||
}
|
||||
}
|
85
crates/nu-command/src/dataframe/series/string/str_lengths.rs
Normal file
85
crates/nu-command/src/dataframe/series/string/str_lengths.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
#[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()).category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Returns string lengths",
|
||||
example: "[a ab abc] | dfr to-df | dfr str-lengths",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![1.into(), 2.into(), 3.into()],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledErrorHelp(
|
||||
"Error casting to string".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
"The str-lengths command can only be used with string columns".into(),
|
||||
)
|
||||
})?;
|
||||
|
||||
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 {})])
|
||||
}
|
||||
}
|
101
crates/nu-command/src/dataframe/series/string/str_slice.rs
Normal file
101
crates/nu-command/src/dataframe/series/string/str_slice.rs
Normal file
@ -0,0 +1,101 @@
|
||||
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,
|
||||
};
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
#[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'))
|
||||
.category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Creates slices from the strings",
|
||||
example: "[abcded abc321 abc123] | dfr to-df | dfr str-slice 1 -l 2",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![
|
||||
"bc".to_string().into(),
|
||||
"bc".to_string().into(),
|
||||
"bc".to_string().into(),
|
||||
],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledErrorHelp(
|
||||
"Error casting to string".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
"The str-slice command can only be used with string columns".into(),
|
||||
)
|
||||
})?;
|
||||
|
||||
let mut res = chunked.str_slice(start, length).map_err(|e| {
|
||||
ShellError::SpannedLabeledError("Error slicing series".into(), e.to_string(), call.head)
|
||||
})?;
|
||||
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 {})])
|
||||
}
|
||||
}
|
96
crates/nu-command/src/dataframe/series/string/strftime.rs
Normal file
96
crates/nu-command/src/dataframe/series/string/strftime.rs
Normal file
@ -0,0 +1,96 @@
|
||||
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,
|
||||
};
|
||||
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")
|
||||
.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 to-df);
|
||||
$df | dfr strftime "%Y/%m/%d""#,
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![
|
||||
"2020/08/04".to_string().into(),
|
||||
"2020/08/04".to_string().into(),
|
||||
],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledErrorHelp(
|
||||
"Error casting to date".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
"The str-slice command can only be used with string columns".into(),
|
||||
)
|
||||
})?;
|
||||
|
||||
let res = casted.strftime(&fmt).into_series();
|
||||
|
||||
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::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 {})])
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ToLowerCase;
|
||||
|
||||
impl Command for ToLowerCase {
|
||||
fn name(&self) -> &str {
|
||||
"dfr to-lowercase"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Lowercase the strings in the column"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name()).category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Modifies strings to lowercase",
|
||||
example: "[Abc aBc abC] | dfr to-df | dfr to-lowercase",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![
|
||||
"abc".to_string().into(),
|
||||
"abc".to_string().into(),
|
||||
"abc".to_string().into(),
|
||||
],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledErrorHelp(
|
||||
"Error casting to string".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
"The str-slice command can only be used with string columns".into(),
|
||||
)
|
||||
})?;
|
||||
|
||||
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 {})])
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
use super::super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ToUpperCase;
|
||||
|
||||
impl Command for ToUpperCase {
|
||||
fn name(&self) -> &str {
|
||||
"dfr to-uppercase"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Uppercase the strings in the column"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name()).category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Modifies strings to uppercase",
|
||||
example: "[Abc aBc abC] | dfr to-df | dfr to-uppercase",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
vec![
|
||||
"ABC".to_string().into(),
|
||||
"ABC".to_string().into(),
|
||||
"ABC".to_string().into(),
|
||||
],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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::SpannedLabeledErrorHelp(
|
||||
"Error casting to string".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
"The str-slice command can only be used with string columns".into(),
|
||||
)
|
||||
})?;
|
||||
|
||||
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 {})])
|
||||
}
|
||||
}
|
80
crates/nu-command/src/dataframe/series/unique.rs
Normal file
80
crates/nu-command/src/dataframe/series/unique.rs
Normal file
@ -0,0 +1,80 @@
|
||||
use super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
use polars::prelude::IntoSeries;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Unique;
|
||||
|
||||
impl Command for Unique {
|
||||
fn name(&self) -> &str {
|
||||
"dfr unique"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Returns unique values from a series"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name()).category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Returns unique values from a series",
|
||||
example: "[2 2 2 2 2] | dfr to-df | dfr unique",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new("0".to_string(), vec![2.into()])])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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.unique().map_err(|e| {
|
||||
ShellError::SpannedLabeledErrorHelp(
|
||||
"Error calculating unique values".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
"The str-slice command can only be used with string columns".into(),
|
||||
)
|
||||
})?;
|
||||
|
||||
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(Unique {})])
|
||||
}
|
||||
}
|
84
crates/nu-command/src/dataframe/series/value_counts.rs
Normal file
84
crates/nu-command/src/dataframe/series/value_counts.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use super::super::values::{Column, NuDataFrame};
|
||||
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span,
|
||||
};
|
||||
|
||||
#[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()).category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Calculates value counts",
|
||||
example: "[5 5 5 5 6 6] | dfr to-df | dfr value-counts",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![
|
||||
Column::new("0".to_string(), vec![5.into(), 6.into()]),
|
||||
Column::new("counts".to_string(), vec![4.into(), 2.into()]),
|
||||
])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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().map_err(|e| {
|
||||
ShellError::SpannedLabeledErrorHelp(
|
||||
"Error calculating value counts values".into(),
|
||||
e.to_string(),
|
||||
call.head,
|
||||
"The str-slice command can only be used with string columns".into(),
|
||||
)
|
||||
})?;
|
||||
|
||||
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 {})])
|
||||
}
|
||||
}
|
@ -8,8 +8,13 @@ use nu_protocol::{
|
||||
use super::ToDataFrame;
|
||||
use crate::Let;
|
||||
|
||||
pub fn test_dataframe(cmd: impl Command + 'static) {
|
||||
let examples = cmd.examples();
|
||||
pub fn test_dataframe(cmds: Vec<Box<dyn Command + 'static>>) {
|
||||
if cmds.is_empty() {
|
||||
panic!("Empty commands vector")
|
||||
}
|
||||
|
||||
// The first element in the cmds vector must be the one tested
|
||||
let examples = cmds[0].examples();
|
||||
let mut engine_state = Box::new(EngineState::new());
|
||||
|
||||
let delta = {
|
||||
@ -20,7 +25,9 @@ pub fn test_dataframe(cmd: impl Command + 'static) {
|
||||
working_set.add_decl(Box::new(ToDataFrame));
|
||||
|
||||
// Adding the command that is being tested to the working set
|
||||
working_set.add_decl(Box::new(cmd));
|
||||
for cmd in cmds {
|
||||
working_set.add_decl(cmd);
|
||||
}
|
||||
|
||||
working_set.render()
|
||||
};
|
||||
|
@ -11,7 +11,7 @@ pub struct ToDataFrame;
|
||||
|
||||
impl Command for ToDataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe to-df"
|
||||
"dfr to-df"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
@ -26,7 +26,7 @@ impl Command for ToDataFrame {
|
||||
vec![
|
||||
Example {
|
||||
description: "Takes a dictionary and creates a dataframe",
|
||||
example: "[[a b];[1 2] [3 4]] | dataframe to-df",
|
||||
example: "[[a b];[1 2] [3 4]] | dfr to-df",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![
|
||||
Column::new("a".to_string(), vec![1.into(), 3.into()]),
|
||||
@ -38,7 +38,7 @@ impl Command for ToDataFrame {
|
||||
},
|
||||
Example {
|
||||
description: "Takes a list of tables and creates a dataframe",
|
||||
example: "[[1 2 a] [3 4 b] [5 6 c]] | dataframe to-df",
|
||||
example: "[[1 2 a] [3 4 b] [5 6 c]] | dfr to-df",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![
|
||||
Column::new("0".to_string(), vec![1.into(), 3.into(), 5.into()]),
|
||||
@ -58,7 +58,7 @@ impl Command for ToDataFrame {
|
||||
},
|
||||
Example {
|
||||
description: "Takes a list and creates a dataframe",
|
||||
example: "[a b c] | dataframe to-df",
|
||||
example: "[a b c] | dfr to-df",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
@ -74,7 +74,7 @@ impl Command for ToDataFrame {
|
||||
},
|
||||
Example {
|
||||
description: "Takes a list of booleans and creates a dataframe",
|
||||
example: "[$true $true $false] | dataframe to-df",
|
||||
example: "[$true $true $false] | dfr to-df",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"0".to_string(),
|
||||
@ -106,6 +106,6 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
test_dataframe(ToDataFrame {})
|
||||
test_dataframe(vec![Box::new(ToDataFrame {})])
|
||||
}
|
||||
}
|
||||
|
100
crates/nu-command/src/dataframe/with_column.rs
Normal file
100
crates/nu-command/src/dataframe/with_column.rs
Normal file
@ -0,0 +1,100 @@
|
||||
use nu_engine::CallExt;
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
|
||||
};
|
||||
|
||||
use super::values::{Column, NuDataFrame};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WithColumn;
|
||||
|
||||
impl Command for WithColumn {
|
||||
fn name(&self) -> &str {
|
||||
"dfr with-column"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Adds a series to the dataframe"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
.required("series", SyntaxShape::Any, "series to be added")
|
||||
.required_named("name", SyntaxShape::String, "column name", Some('n'))
|
||||
.category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Adds a series to the dataframe",
|
||||
example:
|
||||
"[[a b]; [1 2] [3 4]] | dfr to-df | dfr with-column ([5 6] | dfr to-df) --name c",
|
||||
result: Some(
|
||||
NuDataFrame::try_from_columns(vec![
|
||||
Column::new("a".to_string(), vec![1.into(), 3.into()]),
|
||||
Column::new("b".to_string(), vec![2.into(), 4.into()]),
|
||||
Column::new("c".to_string(), vec![5.into(), 6.into()]),
|
||||
])
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Span::unknown()),
|
||||
),
|
||||
}]
|
||||
}
|
||||
|
||||
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 name: Spanned<String> = call
|
||||
.get_flag(engine_state, stack, "name")?
|
||||
.expect("required named value");
|
||||
|
||||
let other_value: Value = call.req(engine_state, stack, 0)?;
|
||||
let other_span = other_value.span()?;
|
||||
let mut other = NuDataFrame::try_from_value(other_value)?.as_series(other_span)?;
|
||||
let series = other.rename(&name.item).clone();
|
||||
|
||||
let mut df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
|
||||
df.as_mut()
|
||||
.with_column(series)
|
||||
.map_err(|e| {
|
||||
ShellError::SpannedLabeledError(
|
||||
"Error adding column to dataframe".into(),
|
||||
e.to_string(),
|
||||
other_span,
|
||||
)
|
||||
})
|
||||
.map(|df| {
|
||||
PipelineData::Value(
|
||||
NuDataFrame::dataframe_into_value(df.clone(), call.head),
|
||||
None,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::test_dataframe::test_dataframe;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
test_dataframe(vec![Box::new(WithColumn {})])
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ use std::collections::{HashMap, HashSet};
|
||||
use crate::{
|
||||
lex, lite_parse,
|
||||
parser::{
|
||||
check_call, check_name, garbage, garbage_statement, parse, parse_block_expression,
|
||||
check_name, garbage, garbage_statement, parse, parse_block_expression,
|
||||
parse_import_pattern, parse_internal_call, parse_multispan_value, parse_signature,
|
||||
parse_string, parse_var_with_opt_type, trim_quotes,
|
||||
},
|
||||
@ -1135,6 +1135,7 @@ pub fn parse_register(
|
||||
working_set: &mut StateWorkingSet,
|
||||
spans: &[Span],
|
||||
) -> (Statement, Option<ParseError>) {
|
||||
use crate::parser::check_call;
|
||||
use nu_plugin::{get_signature, EncodingType, PluginDeclaration};
|
||||
use nu_protocol::Signature;
|
||||
|
||||
|
@ -246,6 +246,10 @@ pub enum ShellError {
|
||||
#[diagnostic()]
|
||||
SpannedLabeledError(String, String, #[label("{1}")] Span),
|
||||
|
||||
#[error("{0}")]
|
||||
#[diagnostic(help("{3}"))]
|
||||
SpannedLabeledErrorHelp(String, String, #[label("{1}")] Span, String),
|
||||
|
||||
#[error("{0}")]
|
||||
#[diagnostic()]
|
||||
LabeledError(String, String),
|
||||
|
@ -337,3 +337,17 @@ impl FromValue for Spanned<PathBuf> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromValue for Vec<Value> {
|
||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||
// FIXME: we may want to fail a little nicer here
|
||||
match v {
|
||||
Value::List { vals, .. } => Ok(vals.clone()),
|
||||
v => Err(ShellError::CantConvert(
|
||||
"Vector of values".into(),
|
||||
v.get_type().to_string(),
|
||||
v.span()?,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user