polars-df 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -1
  3. data/Cargo.lock +486 -380
  4. data/Cargo.toml +0 -2
  5. data/README.md +31 -2
  6. data/ext/polars/Cargo.toml +10 -4
  7. data/ext/polars/src/apply/dataframe.rs +2 -2
  8. data/ext/polars/src/{lazy/apply.rs → apply/lazy.rs} +1 -2
  9. data/ext/polars/src/apply/mod.rs +1 -0
  10. data/ext/polars/src/batched_csv.rs +36 -19
  11. data/ext/polars/src/conversion.rs +159 -16
  12. data/ext/polars/src/dataframe.rs +51 -52
  13. data/ext/polars/src/error.rs +0 -4
  14. data/ext/polars/src/expr/binary.rs +69 -0
  15. data/ext/polars/src/expr/categorical.rs +10 -0
  16. data/ext/polars/src/expr/datetime.rs +223 -0
  17. data/ext/polars/src/{lazy/dsl.rs → expr/general.rs} +22 -799
  18. data/ext/polars/src/expr/list.rs +146 -0
  19. data/ext/polars/src/{lazy → expr}/meta.rs +16 -6
  20. data/ext/polars/src/expr/string.rs +313 -0
  21. data/ext/polars/src/expr/struct.rs +15 -0
  22. data/ext/polars/src/expr.rs +33 -0
  23. data/ext/polars/src/functions/eager.rs +93 -0
  24. data/ext/polars/src/functions/io.rs +34 -0
  25. data/ext/polars/src/functions/lazy.rs +209 -0
  26. data/ext/polars/src/functions/meta.rs +8 -0
  27. data/ext/polars/src/functions/mod.rs +5 -0
  28. data/ext/polars/src/functions/whenthen.rs +43 -0
  29. data/ext/polars/src/{lazy/dataframe.rs → lazyframe.rs} +58 -45
  30. data/ext/polars/src/lazygroupby.rs +29 -0
  31. data/ext/polars/src/lib.rs +216 -300
  32. data/ext/polars/src/rb_modules.rs +8 -0
  33. data/ext/polars/src/series/aggregation.rs +83 -0
  34. data/ext/polars/src/series/arithmetic.rs +88 -0
  35. data/ext/polars/src/series/comparison.rs +251 -0
  36. data/ext/polars/src/series/construction.rs +164 -0
  37. data/ext/polars/src/series.rs +103 -531
  38. data/lib/polars/batched_csv_reader.rb +1 -1
  39. data/lib/polars/binary_expr.rb +77 -0
  40. data/lib/polars/binary_name_space.rb +66 -0
  41. data/lib/polars/convert.rb +2 -2
  42. data/lib/polars/data_frame.rb +263 -87
  43. data/lib/polars/data_types.rb +6 -4
  44. data/lib/polars/date_time_expr.rb +148 -8
  45. data/lib/polars/expr.rb +78 -11
  46. data/lib/polars/io.rb +73 -62
  47. data/lib/polars/lazy_frame.rb +107 -10
  48. data/lib/polars/lazy_functions.rb +7 -3
  49. data/lib/polars/list_expr.rb +70 -21
  50. data/lib/polars/list_name_space.rb +2 -2
  51. data/lib/polars/series.rb +190 -74
  52. data/lib/polars/string_expr.rb +150 -44
  53. data/lib/polars/string_name_space.rb +4 -4
  54. data/lib/polars/struct_name_space.rb +32 -0
  55. data/lib/polars/utils.rb +51 -9
  56. data/lib/polars/version.rb +1 -1
  57. data/lib/polars.rb +4 -2
  58. metadata +29 -12
  59. data/ext/polars/src/lazy/mod.rs +0 -5
  60. data/ext/polars/src/lazy/utils.rs +0 -13
  61. data/ext/polars/src/list_construction.rs +0 -100
  62. /data/ext/polars/src/{numo.rs → series/export.rs} +0 -0
  63. /data/ext/polars/src/{set.rs → series/set_at_idx.rs} +0 -0
@@ -48,20 +48,25 @@ impl RbDataFrame {
48
48
  crate::object::register_object_builder();
49
49
 
50
50
  let schema =
51
- rows_to_schema_supertypes(&rows, infer_schema_length).map_err(RbPolarsErr::from)?;
51
+ rows_to_schema_supertypes(&rows, infer_schema_length.map(|n| std::cmp::max(1, n)))
52
+ .map_err(RbPolarsErr::from)?;
52
53
  // replace inferred nulls with boolean
53
54
  let fields = schema.iter_fields().map(|mut fld| match fld.data_type() {
54
55
  DataType::Null => {
55
56
  fld.coerce(DataType::Boolean);
56
57
  fld
57
58
  }
59
+ DataType::Decimal(_, _) => {
60
+ fld.coerce(DataType::Decimal(None, None));
61
+ fld
62
+ }
58
63
  _ => fld,
59
64
  });
60
- let mut schema = Schema::from(fields);
65
+ let mut schema = Schema::from_iter(fields);
61
66
 
62
67
  if let Some(schema_overwrite) = schema_overwrite {
63
68
  for (i, (name, dtype)) in schema_overwrite.into_iter().enumerate() {
64
- if let Some((name_, dtype_)) = schema.get_index_mut(i) {
69
+ if let Some((name_, dtype_)) = schema.get_at_index_mut(i) {
65
70
  *name_ = name;
66
71
 
67
72
  // if user sets dtype unknown, we use the inferred datatype
@@ -115,7 +120,7 @@ impl RbDataFrame {
115
120
  let comment_char: Option<String> = arguments[17].try_convert()?;
116
121
  let quote_char: Option<String> = arguments[18].try_convert()?;
117
122
  let null_values: Option<Wrap<NullValues>> = arguments[19].try_convert()?;
118
- let parse_dates: bool = arguments[20].try_convert()?;
123
+ let try_parse_dates: bool = arguments[20].try_convert()?;
119
124
  let skip_rows_after_header: usize = arguments[21].try_convert()?;
120
125
  let row_count: Option<(String, IdxSize)> = arguments[22].try_convert()?;
121
126
  let sample_size: usize = arguments[23].try_convert()?;
@@ -139,11 +144,13 @@ impl RbDataFrame {
139
144
  };
140
145
 
141
146
  let overwrite_dtype = overwrite_dtype.map(|overwrite_dtype| {
142
- let fields = overwrite_dtype.iter().map(|(name, dtype)| {
143
- let dtype = dtype.0.clone();
144
- Field::new(name, dtype)
145
- });
146
- Schema::from(fields)
147
+ overwrite_dtype
148
+ .iter()
149
+ .map(|(name, dtype)| {
150
+ let dtype = dtype.0.clone();
151
+ Field::new(name, dtype)
152
+ })
153
+ .collect::<Schema>()
147
154
  });
148
155
 
149
156
  let overwrite_dtype_slice = overwrite_dtype_slice.map(|overwrite_dtype| {
@@ -168,12 +175,12 @@ impl RbDataFrame {
168
175
  .with_columns(columns)
169
176
  .with_n_threads(n_threads)
170
177
  .with_path(path)
171
- .with_dtypes(overwrite_dtype.as_ref())
178
+ .with_dtypes(overwrite_dtype.map(Arc::new))
172
179
  .with_dtypes_slice(overwrite_dtype_slice.as_deref())
173
180
  .low_memory(low_memory)
174
181
  .with_comment_char(comment_char)
175
182
  .with_null_values(null_values)
176
- .with_parse_dates(parse_dates)
183
+ .with_try_parse_dates(try_parse_dates)
177
184
  .with_quote_char(quote_char)
178
185
  .with_end_of_line_char(eol_char)
179
186
  .with_skip_rows_after_header(skip_rows_after_header)
@@ -184,6 +191,7 @@ impl RbDataFrame {
184
191
  Ok(df.into())
185
192
  }
186
193
 
194
+ #[allow(clippy::too_many_arguments)]
187
195
  pub fn read_parquet(
188
196
  rb_f: Value,
189
197
  columns: Option<Vec<String>>,
@@ -192,6 +200,8 @@ impl RbDataFrame {
192
200
  parallel: Wrap<ParallelStrategy>,
193
201
  row_count: Option<(String, IdxSize)>,
194
202
  low_memory: bool,
203
+ use_statistics: bool,
204
+ rechunk: bool,
195
205
  ) -> RbResult<Self> {
196
206
  let row_count = row_count.map(|(name, offset)| RowCount { name, offset });
197
207
  let mmap_bytes_r = get_mmap_bytes_reader(rb_f)?;
@@ -202,6 +212,8 @@ impl RbDataFrame {
202
212
  .with_n_rows(n_rows)
203
213
  .with_row_count(row_count)
204
214
  .set_low_memory(low_memory)
215
+ .use_statistics(use_statistics)
216
+ .set_rechunk(rechunk)
205
217
  .finish()
206
218
  .map_err(RbPolarsErr::from)?;
207
219
  Ok(RbDataFrame::new(df))
@@ -254,7 +266,7 @@ impl RbDataFrame {
254
266
  use polars::io::avro::AvroWriter;
255
267
 
256
268
  if let Ok(s) = rb_f.try_convert::<String>() {
257
- let f = std::fs::File::create(&s).unwrap();
269
+ let f = std::fs::File::create(s).unwrap();
258
270
  AvroWriter::new(f)
259
271
  .with_compression(compression.0)
260
272
  .finish(&mut self.df.borrow_mut())
@@ -339,7 +351,7 @@ impl RbDataFrame {
339
351
  // ensure the new names are used
340
352
  if let Some(schema) = &schema_overwrite {
341
353
  for (new_name, name) in schema.0.iter_names().zip(names.iter_mut()) {
342
- *name = new_name.clone();
354
+ *name = new_name.to_string();
343
355
  }
344
356
  }
345
357
  let rbdf = Self::finish_from_rows(
@@ -348,17 +360,19 @@ impl RbDataFrame {
348
360
  schema_overwrite.map(|wrap| wrap.0),
349
361
  )?;
350
362
 
351
- rbdf.df
352
- .borrow_mut()
353
- .get_columns_mut()
354
- .iter_mut()
355
- .zip(&names)
356
- .for_each(|(s, name)| {
357
- s.rename(name);
358
- });
363
+ unsafe {
364
+ rbdf.df
365
+ .borrow_mut()
366
+ .get_columns_mut()
367
+ .iter_mut()
368
+ .zip(&names)
369
+ .for_each(|(s, name)| {
370
+ s.rename(name);
371
+ });
372
+ }
359
373
  let length = names.len();
360
374
  if names.into_iter().collect::<PlHashSet<_>>().len() != length {
361
- let err = PolarsError::SchemaMisMatch("duplicate column names found".into());
375
+ let err = PolarsError::SchemaMismatch("duplicate column names found".into());
362
376
  Err(RbPolarsErr::from(err))?;
363
377
  }
364
378
 
@@ -394,7 +408,7 @@ impl RbDataFrame {
394
408
  let null = null_value.unwrap_or_default();
395
409
 
396
410
  if let Ok(s) = rb_f.try_convert::<String>() {
397
- let f = std::fs::File::create(&s).unwrap();
411
+ let f = std::fs::File::create(s).unwrap();
398
412
  // no need for a buffered writer, because the csv writer does internal buffering
399
413
  CsvWriter::new(f)
400
414
  .has_header(has_header)
@@ -436,7 +450,7 @@ impl RbDataFrame {
436
450
  compression: Wrap<Option<IpcCompression>>,
437
451
  ) -> RbResult<()> {
438
452
  if let Ok(s) = rb_f.try_convert::<String>() {
439
- let f = std::fs::File::create(&s).unwrap();
453
+ let f = std::fs::File::create(s).unwrap();
440
454
  IpcWriter::new(f)
441
455
  .with_compression(compression.0)
442
456
  .finish(&mut self.df.borrow_mut())
@@ -505,12 +519,10 @@ impl RbDataFrame {
505
519
  }
506
520
  }
507
521
  }
508
- let st = st?;
522
+ let _st = st?;
509
523
 
510
- match st {
511
- // TODO
512
- _ => None,
513
- }
524
+ // TODO
525
+ None
514
526
  }
515
527
 
516
528
  pub fn write_parquet(
@@ -524,7 +536,7 @@ impl RbDataFrame {
524
536
  let compression = parse_parquet_compression(&compression, compression_level)?;
525
537
 
526
538
  if let Ok(s) = rb_f.try_convert::<String>() {
527
- let f = std::fs::File::create(&s).unwrap();
539
+ let f = std::fs::File::create(s).unwrap();
528
540
  ParquetWriter::new(f)
529
541
  .with_compression(compression)
530
542
  .with_statistics(statistics)
@@ -627,7 +639,7 @@ impl RbDataFrame {
627
639
  }
628
640
 
629
641
  pub fn get_columns(&self) -> RArray {
630
- let cols = self.df.borrow().get_columns().clone();
642
+ let cols = self.df.borrow().get_columns().to_vec();
631
643
  to_rbseries_collection(cols)
632
644
  }
633
645
 
@@ -881,10 +893,11 @@ impl RbDataFrame {
881
893
  variable_name: Option<String>,
882
894
  ) -> RbResult<Self> {
883
895
  let args = MeltArgs {
884
- id_vars,
885
- value_vars,
886
- value_name,
887
- variable_name,
896
+ id_vars: strings_to_smartstrings(id_vars),
897
+ value_vars: strings_to_smartstrings(value_vars),
898
+ value_name: value_name.map(|s| s.into()),
899
+ variable_name: variable_name.map(|s| s.into()),
900
+ streamable: false,
888
901
  };
889
902
 
890
903
  let df = self.df.borrow().melt2(args).map_err(RbPolarsErr::from)?;
@@ -897,22 +910,23 @@ impl RbDataFrame {
897
910
  values: Vec<String>,
898
911
  index: Vec<String>,
899
912
  columns: Vec<String>,
900
- aggregate_expr: &RbExpr,
901
913
  maintain_order: bool,
902
914
  sort_columns: bool,
915
+ aggregate_expr: Option<&RbExpr>,
903
916
  separator: Option<String>,
904
917
  ) -> RbResult<Self> {
905
918
  let fun = match maintain_order {
906
919
  true => pivot_stable,
907
920
  false => pivot,
908
921
  };
922
+ let agg_expr = aggregate_expr.map(|aggregate_expr| aggregate_expr.inner.clone());
909
923
  let df = fun(
910
924
  &self.df.borrow(),
911
925
  values,
912
926
  index,
913
927
  columns,
914
- aggregate_expr.inner.clone(),
915
928
  sort_columns,
929
+ agg_expr,
916
930
  separator.as_deref(),
917
931
  )
918
932
  .map_err(RbPolarsErr::from)?;
@@ -933,21 +947,6 @@ impl RbDataFrame {
933
947
  self.df.borrow().shift(periods).into()
934
948
  }
935
949
 
936
- pub fn unique(
937
- &self,
938
- maintain_order: bool,
939
- subset: Option<Vec<String>>,
940
- keep: Wrap<UniqueKeepStrategy>,
941
- ) -> RbResult<Self> {
942
- let subset = subset.as_ref().map(|v| v.as_ref());
943
- let df = match maintain_order {
944
- true => self.df.borrow().unique_stable(subset, keep.0),
945
- false => self.df.borrow().unique(subset, keep.0),
946
- }
947
- .map_err(RbPolarsErr::from)?;
948
- Ok(df.into())
949
- }
950
-
951
950
  pub fn lazy(&self) -> RbLazyFrame {
952
951
  self.df.borrow().clone().lazy().into()
953
952
  }
@@ -22,10 +22,6 @@ impl RbPolarsErr {
22
22
  pub fn other(message: String) -> Error {
23
23
  Error::new(exception::runtime_error(), message)
24
24
  }
25
-
26
- pub fn todo() -> Error {
27
- Error::new(exception::runtime_error(), "not implemented yet")
28
- }
29
25
  }
30
26
 
31
27
  pub struct RbValueError {}
@@ -0,0 +1,69 @@
1
+ use polars::prelude::*;
2
+
3
+ use crate::RbExpr;
4
+
5
+ impl RbExpr {
6
+ pub fn bin_contains(&self, lit: Vec<u8>) -> Self {
7
+ self.inner.clone().binary().contains_literal(lit).into()
8
+ }
9
+
10
+ pub fn bin_ends_with(&self, sub: Vec<u8>) -> Self {
11
+ self.inner.clone().binary().ends_with(sub).into()
12
+ }
13
+
14
+ pub fn bin_starts_with(&self, sub: Vec<u8>) -> Self {
15
+ self.inner.clone().binary().starts_with(sub).into()
16
+ }
17
+
18
+ pub fn bin_hex_decode(&self, strict: bool) -> Self {
19
+ self.clone()
20
+ .inner
21
+ .map(
22
+ move |s| {
23
+ s.binary()?
24
+ .hex_decode(strict)
25
+ .map(|s| Some(s.into_series()))
26
+ },
27
+ GetOutput::same_type(),
28
+ )
29
+ .with_fmt("bin.hex_decode")
30
+ .into()
31
+ }
32
+
33
+ pub fn bin_base64_decode(&self, strict: bool) -> Self {
34
+ self.clone()
35
+ .inner
36
+ .map(
37
+ move |s| {
38
+ s.binary()?
39
+ .base64_decode(strict)
40
+ .map(|s| Some(s.into_series()))
41
+ },
42
+ GetOutput::same_type(),
43
+ )
44
+ .with_fmt("bin.base64_decode")
45
+ .into()
46
+ }
47
+
48
+ pub fn bin_hex_encode(&self) -> Self {
49
+ self.clone()
50
+ .inner
51
+ .map(
52
+ move |s| s.binary().map(|s| Some(s.hex_encode().into_series())),
53
+ GetOutput::same_type(),
54
+ )
55
+ .with_fmt("bin.hex_encode")
56
+ .into()
57
+ }
58
+
59
+ pub fn bin_base64_encode(&self) -> Self {
60
+ self.clone()
61
+ .inner
62
+ .map(
63
+ move |s| s.binary().map(|s| Some(s.base64_encode().into_series())),
64
+ GetOutput::same_type(),
65
+ )
66
+ .with_fmt("bin.base64_encode")
67
+ .into()
68
+ }
69
+ }
@@ -0,0 +1,10 @@
1
+ use polars::prelude::*;
2
+
3
+ use crate::conversion::Wrap;
4
+ use crate::RbExpr;
5
+
6
+ impl RbExpr {
7
+ pub fn cat_set_ordering(&self, ordering: Wrap<CategoricalOrdering>) -> Self {
8
+ self.inner.clone().cat().set_ordering(ordering.0).into()
9
+ }
10
+ }
@@ -0,0 +1,223 @@
1
+ use polars::prelude::*;
2
+
3
+ use crate::conversion::Wrap;
4
+ use crate::RbExpr;
5
+
6
+ impl RbExpr {
7
+ pub fn dt_to_string(&self, format: String) -> Self {
8
+ self.inner.clone().dt().to_string(&format).into()
9
+ }
10
+
11
+ pub fn dt_offset_by(&self, by: String) -> Self {
12
+ let by = Duration::parse(&by);
13
+ self.inner.clone().dt().offset_by(by).into()
14
+ }
15
+
16
+ pub fn dt_epoch_seconds(&self) -> Self {
17
+ self.clone()
18
+ .inner
19
+ .map(
20
+ |s| {
21
+ s.timestamp(TimeUnit::Milliseconds)
22
+ .map(|ca| Some((ca / 1000).into_series()))
23
+ },
24
+ GetOutput::from_type(DataType::Int64),
25
+ )
26
+ .into()
27
+ }
28
+
29
+ pub fn dt_with_time_unit(&self, tu: Wrap<TimeUnit>) -> Self {
30
+ self.inner.clone().dt().with_time_unit(tu.0).into()
31
+ }
32
+
33
+ pub fn dt_convert_time_zone(&self, tz: TimeZone) -> Self {
34
+ self.inner.clone().dt().convert_time_zone(tz).into()
35
+ }
36
+
37
+ pub fn dt_cast_time_unit(&self, tu: Wrap<TimeUnit>) -> Self {
38
+ self.inner.clone().dt().cast_time_unit(tu.0).into()
39
+ }
40
+
41
+ pub fn dt_replace_time_zone(&self, tz: Option<String>, use_earliest: Option<bool>) -> Self {
42
+ self.inner
43
+ .clone()
44
+ .dt()
45
+ .replace_time_zone(tz, use_earliest)
46
+ .into()
47
+ }
48
+
49
+ #[allow(deprecated)]
50
+ pub fn dt_tz_localize(&self, tz: String) -> Self {
51
+ self.inner.clone().dt().tz_localize(tz).into()
52
+ }
53
+
54
+ pub fn dt_truncate(&self, every: String, offset: String) -> Self {
55
+ self.inner.clone().dt().truncate(&every, &offset).into()
56
+ }
57
+
58
+ pub fn dt_month_start(&self) -> Self {
59
+ self.inner.clone().dt().month_start().into()
60
+ }
61
+
62
+ pub fn dt_month_end(&self) -> Self {
63
+ self.inner.clone().dt().month_end().into()
64
+ }
65
+
66
+ pub fn dt_round(&self, every: String, offset: String) -> Self {
67
+ self.inner.clone().dt().round(&every, &offset).into()
68
+ }
69
+
70
+ pub fn dt_combine(&self, time: &Self, time_unit: Wrap<TimeUnit>) -> Self {
71
+ self.inner
72
+ .clone()
73
+ .dt()
74
+ .combine(time.inner.clone(), time_unit.0)
75
+ .into()
76
+ }
77
+
78
+ pub fn dt_year(&self) -> Self {
79
+ self.clone().inner.dt().year().into()
80
+ }
81
+
82
+ pub fn dt_is_leap_year(&self) -> Self {
83
+ self.clone().inner.dt().is_leap_year().into()
84
+ }
85
+
86
+ pub fn dt_iso_year(&self) -> Self {
87
+ self.clone().inner.dt().iso_year().into()
88
+ }
89
+
90
+ pub fn dt_quarter(&self) -> Self {
91
+ self.clone().inner.dt().quarter().into()
92
+ }
93
+
94
+ pub fn dt_month(&self) -> Self {
95
+ self.clone().inner.dt().month().into()
96
+ }
97
+
98
+ pub fn dt_week(&self) -> Self {
99
+ self.clone().inner.dt().week().into()
100
+ }
101
+
102
+ pub fn dt_weekday(&self) -> Self {
103
+ self.clone().inner.dt().weekday().into()
104
+ }
105
+
106
+ pub fn dt_day(&self) -> Self {
107
+ self.clone().inner.dt().day().into()
108
+ }
109
+
110
+ pub fn dt_ordinal_day(&self) -> Self {
111
+ self.clone().inner.dt().ordinal_day().into()
112
+ }
113
+
114
+ pub fn dt_time(&self) -> Self {
115
+ self.clone().inner.dt().time().into()
116
+ }
117
+
118
+ pub fn dt_date(&self) -> Self {
119
+ self.clone().inner.dt().date().into()
120
+ }
121
+
122
+ pub fn dt_datetime(&self) -> Self {
123
+ self.clone().inner.dt().datetime().into()
124
+ }
125
+
126
+ pub fn dt_hour(&self) -> Self {
127
+ self.clone().inner.dt().hour().into()
128
+ }
129
+
130
+ pub fn dt_minute(&self) -> Self {
131
+ self.clone().inner.dt().minute().into()
132
+ }
133
+
134
+ pub fn dt_second(&self) -> Self {
135
+ self.clone().inner.dt().second().into()
136
+ }
137
+
138
+ pub fn dt_millisecond(&self) -> Self {
139
+ self.clone().inner.dt().millisecond().into()
140
+ }
141
+
142
+ pub fn dt_microsecond(&self) -> Self {
143
+ self.clone().inner.dt().microsecond().into()
144
+ }
145
+
146
+ pub fn dt_nanosecond(&self) -> Self {
147
+ self.clone().inner.dt().nanosecond().into()
148
+ }
149
+
150
+ pub fn dt_timestamp(&self, tu: Wrap<TimeUnit>) -> Self {
151
+ self.inner.clone().dt().timestamp(tu.0).into()
152
+ }
153
+
154
+ pub fn duration_days(&self) -> Self {
155
+ self.inner
156
+ .clone()
157
+ .map(
158
+ |s| Ok(Some(s.duration()?.days().into_series())),
159
+ GetOutput::from_type(DataType::Int64),
160
+ )
161
+ .into()
162
+ }
163
+
164
+ pub fn duration_hours(&self) -> Self {
165
+ self.inner
166
+ .clone()
167
+ .map(
168
+ |s| Ok(Some(s.duration()?.hours().into_series())),
169
+ GetOutput::from_type(DataType::Int64),
170
+ )
171
+ .into()
172
+ }
173
+
174
+ pub fn duration_minutes(&self) -> Self {
175
+ self.inner
176
+ .clone()
177
+ .map(
178
+ |s| Ok(Some(s.duration()?.minutes().into_series())),
179
+ GetOutput::from_type(DataType::Int64),
180
+ )
181
+ .into()
182
+ }
183
+
184
+ pub fn duration_seconds(&self) -> Self {
185
+ self.inner
186
+ .clone()
187
+ .map(
188
+ |s| Ok(Some(s.duration()?.seconds().into_series())),
189
+ GetOutput::from_type(DataType::Int64),
190
+ )
191
+ .into()
192
+ }
193
+
194
+ pub fn duration_milliseconds(&self) -> Self {
195
+ self.inner
196
+ .clone()
197
+ .map(
198
+ |s| Ok(Some(s.duration()?.milliseconds().into_series())),
199
+ GetOutput::from_type(DataType::Int64),
200
+ )
201
+ .into()
202
+ }
203
+
204
+ pub fn duration_microseconds(&self) -> Self {
205
+ self.inner
206
+ .clone()
207
+ .map(
208
+ |s| Ok(Some(s.duration()?.microseconds().into_series())),
209
+ GetOutput::from_type(DataType::Int64),
210
+ )
211
+ .into()
212
+ }
213
+
214
+ pub fn duration_nanoseconds(&self) -> Self {
215
+ self.inner
216
+ .clone()
217
+ .map(
218
+ |s| Ok(Some(s.duration()?.nanoseconds().into_series())),
219
+ GetOutput::from_type(DataType::Int64),
220
+ )
221
+ .into()
222
+ }
223
+ }