polars-df 0.8.0 → 0.10.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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -1
  3. data/Cargo.lock +159 -66
  4. data/Cargo.toml +0 -3
  5. data/LICENSE.txt +1 -1
  6. data/README.md +3 -2
  7. data/ext/polars/Cargo.toml +18 -8
  8. data/ext/polars/src/batched_csv.rs +7 -5
  9. data/ext/polars/src/conversion/anyvalue.rs +186 -0
  10. data/ext/polars/src/conversion/chunked_array.rs +140 -0
  11. data/ext/polars/src/{conversion.rs → conversion/mod.rs} +273 -342
  12. data/ext/polars/src/dataframe.rs +108 -66
  13. data/ext/polars/src/expr/array.rs +78 -0
  14. data/ext/polars/src/expr/datetime.rs +29 -58
  15. data/ext/polars/src/expr/general.rs +83 -36
  16. data/ext/polars/src/expr/list.rs +58 -6
  17. data/ext/polars/src/expr/meta.rs +48 -0
  18. data/ext/polars/src/expr/rolling.rs +1 -0
  19. data/ext/polars/src/expr/string.rs +62 -11
  20. data/ext/polars/src/expr/struct.rs +8 -4
  21. data/ext/polars/src/file.rs +158 -11
  22. data/ext/polars/src/functions/aggregation.rs +6 -0
  23. data/ext/polars/src/functions/lazy.rs +120 -50
  24. data/ext/polars/src/functions/meta.rs +45 -1
  25. data/ext/polars/src/functions/string_cache.rs +14 -0
  26. data/ext/polars/src/functions/whenthen.rs +47 -17
  27. data/ext/polars/src/{lazyframe.rs → lazyframe/mod.rs} +195 -40
  28. data/ext/polars/src/lib.rs +246 -179
  29. data/ext/polars/src/map/dataframe.rs +17 -9
  30. data/ext/polars/src/series/aggregation.rs +20 -0
  31. data/ext/polars/src/series/mod.rs +35 -4
  32. data/lib/polars/array_expr.rb +453 -0
  33. data/lib/polars/array_name_space.rb +346 -0
  34. data/lib/polars/batched_csv_reader.rb +4 -2
  35. data/lib/polars/cat_expr.rb +24 -0
  36. data/lib/polars/cat_name_space.rb +75 -0
  37. data/lib/polars/config.rb +2 -2
  38. data/lib/polars/data_frame.rb +306 -96
  39. data/lib/polars/data_types.rb +191 -28
  40. data/lib/polars/date_time_expr.rb +41 -18
  41. data/lib/polars/date_time_name_space.rb +9 -3
  42. data/lib/polars/exceptions.rb +12 -1
  43. data/lib/polars/expr.rb +898 -215
  44. data/lib/polars/functions/aggregation/horizontal.rb +246 -0
  45. data/lib/polars/functions/aggregation/vertical.rb +282 -0
  46. data/lib/polars/functions/as_datatype.rb +248 -0
  47. data/lib/polars/functions/col.rb +47 -0
  48. data/lib/polars/functions/eager.rb +182 -0
  49. data/lib/polars/functions/lazy.rb +1280 -0
  50. data/lib/polars/functions/len.rb +49 -0
  51. data/lib/polars/functions/lit.rb +35 -0
  52. data/lib/polars/functions/random.rb +16 -0
  53. data/lib/polars/functions/range/date_range.rb +103 -0
  54. data/lib/polars/functions/range/int_range.rb +51 -0
  55. data/lib/polars/functions/repeat.rb +144 -0
  56. data/lib/polars/functions/whenthen.rb +96 -0
  57. data/lib/polars/functions.rb +29 -416
  58. data/lib/polars/group_by.rb +2 -2
  59. data/lib/polars/io.rb +36 -31
  60. data/lib/polars/lazy_frame.rb +405 -88
  61. data/lib/polars/list_expr.rb +158 -8
  62. data/lib/polars/list_name_space.rb +102 -0
  63. data/lib/polars/meta_expr.rb +175 -7
  64. data/lib/polars/series.rb +282 -41
  65. data/lib/polars/string_cache.rb +75 -0
  66. data/lib/polars/string_expr.rb +413 -96
  67. data/lib/polars/string_name_space.rb +4 -4
  68. data/lib/polars/testing.rb +507 -0
  69. data/lib/polars/utils.rb +106 -8
  70. data/lib/polars/version.rb +1 -1
  71. data/lib/polars/whenthen.rb +83 -0
  72. data/lib/polars.rb +16 -4
  73. metadata +37 -8
  74. data/lib/polars/lazy_functions.rb +0 -1181
  75. data/lib/polars/when.rb +0 -16
  76. data/lib/polars/when_then.rb +0 -19
@@ -6,16 +6,17 @@ use polars::frame::row::{rows_to_schema_supertypes, Row};
6
6
  use polars::frame::NullStrategy;
7
7
  use polars::io::avro::AvroCompression;
8
8
  use polars::io::mmap::ReaderBytes;
9
- use polars::io::RowCount;
9
+ use polars::io::RowIndex;
10
10
  use polars::prelude::pivot::{pivot, pivot_stable};
11
11
  use polars::prelude::*;
12
12
  use polars_core::utils::try_get_supertype;
13
13
  use std::cell::RefCell;
14
14
  use std::io::{BufWriter, Cursor};
15
+ use std::num::NonZeroUsize;
15
16
  use std::ops::Deref;
16
17
 
17
18
  use crate::conversion::*;
18
- use crate::file::{get_file_like, get_mmap_bytes_reader};
19
+ use crate::file::{get_either_file, get_file_like, get_mmap_bytes_reader, EitherRustRubyFile};
19
20
  use crate::map::dataframe::{
20
21
  apply_lambda_unknown, apply_lambda_with_bool_out_type, apply_lambda_with_primitive_out_type,
21
22
  apply_lambda_with_utf8_out_type,
@@ -45,44 +46,51 @@ impl RbDataFrame {
45
46
  fn finish_from_rows(
46
47
  rows: Vec<Row>,
47
48
  infer_schema_length: Option<usize>,
48
- schema_overwrite: Option<Schema>,
49
+ schema: Option<Schema>,
50
+ schema_overrides_by_idx: Option<Vec<(usize, DataType)>>,
49
51
  ) -> RbResult<Self> {
50
- // object builder must be registered.
52
+ // Object builder must be registered
51
53
  crate::on_startup::register_object_builder();
52
54
 
53
- let schema =
55
+ let mut final_schema =
54
56
  rows_to_schema_supertypes(&rows, infer_schema_length.map(|n| std::cmp::max(1, n)))
55
57
  .map_err(RbPolarsErr::from)?;
56
- // replace inferred nulls with boolean
57
- let fields = schema.iter_fields().map(|mut fld| match fld.data_type() {
58
- DataType::Null => {
59
- // fld.coerce(DataType::Boolean);
60
- fld
61
- }
62
- DataType::Decimal(_, _) => {
63
- fld.coerce(DataType::Decimal(None, None));
64
- fld
58
+
59
+ // Erase scale from inferred decimals.
60
+ for dtype in final_schema.iter_dtypes_mut() {
61
+ if let DataType::Decimal(_, _) = dtype {
62
+ *dtype = DataType::Decimal(None, None)
65
63
  }
66
- _ => fld,
67
- });
68
- let mut schema = Schema::from_iter(fields);
64
+ }
69
65
 
70
- if let Some(schema_overwrite) = schema_overwrite {
71
- for (i, (name, dtype)) in schema_overwrite.into_iter().enumerate() {
72
- if let Some((name_, dtype_)) = schema.get_at_index_mut(i) {
66
+ // Integrate explicit/inferred schema.
67
+ if let Some(schema) = schema {
68
+ for (i, (name, dtype)) in schema.into_iter().enumerate() {
69
+ if let Some((name_, dtype_)) = final_schema.get_at_index_mut(i) {
73
70
  *name_ = name;
74
71
 
75
- // if user sets dtype unknown, we use the inferred datatype
72
+ // If schema dtype is Unknown, overwrite with inferred datatype.
76
73
  if !matches!(dtype, DataType::Unknown) {
77
74
  *dtype_ = dtype;
78
75
  }
79
76
  } else {
80
- schema.with_column(name, dtype);
77
+ final_schema.with_column(name, dtype);
81
78
  }
82
79
  }
83
80
  }
84
81
 
85
- let df = DataFrame::from_rows_and_schema(&rows, &schema).map_err(RbPolarsErr::from)?;
82
+ // Optional per-field overrides; these supersede default/inferred dtypes.
83
+ if let Some(overrides) = schema_overrides_by_idx {
84
+ for (i, dtype) in overrides {
85
+ if let Some((_, dtype_)) = final_schema.get_at_index_mut(i) {
86
+ if !matches!(dtype, DataType::Unknown) {
87
+ *dtype_ = dtype;
88
+ }
89
+ }
90
+ }
91
+ }
92
+ let df =
93
+ DataFrame::from_rows_and_schema(&rows, &final_schema).map_err(RbPolarsErr::from)?;
86
94
  Ok(df.into())
87
95
  }
88
96
 
@@ -125,15 +133,16 @@ impl RbDataFrame {
125
133
  let null_values = Option::<Wrap<NullValues>>::try_convert(arguments[19])?;
126
134
  let try_parse_dates = bool::try_convert(arguments[20])?;
127
135
  let skip_rows_after_header = usize::try_convert(arguments[21])?;
128
- let row_count = Option::<(String, IdxSize)>::try_convert(arguments[22])?;
136
+ let row_index = Option::<(String, IdxSize)>::try_convert(arguments[22])?;
129
137
  let sample_size = usize::try_convert(arguments[23])?;
130
138
  let eol_char = String::try_convert(arguments[24])?;
139
+ let truncate_ragged_lines = bool::try_convert(arguments[25])?;
131
140
  // end arguments
132
141
 
133
142
  let null_values = null_values.map(|w| w.0);
134
143
  let eol_char = eol_char.as_bytes()[0];
135
144
 
136
- let row_count = row_count.map(|(name, offset)| RowCount { name, offset });
145
+ let row_index = row_index.map(|(name, offset)| RowIndex { name, offset });
137
146
 
138
147
  let quote_char = if let Some(s) = quote_char {
139
148
  if s.is_empty() {
@@ -186,8 +195,9 @@ impl RbDataFrame {
186
195
  .with_quote_char(quote_char)
187
196
  .with_end_of_line_char(eol_char)
188
197
  .with_skip_rows_after_header(skip_rows_after_header)
189
- .with_row_count(row_count)
198
+ .with_row_index(row_index)
190
199
  .sample_size(sample_size)
200
+ .truncate_ragged_lines(truncate_ragged_lines)
191
201
  .finish()
192
202
  .map_err(RbPolarsErr::from)?;
193
203
  Ok(df.into())
@@ -200,24 +210,39 @@ impl RbDataFrame {
200
210
  projection: Option<Vec<usize>>,
201
211
  n_rows: Option<usize>,
202
212
  parallel: Wrap<ParallelStrategy>,
203
- row_count: Option<(String, IdxSize)>,
213
+ row_index: Option<(String, IdxSize)>,
204
214
  low_memory: bool,
205
215
  use_statistics: bool,
206
216
  rechunk: bool,
207
217
  ) -> RbResult<Self> {
208
- let row_count = row_count.map(|(name, offset)| RowCount { name, offset });
209
- let mmap_bytes_r = get_mmap_bytes_reader(rb_f)?;
210
- let df = ParquetReader::new(mmap_bytes_r)
211
- .with_projection(projection)
212
- .with_columns(columns)
213
- .read_parallel(parallel.0)
214
- .with_n_rows(n_rows)
215
- .with_row_count(row_count)
216
- .set_low_memory(low_memory)
217
- .use_statistics(use_statistics)
218
- .set_rechunk(rechunk)
219
- .finish()
220
- .map_err(RbPolarsErr::from)?;
218
+ use EitherRustRubyFile::*;
219
+
220
+ let row_index = row_index.map(|(name, offset)| RowIndex { name, offset });
221
+ let result = match get_either_file(rb_f, false)? {
222
+ Rb(f) => {
223
+ let buf = f.as_buffer();
224
+ ParquetReader::new(buf)
225
+ .with_projection(projection)
226
+ .with_columns(columns)
227
+ .read_parallel(parallel.0)
228
+ .with_n_rows(n_rows)
229
+ .with_row_index(row_index)
230
+ .set_low_memory(low_memory)
231
+ .use_statistics(use_statistics)
232
+ .set_rechunk(rechunk)
233
+ .finish()
234
+ }
235
+ Rust(f) => ParquetReader::new(f.into_inner())
236
+ .with_projection(projection)
237
+ .with_columns(columns)
238
+ .read_parallel(parallel.0)
239
+ .with_n_rows(n_rows)
240
+ .with_row_index(row_index)
241
+ .use_statistics(use_statistics)
242
+ .set_rechunk(rechunk)
243
+ .finish(),
244
+ };
245
+ let df = result.map_err(RbPolarsErr::from)?;
221
246
  Ok(RbDataFrame::new(df))
222
247
  }
223
248
 
@@ -226,16 +251,16 @@ impl RbDataFrame {
226
251
  columns: Option<Vec<String>>,
227
252
  projection: Option<Vec<usize>>,
228
253
  n_rows: Option<usize>,
229
- row_count: Option<(String, IdxSize)>,
254
+ row_index: Option<(String, IdxSize)>,
230
255
  memory_map: bool,
231
256
  ) -> RbResult<Self> {
232
- let row_count = row_count.map(|(name, offset)| RowCount { name, offset });
257
+ let row_index = row_index.map(|(name, offset)| RowIndex { name, offset });
233
258
  let mmap_bytes_r = get_mmap_bytes_reader(rb_f)?;
234
259
  let df = IpcReader::new(mmap_bytes_r)
235
260
  .with_projection(projection)
236
261
  .with_columns(columns)
237
262
  .with_n_rows(n_rows)
238
- .with_row_count(row_count)
263
+ .with_row_index(row_index)
239
264
  .memory_mapped(memory_map)
240
265
  .finish()
241
266
  .map_err(RbPolarsErr::from)?;
@@ -352,7 +377,7 @@ impl RbDataFrame {
352
377
  pub fn read_rows(
353
378
  rb_rows: RArray,
354
379
  infer_schema_length: Option<usize>,
355
- schema_overwrite: Option<Wrap<Schema>>,
380
+ schema: Option<Wrap<Schema>>,
356
381
  ) -> RbResult<Self> {
357
382
  let mut rows = Vec::with_capacity(rb_rows.len());
358
383
  for v in rb_rows.each() {
@@ -363,30 +388,34 @@ impl RbDataFrame {
363
388
  }
364
389
  rows.push(Row(row));
365
390
  }
366
- Self::finish_from_rows(
367
- rows,
368
- infer_schema_length,
369
- schema_overwrite.map(|wrap| wrap.0),
370
- )
391
+ Self::finish_from_rows(rows, infer_schema_length, schema.map(|wrap| wrap.0), None)
371
392
  }
372
393
 
373
394
  pub fn read_hashes(
374
395
  dicts: Value,
375
396
  infer_schema_length: Option<usize>,
376
- schema_overwrite: Option<Wrap<Schema>>,
397
+ schema: Option<Wrap<Schema>>,
398
+ schema_overrides: Option<Wrap<Schema>>,
377
399
  ) -> RbResult<Self> {
378
- let (rows, mut names) = dicts_to_rows(&dicts, infer_schema_length.unwrap_or(50))?;
400
+ let mut schema_columns = PlIndexSet::new();
401
+ if let Some(s) = &schema {
402
+ schema_columns.extend(s.0.iter_names().map(|n| n.to_string()))
403
+ }
404
+ let (rows, names) = dicts_to_rows(&dicts, infer_schema_length, schema_columns)?;
379
405
 
380
- // ensure the new names are used
381
- if let Some(schema) = &schema_overwrite {
382
- for (new_name, name) in schema.0.iter_names().zip(names.iter_mut()) {
383
- *name = new_name.to_string();
406
+ let mut schema_overrides_by_idx: Vec<(usize, DataType)> = Vec::new();
407
+ if let Some(overrides) = schema_overrides {
408
+ for (idx, name) in names.iter().enumerate() {
409
+ if let Some(dtype) = overrides.0.get(name) {
410
+ schema_overrides_by_idx.push((idx, dtype.clone()));
411
+ }
384
412
  }
385
413
  }
386
414
  let rbdf = Self::finish_from_rows(
387
415
  rows,
388
416
  infer_schema_length,
389
- schema_overwrite.map(|wrap| wrap.0),
417
+ schema.map(|wrap| wrap.0),
418
+ Some(schema_overrides_by_idx),
390
419
  )?;
391
420
 
392
421
  unsafe {
@@ -427,13 +456,14 @@ impl RbDataFrame {
427
456
  include_header: bool,
428
457
  separator: u8,
429
458
  quote_char: u8,
430
- batch_size: usize,
459
+ batch_size: Wrap<NonZeroUsize>,
431
460
  datetime_format: Option<String>,
432
461
  date_format: Option<String>,
433
462
  time_format: Option<String>,
434
463
  float_precision: Option<usize>,
435
464
  null_value: Option<String>,
436
465
  ) -> RbResult<()> {
466
+ let batch_size = batch_size.0;
437
467
  let null = null_value.unwrap_or_default();
438
468
 
439
469
  if let Ok(s) = String::try_convert(rb_f) {
@@ -563,6 +593,7 @@ impl RbDataFrame {
563
593
  compression_level: Option<i32>,
564
594
  statistics: bool,
565
595
  row_group_size: Option<usize>,
596
+ data_page_size: Option<usize>,
566
597
  ) -> RbResult<()> {
567
598
  let compression = parse_parquet_compression(&compression, compression_level)?;
568
599
 
@@ -572,10 +603,18 @@ impl RbDataFrame {
572
603
  .with_compression(compression)
573
604
  .with_statistics(statistics)
574
605
  .with_row_group_size(row_group_size)
606
+ .with_data_page_size(data_page_size)
575
607
  .finish(&mut self.df.borrow_mut())
576
608
  .map_err(RbPolarsErr::from)?;
577
609
  } else {
578
- todo!();
610
+ let buf = get_file_like(rb_f, true)?;
611
+ ParquetWriter::new(buf)
612
+ .with_compression(compression)
613
+ .with_statistics(statistics)
614
+ .with_row_group_size(row_group_size)
615
+ .with_data_page_size(data_page_size)
616
+ .finish(&mut self.df.borrow_mut())
617
+ .map_err(RbPolarsErr::from)?;
579
618
  }
580
619
 
581
620
  Ok(())
@@ -794,12 +833,11 @@ impl RbDataFrame {
794
833
  self.df.borrow().get_column_index(&name)
795
834
  }
796
835
 
797
- // TODO remove clone
798
- pub fn column(&self, name: String) -> RbResult<RbSeries> {
836
+ pub fn get_column(&self, name: String) -> RbResult<RbSeries> {
799
837
  self.df
800
838
  .borrow()
801
839
  .column(&name)
802
- .map(|v| v.clone().into())
840
+ .map(|s| RbSeries::new(s.clone()))
803
841
  .map_err(RbPolarsErr::from)
804
842
  }
805
843
 
@@ -887,11 +925,11 @@ impl RbDataFrame {
887
925
  }
888
926
  }
889
927
 
890
- pub fn with_row_count(&self, name: String, offset: Option<IdxSize>) -> RbResult<Self> {
928
+ pub fn with_row_index(&self, name: String, offset: Option<IdxSize>) -> RbResult<Self> {
891
929
  let df = self
892
930
  .df
893
931
  .borrow()
894
- .with_row_count(&name, offset)
932
+ .with_row_index(&name, offset)
895
933
  .map_err(RbPolarsErr::from)?;
896
934
  Ok(df.into())
897
935
  }
@@ -922,9 +960,9 @@ impl RbDataFrame {
922
960
  #[allow(clippy::too_many_arguments)]
923
961
  pub fn pivot_expr(
924
962
  &self,
925
- values: Vec<String>,
926
963
  index: Vec<String>,
927
964
  columns: Vec<String>,
965
+ values: Option<Vec<String>>,
928
966
  maintain_order: bool,
929
967
  sort_columns: bool,
930
968
  aggregate_expr: Option<&RbExpr>,
@@ -937,9 +975,9 @@ impl RbDataFrame {
937
975
  let agg_expr = aggregate_expr.map(|aggregate_expr| aggregate_expr.inner.clone());
938
976
  let df = fun(
939
977
  &self.df.borrow(),
940
- values,
941
978
  index,
942
979
  columns,
980
+ values,
943
981
  sort_columns,
944
982
  agg_expr,
945
983
  separator.as_deref(),
@@ -1121,7 +1159,7 @@ impl RbDataFrame {
1121
1159
  };
1122
1160
  Ok(self
1123
1161
  .df
1124
- .borrow()
1162
+ .borrow_mut()
1125
1163
  .transpose(keep_names_as.as_deref(), new_col_names)
1126
1164
  .map_err(RbPolarsErr::from)?
1127
1165
  .into())
@@ -1163,4 +1201,8 @@ impl RbDataFrame {
1163
1201
  let df = self.df.borrow().unnest(names).map_err(RbPolarsErr::from)?;
1164
1202
  Ok(df.into())
1165
1203
  }
1204
+
1205
+ pub fn clear(&self) -> Self {
1206
+ self.df.borrow().clear().into()
1207
+ }
1166
1208
  }
@@ -1,3 +1,5 @@
1
+ use polars::prelude::*;
2
+
1
3
  use crate::RbExpr;
2
4
 
3
5
  impl RbExpr {
@@ -12,4 +14,80 @@ impl RbExpr {
12
14
  pub fn array_sum(&self) -> Self {
13
15
  self.inner.clone().arr().sum().into()
14
16
  }
17
+
18
+ pub fn arr_unique(&self, maintain_order: bool) -> Self {
19
+ if maintain_order {
20
+ self.inner.clone().arr().unique_stable().into()
21
+ } else {
22
+ self.inner.clone().arr().unique().into()
23
+ }
24
+ }
25
+
26
+ pub fn arr_to_list(&self) -> Self {
27
+ self.inner.clone().arr().to_list().into()
28
+ }
29
+
30
+ pub fn arr_all(&self) -> Self {
31
+ self.inner.clone().arr().all().into()
32
+ }
33
+
34
+ pub fn arr_any(&self) -> Self {
35
+ self.inner.clone().arr().any().into()
36
+ }
37
+
38
+ pub fn arr_sort(&self, descending: bool, nulls_last: bool) -> Self {
39
+ self.inner
40
+ .clone()
41
+ .arr()
42
+ .sort(SortOptions {
43
+ descending,
44
+ nulls_last,
45
+ ..Default::default()
46
+ })
47
+ .into()
48
+ }
49
+
50
+ pub fn arr_reverse(&self) -> Self {
51
+ self.inner.clone().arr().reverse().into()
52
+ }
53
+
54
+ pub fn arr_arg_min(&self) -> Self {
55
+ self.inner.clone().arr().arg_min().into()
56
+ }
57
+
58
+ pub fn arr_arg_max(&self) -> Self {
59
+ self.inner.clone().arr().arg_max().into()
60
+ }
61
+
62
+ pub fn arr_get(&self, index: &RbExpr, null_on_oob: bool) -> Self {
63
+ self.inner
64
+ .clone()
65
+ .arr()
66
+ .get(index.inner.clone(), null_on_oob)
67
+ .into()
68
+ }
69
+
70
+ pub fn arr_join(&self, separator: &RbExpr, ignore_nulls: bool) -> Self {
71
+ self.inner
72
+ .clone()
73
+ .arr()
74
+ .join(separator.inner.clone(), ignore_nulls)
75
+ .into()
76
+ }
77
+
78
+ pub fn arr_contains(&self, other: &RbExpr) -> Self {
79
+ self.inner
80
+ .clone()
81
+ .arr()
82
+ .contains(other.inner.clone())
83
+ .into()
84
+ }
85
+
86
+ pub fn arr_count_matches(&self, expr: &RbExpr) -> Self {
87
+ self.inner
88
+ .clone()
89
+ .arr()
90
+ .count_matches(expr.inner.clone())
91
+ .into()
92
+ }
15
93
  }
@@ -37,11 +37,16 @@ impl RbExpr {
37
37
  self.inner.clone().dt().cast_time_unit(tu.0).into()
38
38
  }
39
39
 
40
- pub fn dt_replace_time_zone(&self, time_zone: Option<String>, ambiguous: &Self) -> Self {
40
+ pub fn dt_replace_time_zone(
41
+ &self,
42
+ time_zone: Option<String>,
43
+ ambiguous: &Self,
44
+ non_existent: Wrap<NonExistent>,
45
+ ) -> Self {
41
46
  self.inner
42
47
  .clone()
43
48
  .dt()
44
- .replace_time_zone(time_zone, ambiguous.inner.clone())
49
+ .replace_time_zone(time_zone, ambiguous.inner.clone(), non_existent.0)
45
50
  .into()
46
51
  }
47
52
 
@@ -61,6 +66,14 @@ impl RbExpr {
61
66
  self.inner.clone().dt().month_end().into()
62
67
  }
63
68
 
69
+ pub fn dt_base_utc_offset(&self) -> Self {
70
+ self.inner.clone().dt().base_utc_offset().into()
71
+ }
72
+
73
+ pub fn dt_dst_offset(&self) -> Self {
74
+ self.inner.clone().dt().dst_offset().into()
75
+ }
76
+
64
77
  pub fn dt_round(&self, every: String, offset: String) -> Self {
65
78
  self.inner.clone().dt().round(&every, &offset).into()
66
79
  }
@@ -149,73 +162,31 @@ impl RbExpr {
149
162
  self.inner.clone().dt().timestamp(tu.0).into()
150
163
  }
151
164
 
152
- pub fn duration_days(&self) -> Self {
153
- self.inner
154
- .clone()
155
- .map(
156
- |s| Ok(Some(s.duration()?.days().into_series())),
157
- GetOutput::from_type(DataType::Int64),
158
- )
159
- .into()
165
+ pub fn dt_total_days(&self) -> Self {
166
+ self.inner.clone().dt().total_days().into()
160
167
  }
161
168
 
162
- pub fn duration_hours(&self) -> Self {
163
- self.inner
164
- .clone()
165
- .map(
166
- |s| Ok(Some(s.duration()?.hours().into_series())),
167
- GetOutput::from_type(DataType::Int64),
168
- )
169
- .into()
169
+ pub fn dt_total_hours(&self) -> Self {
170
+ self.inner.clone().dt().total_hours().into()
170
171
  }
171
172
 
172
- pub fn duration_minutes(&self) -> Self {
173
- self.inner
174
- .clone()
175
- .map(
176
- |s| Ok(Some(s.duration()?.minutes().into_series())),
177
- GetOutput::from_type(DataType::Int64),
178
- )
179
- .into()
173
+ pub fn dt_total_minutes(&self) -> Self {
174
+ self.inner.clone().dt().total_minutes().into()
180
175
  }
181
176
 
182
- pub fn duration_seconds(&self) -> Self {
183
- self.inner
184
- .clone()
185
- .map(
186
- |s| Ok(Some(s.duration()?.seconds().into_series())),
187
- GetOutput::from_type(DataType::Int64),
188
- )
189
- .into()
177
+ pub fn dt_total_seconds(&self) -> Self {
178
+ self.inner.clone().dt().total_seconds().into()
190
179
  }
191
180
 
192
- pub fn duration_milliseconds(&self) -> Self {
193
- self.inner
194
- .clone()
195
- .map(
196
- |s| Ok(Some(s.duration()?.milliseconds().into_series())),
197
- GetOutput::from_type(DataType::Int64),
198
- )
199
- .into()
181
+ pub fn dt_total_milliseconds(&self) -> Self {
182
+ self.inner.clone().dt().total_milliseconds().into()
200
183
  }
201
184
 
202
- pub fn duration_microseconds(&self) -> Self {
203
- self.inner
204
- .clone()
205
- .map(
206
- |s| Ok(Some(s.duration()?.microseconds().into_series())),
207
- GetOutput::from_type(DataType::Int64),
208
- )
209
- .into()
185
+ pub fn dt_total_microseconds(&self) -> Self {
186
+ self.inner.clone().dt().total_microseconds().into()
210
187
  }
211
188
 
212
- pub fn duration_nanoseconds(&self) -> Self {
213
- self.inner
214
- .clone()
215
- .map(
216
- |s| Ok(Some(s.duration()?.nanoseconds().into_series())),
217
- GetOutput::from_type(DataType::Int64),
218
- )
219
- .into()
189
+ pub fn dt_total_nanoseconds(&self) -> Self {
190
+ self.inner.clone().dt().total_nanoseconds().into()
220
191
  }
221
192
  }