polars-df 0.15.0 → 0.26.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 (206) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +274 -0
  3. data/Cargo.lock +1465 -867
  4. data/Cargo.toml +3 -0
  5. data/LICENSE.txt +2 -2
  6. data/README.md +87 -37
  7. data/ext/polars/Cargo.toml +47 -16
  8. data/ext/polars/src/c_api/allocator.rs +7 -0
  9. data/ext/polars/src/c_api/mod.rs +1 -0
  10. data/ext/polars/src/catalog/mod.rs +1 -0
  11. data/ext/polars/src/catalog/unity.rs +470 -0
  12. data/ext/polars/src/conversion/any_value.rs +99 -84
  13. data/ext/polars/src/conversion/categorical.rs +30 -0
  14. data/ext/polars/src/conversion/chunked_array.rs +71 -62
  15. data/ext/polars/src/conversion/datetime.rs +63 -0
  16. data/ext/polars/src/conversion/mod.rs +796 -312
  17. data/ext/polars/src/dataframe/construction.rs +6 -18
  18. data/ext/polars/src/dataframe/export.rs +30 -39
  19. data/ext/polars/src/dataframe/general.rs +294 -362
  20. data/ext/polars/src/dataframe/io.rs +33 -150
  21. data/ext/polars/src/dataframe/map.rs +175 -0
  22. data/ext/polars/src/dataframe/mod.rs +37 -5
  23. data/ext/polars/src/dataframe/serde.rs +23 -8
  24. data/ext/polars/src/error.rs +44 -7
  25. data/ext/polars/src/exceptions.rs +21 -8
  26. data/ext/polars/src/expr/array.rs +86 -22
  27. data/ext/polars/src/expr/binary.rs +50 -1
  28. data/ext/polars/src/expr/bitwise.rs +39 -0
  29. data/ext/polars/src/expr/categorical.rs +20 -0
  30. data/ext/polars/src/expr/datatype.rs +51 -0
  31. data/ext/polars/src/expr/datetime.rs +99 -41
  32. data/ext/polars/src/expr/extension.rs +12 -0
  33. data/ext/polars/src/expr/general.rs +252 -128
  34. data/ext/polars/src/expr/list.rs +56 -60
  35. data/ext/polars/src/expr/meta.rs +30 -35
  36. data/ext/polars/src/expr/mod.rs +28 -6
  37. data/ext/polars/src/expr/name.rs +29 -14
  38. data/ext/polars/src/expr/rolling.rs +111 -3
  39. data/ext/polars/src/expr/selector.rs +219 -0
  40. data/ext/polars/src/expr/serde.rs +28 -0
  41. data/ext/polars/src/expr/string.rs +118 -20
  42. data/ext/polars/src/expr/struct.rs +14 -1
  43. data/ext/polars/src/file.rs +194 -86
  44. data/ext/polars/src/functions/aggregation.rs +13 -12
  45. data/ext/polars/src/functions/business.rs +2 -3
  46. data/ext/polars/src/functions/eager.rs +3 -2
  47. data/ext/polars/src/functions/io.rs +90 -18
  48. data/ext/polars/src/functions/lazy.rs +267 -118
  49. data/ext/polars/src/functions/meta.rs +8 -7
  50. data/ext/polars/src/functions/misc.rs +1 -1
  51. data/ext/polars/src/functions/mod.rs +2 -1
  52. data/ext/polars/src/functions/range.rs +88 -31
  53. data/ext/polars/src/functions/strings.rs +6 -0
  54. data/ext/polars/src/functions/utils.rs +8 -0
  55. data/ext/polars/src/interop/arrow/mod.rs +52 -1
  56. data/ext/polars/src/interop/arrow/{to_ruby.rs → to_rb.rs} +37 -7
  57. data/ext/polars/src/interop/arrow/to_rust.rs +43 -0
  58. data/ext/polars/src/interop/numo/to_numo_df.rs +1 -1
  59. data/ext/polars/src/interop/numo/to_numo_series.rs +72 -50
  60. data/ext/polars/src/io/cloud_options.rs +107 -0
  61. data/ext/polars/src/io/mod.rs +4 -0
  62. data/ext/polars/src/io/scan_options.rs +113 -0
  63. data/ext/polars/src/io/sink_options.rs +46 -0
  64. data/ext/polars/src/io/sink_output.rs +21 -0
  65. data/ext/polars/src/lazyframe/exitable.rs +39 -0
  66. data/ext/polars/src/lazyframe/general.rs +846 -368
  67. data/ext/polars/src/lazyframe/mod.rs +58 -5
  68. data/ext/polars/src/lazyframe/optflags.rs +59 -0
  69. data/ext/polars/src/lazyframe/serde.rs +36 -4
  70. data/ext/polars/src/lazyframe/sink.rs +46 -0
  71. data/ext/polars/src/lazygroupby.rs +38 -9
  72. data/ext/polars/src/lib.rs +574 -165
  73. data/ext/polars/src/map/lazy.rs +44 -74
  74. data/ext/polars/src/map/mod.rs +18 -254
  75. data/ext/polars/src/map/series.rs +241 -1087
  76. data/ext/polars/src/on_startup.rs +192 -9
  77. data/ext/polars/src/prelude.rs +1 -0
  78. data/ext/polars/src/rb_modules.rs +10 -57
  79. data/ext/polars/src/ruby/exceptions.rs +26 -0
  80. data/ext/polars/src/ruby/gvl.rs +104 -0
  81. data/ext/polars/src/ruby/lazy.rs +46 -0
  82. data/ext/polars/src/ruby/mod.rs +11 -0
  83. data/ext/polars/src/ruby/numo.rs +52 -0
  84. data/ext/polars/src/ruby/plan_callback.rs +198 -0
  85. data/ext/polars/src/ruby/rb_modules.rs +16 -0
  86. data/ext/polars/src/ruby/ruby_convert_registry.rs +51 -0
  87. data/ext/polars/src/ruby/ruby_function.rs +11 -0
  88. data/ext/polars/src/ruby/ruby_udf.rs +164 -0
  89. data/ext/polars/src/ruby/thread.rs +65 -0
  90. data/ext/polars/src/ruby/utils.rs +39 -0
  91. data/ext/polars/src/series/aggregation.rs +116 -91
  92. data/ext/polars/src/series/arithmetic.rs +16 -22
  93. data/ext/polars/src/series/comparison.rs +101 -222
  94. data/ext/polars/src/series/construction.rs +80 -70
  95. data/ext/polars/src/series/export.rs +98 -56
  96. data/ext/polars/src/series/general.rs +323 -440
  97. data/ext/polars/src/series/import.rs +22 -5
  98. data/ext/polars/src/series/map.rs +103 -0
  99. data/ext/polars/src/series/mod.rs +57 -15
  100. data/ext/polars/src/series/scatter.rs +139 -82
  101. data/ext/polars/src/sql.rs +16 -9
  102. data/ext/polars/src/testing/frame.rs +31 -0
  103. data/ext/polars/src/testing/mod.rs +5 -0
  104. data/ext/polars/src/testing/series.rs +31 -0
  105. data/ext/polars/src/timeout.rs +105 -0
  106. data/ext/polars/src/utils.rs +105 -4
  107. data/lib/polars/array_expr.rb +500 -22
  108. data/lib/polars/array_name_space.rb +384 -10
  109. data/lib/polars/batched_csv_reader.rb +48 -66
  110. data/lib/polars/binary_expr.rb +217 -0
  111. data/lib/polars/binary_name_space.rb +155 -1
  112. data/lib/polars/cat_expr.rb +224 -0
  113. data/lib/polars/cat_name_space.rb +132 -32
  114. data/lib/polars/catalog/unity/catalog_info.rb +20 -0
  115. data/lib/polars/catalog/unity/column_info.rb +31 -0
  116. data/lib/polars/catalog/unity/namespace_info.rb +21 -0
  117. data/lib/polars/catalog/unity/table_info.rb +50 -0
  118. data/lib/polars/catalog.rb +448 -0
  119. data/lib/polars/collect_batches.rb +22 -0
  120. data/lib/polars/config.rb +3 -3
  121. data/lib/polars/convert.rb +201 -36
  122. data/lib/polars/data_frame.rb +2851 -1017
  123. data/lib/polars/data_frame_plot.rb +173 -0
  124. data/lib/polars/data_type_expr.rb +52 -0
  125. data/lib/polars/data_type_group.rb +6 -0
  126. data/lib/polars/data_types.rb +118 -18
  127. data/lib/polars/date_time_expr.rb +426 -84
  128. data/lib/polars/date_time_name_space.rb +384 -111
  129. data/lib/polars/dynamic_group_by.rb +102 -10
  130. data/lib/polars/exceptions.rb +50 -5
  131. data/lib/polars/expr.rb +2159 -915
  132. data/lib/polars/extension_expr.rb +39 -0
  133. data/lib/polars/extension_name_space.rb +39 -0
  134. data/lib/polars/functions/aggregation/horizontal.rb +11 -6
  135. data/lib/polars/functions/aggregation/vertical.rb +2 -3
  136. data/lib/polars/functions/as_datatype.rb +290 -8
  137. data/lib/polars/functions/business.rb +95 -0
  138. data/lib/polars/functions/col.rb +6 -5
  139. data/lib/polars/functions/datatype.rb +62 -0
  140. data/lib/polars/functions/eager.rb +426 -24
  141. data/lib/polars/functions/escape_regex.rb +21 -0
  142. data/lib/polars/functions/lazy.rb +813 -195
  143. data/lib/polars/functions/lit.rb +21 -10
  144. data/lib/polars/functions/range/int_range.rb +74 -2
  145. data/lib/polars/functions/range/linear_space.rb +195 -0
  146. data/lib/polars/functions/range/time_range.rb +1 -1
  147. data/lib/polars/functions/repeat.rb +7 -12
  148. data/lib/polars/functions/whenthen.rb +2 -2
  149. data/lib/polars/group_by.rb +188 -58
  150. data/lib/polars/iceberg_dataset.rb +108 -0
  151. data/lib/polars/in_process_query.rb +37 -0
  152. data/lib/polars/io/cloud.rb +18 -0
  153. data/lib/polars/io/csv.rb +336 -128
  154. data/lib/polars/io/database.rb +19 -4
  155. data/lib/polars/io/delta.rb +134 -0
  156. data/lib/polars/io/iceberg.rb +34 -0
  157. data/lib/polars/io/ipc.rb +63 -63
  158. data/lib/polars/io/json.rb +16 -0
  159. data/lib/polars/io/lines.rb +172 -0
  160. data/lib/polars/io/ndjson.rb +176 -20
  161. data/lib/polars/io/parquet.rb +173 -95
  162. data/lib/polars/io/scan_options.rb +55 -0
  163. data/lib/polars/io/sink_options.rb +27 -0
  164. data/lib/polars/io/utils.rb +17 -0
  165. data/lib/polars/lazy_frame.rb +3017 -622
  166. data/lib/polars/lazy_group_by.rb +436 -2
  167. data/lib/polars/list_expr.rb +551 -59
  168. data/lib/polars/list_name_space.rb +465 -51
  169. data/lib/polars/meta_expr.rb +146 -24
  170. data/lib/polars/name_expr.rb +87 -2
  171. data/lib/polars/query_opt_flags.rb +264 -0
  172. data/lib/polars/rolling_group_by.rb +90 -5
  173. data/lib/polars/scan_cast_options.rb +86 -0
  174. data/lib/polars/schema.rb +128 -0
  175. data/lib/polars/selector.rb +245 -0
  176. data/lib/polars/selectors.rb +1048 -201
  177. data/lib/polars/series.rb +2522 -774
  178. data/lib/polars/series_plot.rb +72 -0
  179. data/lib/polars/slice.rb +1 -1
  180. data/lib/polars/sql_context.rb +13 -6
  181. data/lib/polars/string_cache.rb +19 -72
  182. data/lib/polars/string_expr.rb +561 -107
  183. data/lib/polars/string_name_space.rb +781 -109
  184. data/lib/polars/struct_expr.rb +139 -18
  185. data/lib/polars/struct_name_space.rb +19 -1
  186. data/lib/polars/testing.rb +24 -273
  187. data/lib/polars/utils/constants.rb +2 -0
  188. data/lib/polars/utils/construction/data_frame.rb +410 -0
  189. data/lib/polars/utils/construction/series.rb +350 -0
  190. data/lib/polars/utils/construction/utils.rb +9 -0
  191. data/lib/polars/utils/convert.rb +18 -8
  192. data/lib/polars/utils/deprecation.rb +11 -0
  193. data/lib/polars/utils/parse.rb +62 -9
  194. data/lib/polars/utils/reduce_balanced.rb +43 -0
  195. data/lib/polars/utils/serde.rb +22 -0
  196. data/lib/polars/utils/unstable.rb +19 -0
  197. data/lib/polars/utils/various.rb +86 -1
  198. data/lib/polars/utils.rb +63 -48
  199. data/lib/polars/version.rb +1 -1
  200. data/lib/polars.rb +85 -2
  201. metadata +80 -28
  202. data/ext/polars/src/allocator.rs +0 -13
  203. data/ext/polars/src/batched_csv.rs +0 -138
  204. data/ext/polars/src/functions/string_cache.rs +0 -25
  205. data/ext/polars/src/map/dataframe.rs +0 -338
  206. data/lib/polars/plot.rb +0 -109
@@ -1,19 +1,72 @@
1
+ mod exitable;
1
2
  mod general;
3
+ mod optflags;
2
4
  mod serde;
5
+ mod sink;
3
6
 
4
- use polars::lazy::frame::LazyFrame;
5
- use std::cell::RefCell;
7
+ pub use exitable::RbInProcessQuery;
8
+ pub use general::RbCollectBatches;
9
+ use magnus::{TryConvert, Value};
10
+ use parking_lot::RwLock;
11
+ use polars::prelude::{Engine, LazyFrame, OptFlags};
12
+
13
+ use crate::prelude::Wrap;
14
+ use crate::{RbResult, RbValueError};
6
15
 
7
16
  #[magnus::wrap(class = "Polars::RbLazyFrame")]
8
- #[derive(Clone)]
17
+ #[repr(transparent)]
9
18
  pub struct RbLazyFrame {
10
- pub ldf: RefCell<LazyFrame>,
19
+ pub ldf: RwLock<LazyFrame>,
20
+ }
21
+
22
+ impl Clone for RbLazyFrame {
23
+ fn clone(&self) -> Self {
24
+ Self {
25
+ ldf: RwLock::new(self.ldf.read().clone()),
26
+ }
27
+ }
11
28
  }
12
29
 
13
30
  impl From<LazyFrame> for RbLazyFrame {
14
31
  fn from(ldf: LazyFrame) -> Self {
15
32
  RbLazyFrame {
16
- ldf: RefCell::new(ldf),
33
+ ldf: RwLock::new(ldf),
17
34
  }
18
35
  }
19
36
  }
37
+
38
+ impl From<RbLazyFrame> for LazyFrame {
39
+ fn from(pldf: RbLazyFrame) -> Self {
40
+ pldf.ldf.into_inner()
41
+ }
42
+ }
43
+
44
+ #[magnus::wrap(class = "Polars::RbOptFlags")]
45
+ pub struct RbOptFlags {
46
+ pub inner: RwLock<OptFlags>,
47
+ }
48
+
49
+ impl Clone for RbOptFlags {
50
+ fn clone(&self) -> Self {
51
+ Self {
52
+ inner: RwLock::new(*self.inner.read()),
53
+ }
54
+ }
55
+ }
56
+
57
+ impl From<OptFlags> for RbOptFlags {
58
+ fn from(inner: OptFlags) -> Self {
59
+ RbOptFlags {
60
+ inner: RwLock::new(inner),
61
+ }
62
+ }
63
+ }
64
+
65
+ impl TryConvert for Wrap<Engine> {
66
+ fn try_convert(ob: Value) -> RbResult<Self> {
67
+ let parsed = String::try_convert(ob)?
68
+ .parse()
69
+ .map_err(RbValueError::new_err)?;
70
+ Ok(Wrap(parsed))
71
+ }
72
+ }
@@ -0,0 +1,59 @@
1
+ use parking_lot::RwLock;
2
+ use polars::prelude::OptFlags;
3
+
4
+ use super::RbOptFlags;
5
+
6
+ macro_rules! flag_getter_setters {
7
+ ($(($flag:ident, $getter:ident, $setter:ident, clear=$clear:literal))+) => {
8
+ impl RbOptFlags {
9
+ pub fn empty() -> Self {
10
+ Self {
11
+ inner: OptFlags::empty().into()
12
+ }
13
+ }
14
+
15
+ #[allow(clippy::should_implement_trait)]
16
+ pub fn default() -> Self {
17
+ Self { inner: OptFlags::default().into() }
18
+ }
19
+
20
+ pub fn no_optimizations(&self) {
21
+ $(if $clear {
22
+ self.inner.write().remove(OptFlags::$flag);
23
+ })+
24
+ }
25
+
26
+ pub fn copy(&self) -> Self {
27
+ Self { inner: RwLock::new(self.inner.read().clone()) }
28
+ }
29
+
30
+ $(
31
+ pub fn $getter(&self) -> bool {
32
+ self.inner.read().contains(OptFlags::$flag)
33
+ }
34
+ pub fn $setter(&self, value: bool) {
35
+ self.inner.write().set(OptFlags::$flag, value)
36
+ }
37
+ )+
38
+ }
39
+ };
40
+ }
41
+
42
+ flag_getter_setters! {
43
+ (TYPE_COERCION, get_type_coercion, set_type_coercion, clear=false)
44
+ (TYPE_CHECK, get_type_check, set_type_check, clear=false)
45
+
46
+ (PROJECTION_PUSHDOWN, get_projection_pushdown, set_projection_pushdown, clear=true)
47
+ (PREDICATE_PUSHDOWN, get_predicate_pushdown, set_predicate_pushdown, clear=true)
48
+ (CLUSTER_WITH_COLUMNS, get_cluster_with_columns, set_cluster_with_columns, clear=true)
49
+ (SIMPLIFY_EXPR, get_simplify_expression, set_simplify_expression, clear=true)
50
+ (SLICE_PUSHDOWN, get_slice_pushdown, set_slice_pushdown, clear=true)
51
+ (COMM_SUBPLAN_ELIM, get_comm_subplan_elim, set_comm_subplan_elim, clear=true)
52
+ (COMM_SUBEXPR_ELIM, get_comm_subexpr_elim, set_comm_subexpr_elim, clear=true)
53
+ (CHECK_ORDER_OBSERVE, get_check_order_observe, set_check_order_observe, clear=true)
54
+ (FAST_PROJECTION, get_fast_projection, set_fast_projection, clear=true)
55
+ (SORT_COLLAPSE, get_sort_collapse, set_sort_collapse, clear=true)
56
+
57
+ (EAGER, get_eager, set_eager, clear=true)
58
+ (STREAMING, get_streaming, set_streaming, clear=true)
59
+ }
@@ -1,14 +1,46 @@
1
+ #[cfg(feature = "serialize_binary")]
2
+ use std::io::BufReader;
3
+ use std::io::{BufWriter, Read};
4
+
1
5
  use magnus::Value;
2
6
  use polars::lazy::frame::LazyFrame;
3
7
  use polars::prelude::*;
4
- use std::io::Read;
5
8
 
9
+ use crate::exceptions::ComputeError;
6
10
  use crate::file::get_file_like;
11
+ #[cfg(feature = "serialize_binary")]
12
+ use crate::utils::to_rb_err;
7
13
  use crate::{RbLazyFrame, RbResult, RbValueError};
8
14
 
9
15
  impl RbLazyFrame {
10
- // TODO change to serialize_json
11
- pub fn read_json(rb_f: Value) -> RbResult<Self> {
16
+ #[cfg(feature = "serialize_binary")]
17
+ pub fn serialize_binary(&self, rb_f: Value) -> RbResult<()> {
18
+ let file = get_file_like(rb_f, true)?;
19
+ let writer = BufWriter::new(file);
20
+ self.ldf
21
+ .read()
22
+ .logical_plan
23
+ .serialize_versioned(writer, Default::default())
24
+ .map_err(to_rb_err)
25
+ }
26
+
27
+ pub fn serialize_json(&self, rb_f: Value) -> RbResult<()> {
28
+ let file = get_file_like(rb_f, true)?;
29
+ let writer = BufWriter::new(file);
30
+ serde_json::to_writer(writer, &self.ldf.read().logical_plan)
31
+ .map_err(|err| ComputeError::new_err(err.to_string()))
32
+ }
33
+
34
+ #[cfg(feature = "serialize_binary")]
35
+ pub fn deserialize_binary(rb_f: Value) -> RbResult<Self> {
36
+ let file = get_file_like(rb_f, false)?;
37
+ let reader = BufReader::new(file);
38
+
39
+ let lp: DslPlan = DslPlan::deserialize_versioned(reader).map_err(to_rb_err)?;
40
+ Ok(LazyFrame::from(lp).into())
41
+ }
42
+
43
+ pub fn deserialize_json(rb_f: Value) -> RbResult<Self> {
12
44
  // it is faster to first read to memory and then parse: https://github.com/serde-rs/json/issues/160
13
45
  // so don't bother with files.
14
46
  let mut json = String::new();
@@ -25,7 +57,7 @@ impl RbLazyFrame {
25
57
  let json = unsafe { std::mem::transmute::<&'_ str, &'static str>(json.as_str()) };
26
58
 
27
59
  let lp = serde_json::from_str::<DslPlan>(json)
28
- .map_err(|err| RbValueError::new_err(format!("{:?}", err)))?;
60
+ .map_err(|err| RbValueError::new_err(format!("{err:?}")))?;
29
61
  Ok(LazyFrame::from(lp).into())
30
62
  }
31
63
  }
@@ -0,0 +1,46 @@
1
+ use std::sync::{Arc, Mutex};
2
+
3
+ use magnus::{Ruby, TryConvert, Value};
4
+ use polars::prelude::sync_on_close::SyncOnCloseType;
5
+ use polars::prelude::{PlRefPath, SpecialEq};
6
+
7
+ use crate::prelude::Wrap;
8
+ use crate::ruby::gvl::GvlExt;
9
+ use crate::{RbResult, RbValueError};
10
+
11
+ impl TryConvert for Wrap<polars_plan::dsl::SinkTarget> {
12
+ fn try_convert(ob: Value) -> RbResult<Self> {
13
+ if let Ok(v) = String::try_convert(ob) {
14
+ Ok(Wrap(polars::prelude::SinkTarget::Path(PlRefPath::new(&v))))
15
+ } else {
16
+ let writer = Ruby::attach(|rb| {
17
+ let rb_f = ob;
18
+ RbResult::Ok(
19
+ crate::file::try_get_rbfile(rb, rb_f, true)?
20
+ .0
21
+ .into_writeable(),
22
+ )
23
+ })?;
24
+
25
+ Ok(Wrap(polars_plan::prelude::SinkTarget::Dyn(SpecialEq::new(
26
+ Arc::new(Mutex::new(Some(writer))),
27
+ ))))
28
+ }
29
+ }
30
+ }
31
+
32
+ impl TryConvert for Wrap<SyncOnCloseType> {
33
+ fn try_convert(ob: Value) -> RbResult<Self> {
34
+ let parsed = match String::try_convert(ob)?.as_str() {
35
+ "none" => SyncOnCloseType::None,
36
+ "data" => SyncOnCloseType::Data,
37
+ "all" => SyncOnCloseType::All,
38
+ v => {
39
+ return Err(RbValueError::new_err(format!(
40
+ "`sync_on_close` must be one of {{'none', 'data', 'all'}}, got {v}",
41
+ )));
42
+ }
43
+ };
44
+ Ok(Wrap(parsed))
45
+ }
46
+ }
@@ -1,29 +1,58 @@
1
- use magnus::RArray;
2
- use polars::lazy::frame::LazyGroupBy;
3
- use std::cell::RefCell;
1
+ use std::sync::Arc;
4
2
 
5
- use crate::expr::rb_exprs_to_exprs;
3
+ use magnus::{RArray, Value};
4
+ use polars::lazy::frame::{LazyFrame, LazyGroupBy};
5
+ use polars::prelude::{PlanCallback, Schema};
6
+
7
+ use crate::conversion::Wrap;
8
+ use crate::error::RbPolarsErr;
9
+ use crate::expr::ToExprs;
10
+ use crate::ruby::plan_callback::PlanCallbackExt;
11
+ use crate::ruby::ruby_function::RubyObject;
6
12
  use crate::{RbLazyFrame, RbResult};
7
13
 
8
14
  #[magnus::wrap(class = "Polars::RbLazyGroupBy")]
9
15
  pub struct RbLazyGroupBy {
10
- pub lgb: RefCell<Option<LazyGroupBy>>,
16
+ pub lgb: Option<LazyGroupBy>,
11
17
  }
12
18
 
13
19
  impl RbLazyGroupBy {
20
+ pub fn having(&self, predicates: RArray) -> RbResult<RbLazyGroupBy> {
21
+ let mut lgb = self.lgb.clone().unwrap();
22
+ let predicates = predicates.to_exprs()?;
23
+ for predicate in predicates.into_iter() {
24
+ lgb = lgb.having(predicate);
25
+ }
26
+ Ok(RbLazyGroupBy { lgb: Some(lgb) })
27
+ }
28
+
14
29
  pub fn agg(&self, aggs: RArray) -> RbResult<RbLazyFrame> {
15
- let lgb = self.lgb.borrow_mut().take().unwrap();
16
- let aggs = rb_exprs_to_exprs(aggs)?;
30
+ let lgb = self.lgb.clone().unwrap();
31
+ let aggs = aggs.to_exprs()?;
17
32
  Ok(lgb.agg(aggs).into())
18
33
  }
19
34
 
20
35
  pub fn head(&self, n: usize) -> RbLazyFrame {
21
- let lgb = self.lgb.take().unwrap();
36
+ let lgb = self.lgb.clone().unwrap();
22
37
  lgb.head(Some(n)).into()
23
38
  }
24
39
 
25
40
  pub fn tail(&self, n: usize) -> RbLazyFrame {
26
- let lgb = self.lgb.take().unwrap();
41
+ let lgb = self.lgb.clone().unwrap();
27
42
  lgb.tail(Some(n)).into()
28
43
  }
44
+
45
+ pub fn map_groups(&self, lambda: Value, schema: Option<Wrap<Schema>>) -> RbResult<RbLazyFrame> {
46
+ let lgb = self.lgb.clone().unwrap();
47
+ let schema = match schema {
48
+ Some(schema) => Arc::new(schema.0),
49
+ None => LazyFrame::from(lgb.logical_plan.clone())
50
+ .collect_schema()
51
+ .map_err(RbPolarsErr::from)?,
52
+ };
53
+
54
+ let function = RubyObject::from(lambda);
55
+
56
+ Ok(lgb.apply(PlanCallback::new_ruby(function), schema).into())
57
+ }
29
58
  }