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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +274 -0
- data/Cargo.lock +1465 -867
- data/Cargo.toml +3 -0
- data/LICENSE.txt +2 -2
- data/README.md +87 -37
- data/ext/polars/Cargo.toml +47 -16
- data/ext/polars/src/c_api/allocator.rs +7 -0
- data/ext/polars/src/c_api/mod.rs +1 -0
- data/ext/polars/src/catalog/mod.rs +1 -0
- data/ext/polars/src/catalog/unity.rs +470 -0
- data/ext/polars/src/conversion/any_value.rs +99 -84
- data/ext/polars/src/conversion/categorical.rs +30 -0
- data/ext/polars/src/conversion/chunked_array.rs +71 -62
- data/ext/polars/src/conversion/datetime.rs +63 -0
- data/ext/polars/src/conversion/mod.rs +796 -312
- data/ext/polars/src/dataframe/construction.rs +6 -18
- data/ext/polars/src/dataframe/export.rs +30 -39
- data/ext/polars/src/dataframe/general.rs +294 -362
- data/ext/polars/src/dataframe/io.rs +33 -150
- data/ext/polars/src/dataframe/map.rs +175 -0
- data/ext/polars/src/dataframe/mod.rs +37 -5
- data/ext/polars/src/dataframe/serde.rs +23 -8
- data/ext/polars/src/error.rs +44 -7
- data/ext/polars/src/exceptions.rs +21 -8
- data/ext/polars/src/expr/array.rs +86 -22
- data/ext/polars/src/expr/binary.rs +50 -1
- data/ext/polars/src/expr/bitwise.rs +39 -0
- data/ext/polars/src/expr/categorical.rs +20 -0
- data/ext/polars/src/expr/datatype.rs +51 -0
- data/ext/polars/src/expr/datetime.rs +99 -41
- data/ext/polars/src/expr/extension.rs +12 -0
- data/ext/polars/src/expr/general.rs +252 -128
- data/ext/polars/src/expr/list.rs +56 -60
- data/ext/polars/src/expr/meta.rs +30 -35
- data/ext/polars/src/expr/mod.rs +28 -6
- data/ext/polars/src/expr/name.rs +29 -14
- data/ext/polars/src/expr/rolling.rs +111 -3
- data/ext/polars/src/expr/selector.rs +219 -0
- data/ext/polars/src/expr/serde.rs +28 -0
- data/ext/polars/src/expr/string.rs +118 -20
- data/ext/polars/src/expr/struct.rs +14 -1
- data/ext/polars/src/file.rs +194 -86
- data/ext/polars/src/functions/aggregation.rs +13 -12
- data/ext/polars/src/functions/business.rs +2 -3
- data/ext/polars/src/functions/eager.rs +3 -2
- data/ext/polars/src/functions/io.rs +90 -18
- data/ext/polars/src/functions/lazy.rs +267 -118
- data/ext/polars/src/functions/meta.rs +8 -7
- data/ext/polars/src/functions/misc.rs +1 -1
- data/ext/polars/src/functions/mod.rs +2 -1
- data/ext/polars/src/functions/range.rs +88 -31
- data/ext/polars/src/functions/strings.rs +6 -0
- data/ext/polars/src/functions/utils.rs +8 -0
- data/ext/polars/src/interop/arrow/mod.rs +52 -1
- data/ext/polars/src/interop/arrow/{to_ruby.rs → to_rb.rs} +37 -7
- data/ext/polars/src/interop/arrow/to_rust.rs +43 -0
- data/ext/polars/src/interop/numo/to_numo_df.rs +1 -1
- data/ext/polars/src/interop/numo/to_numo_series.rs +72 -50
- data/ext/polars/src/io/cloud_options.rs +107 -0
- data/ext/polars/src/io/mod.rs +4 -0
- data/ext/polars/src/io/scan_options.rs +113 -0
- data/ext/polars/src/io/sink_options.rs +46 -0
- data/ext/polars/src/io/sink_output.rs +21 -0
- data/ext/polars/src/lazyframe/exitable.rs +39 -0
- data/ext/polars/src/lazyframe/general.rs +846 -368
- data/ext/polars/src/lazyframe/mod.rs +58 -5
- data/ext/polars/src/lazyframe/optflags.rs +59 -0
- data/ext/polars/src/lazyframe/serde.rs +36 -4
- data/ext/polars/src/lazyframe/sink.rs +46 -0
- data/ext/polars/src/lazygroupby.rs +38 -9
- data/ext/polars/src/lib.rs +574 -165
- data/ext/polars/src/map/lazy.rs +44 -74
- data/ext/polars/src/map/mod.rs +18 -254
- data/ext/polars/src/map/series.rs +241 -1087
- data/ext/polars/src/on_startup.rs +192 -9
- data/ext/polars/src/prelude.rs +1 -0
- data/ext/polars/src/rb_modules.rs +10 -57
- data/ext/polars/src/ruby/exceptions.rs +26 -0
- data/ext/polars/src/ruby/gvl.rs +104 -0
- data/ext/polars/src/ruby/lazy.rs +46 -0
- data/ext/polars/src/ruby/mod.rs +11 -0
- data/ext/polars/src/ruby/numo.rs +52 -0
- data/ext/polars/src/ruby/plan_callback.rs +198 -0
- data/ext/polars/src/ruby/rb_modules.rs +16 -0
- data/ext/polars/src/ruby/ruby_convert_registry.rs +51 -0
- data/ext/polars/src/ruby/ruby_function.rs +11 -0
- data/ext/polars/src/ruby/ruby_udf.rs +164 -0
- data/ext/polars/src/ruby/thread.rs +65 -0
- data/ext/polars/src/ruby/utils.rs +39 -0
- data/ext/polars/src/series/aggregation.rs +116 -91
- data/ext/polars/src/series/arithmetic.rs +16 -22
- data/ext/polars/src/series/comparison.rs +101 -222
- data/ext/polars/src/series/construction.rs +80 -70
- data/ext/polars/src/series/export.rs +98 -56
- data/ext/polars/src/series/general.rs +323 -440
- data/ext/polars/src/series/import.rs +22 -5
- data/ext/polars/src/series/map.rs +103 -0
- data/ext/polars/src/series/mod.rs +57 -15
- data/ext/polars/src/series/scatter.rs +139 -82
- data/ext/polars/src/sql.rs +16 -9
- data/ext/polars/src/testing/frame.rs +31 -0
- data/ext/polars/src/testing/mod.rs +5 -0
- data/ext/polars/src/testing/series.rs +31 -0
- data/ext/polars/src/timeout.rs +105 -0
- data/ext/polars/src/utils.rs +105 -4
- data/lib/polars/array_expr.rb +500 -22
- data/lib/polars/array_name_space.rb +384 -10
- data/lib/polars/batched_csv_reader.rb +48 -66
- data/lib/polars/binary_expr.rb +217 -0
- data/lib/polars/binary_name_space.rb +155 -1
- data/lib/polars/cat_expr.rb +224 -0
- data/lib/polars/cat_name_space.rb +132 -32
- data/lib/polars/catalog/unity/catalog_info.rb +20 -0
- data/lib/polars/catalog/unity/column_info.rb +31 -0
- data/lib/polars/catalog/unity/namespace_info.rb +21 -0
- data/lib/polars/catalog/unity/table_info.rb +50 -0
- data/lib/polars/catalog.rb +448 -0
- data/lib/polars/collect_batches.rb +22 -0
- data/lib/polars/config.rb +3 -3
- data/lib/polars/convert.rb +201 -36
- data/lib/polars/data_frame.rb +2851 -1017
- data/lib/polars/data_frame_plot.rb +173 -0
- data/lib/polars/data_type_expr.rb +52 -0
- data/lib/polars/data_type_group.rb +6 -0
- data/lib/polars/data_types.rb +118 -18
- data/lib/polars/date_time_expr.rb +426 -84
- data/lib/polars/date_time_name_space.rb +384 -111
- data/lib/polars/dynamic_group_by.rb +102 -10
- data/lib/polars/exceptions.rb +50 -5
- data/lib/polars/expr.rb +2159 -915
- data/lib/polars/extension_expr.rb +39 -0
- data/lib/polars/extension_name_space.rb +39 -0
- data/lib/polars/functions/aggregation/horizontal.rb +11 -6
- data/lib/polars/functions/aggregation/vertical.rb +2 -3
- data/lib/polars/functions/as_datatype.rb +290 -8
- data/lib/polars/functions/business.rb +95 -0
- data/lib/polars/functions/col.rb +6 -5
- data/lib/polars/functions/datatype.rb +62 -0
- data/lib/polars/functions/eager.rb +426 -24
- data/lib/polars/functions/escape_regex.rb +21 -0
- data/lib/polars/functions/lazy.rb +813 -195
- data/lib/polars/functions/lit.rb +21 -10
- data/lib/polars/functions/range/int_range.rb +74 -2
- data/lib/polars/functions/range/linear_space.rb +195 -0
- data/lib/polars/functions/range/time_range.rb +1 -1
- data/lib/polars/functions/repeat.rb +7 -12
- data/lib/polars/functions/whenthen.rb +2 -2
- data/lib/polars/group_by.rb +188 -58
- data/lib/polars/iceberg_dataset.rb +108 -0
- data/lib/polars/in_process_query.rb +37 -0
- data/lib/polars/io/cloud.rb +18 -0
- data/lib/polars/io/csv.rb +336 -128
- data/lib/polars/io/database.rb +19 -4
- data/lib/polars/io/delta.rb +134 -0
- data/lib/polars/io/iceberg.rb +34 -0
- data/lib/polars/io/ipc.rb +63 -63
- data/lib/polars/io/json.rb +16 -0
- data/lib/polars/io/lines.rb +172 -0
- data/lib/polars/io/ndjson.rb +176 -20
- data/lib/polars/io/parquet.rb +173 -95
- data/lib/polars/io/scan_options.rb +55 -0
- data/lib/polars/io/sink_options.rb +27 -0
- data/lib/polars/io/utils.rb +17 -0
- data/lib/polars/lazy_frame.rb +3017 -622
- data/lib/polars/lazy_group_by.rb +436 -2
- data/lib/polars/list_expr.rb +551 -59
- data/lib/polars/list_name_space.rb +465 -51
- data/lib/polars/meta_expr.rb +146 -24
- data/lib/polars/name_expr.rb +87 -2
- data/lib/polars/query_opt_flags.rb +264 -0
- data/lib/polars/rolling_group_by.rb +90 -5
- data/lib/polars/scan_cast_options.rb +86 -0
- data/lib/polars/schema.rb +128 -0
- data/lib/polars/selector.rb +245 -0
- data/lib/polars/selectors.rb +1048 -201
- data/lib/polars/series.rb +2522 -774
- data/lib/polars/series_plot.rb +72 -0
- data/lib/polars/slice.rb +1 -1
- data/lib/polars/sql_context.rb +13 -6
- data/lib/polars/string_cache.rb +19 -72
- data/lib/polars/string_expr.rb +561 -107
- data/lib/polars/string_name_space.rb +781 -109
- data/lib/polars/struct_expr.rb +139 -18
- data/lib/polars/struct_name_space.rb +19 -1
- data/lib/polars/testing.rb +24 -273
- data/lib/polars/utils/constants.rb +2 -0
- data/lib/polars/utils/construction/data_frame.rb +410 -0
- data/lib/polars/utils/construction/series.rb +350 -0
- data/lib/polars/utils/construction/utils.rb +9 -0
- data/lib/polars/utils/convert.rb +18 -8
- data/lib/polars/utils/deprecation.rb +11 -0
- data/lib/polars/utils/parse.rb +62 -9
- data/lib/polars/utils/reduce_balanced.rb +43 -0
- data/lib/polars/utils/serde.rb +22 -0
- data/lib/polars/utils/unstable.rb +19 -0
- data/lib/polars/utils/various.rb +86 -1
- data/lib/polars/utils.rb +63 -48
- data/lib/polars/version.rb +1 -1
- data/lib/polars.rb +85 -2
- metadata +80 -28
- data/ext/polars/src/allocator.rs +0 -13
- data/ext/polars/src/batched_csv.rs +0 -138
- data/ext/polars/src/functions/string_cache.rs +0 -25
- data/ext/polars/src/map/dataframe.rs +0 -338
- data/lib/polars/plot.rb +0 -109
|
@@ -1,52 +1,90 @@
|
|
|
1
|
-
use
|
|
2
|
-
use
|
|
1
|
+
use arrow::ffi::export_iterator;
|
|
2
|
+
use magnus::{
|
|
3
|
+
IntoValue, RArray, RHash, Ruby, TryConvert, Value, r_hash::ForEach, value::ReprValue,
|
|
4
|
+
};
|
|
5
|
+
use parking_lot::Mutex;
|
|
6
|
+
use polars::frame::PivotColumnNaming;
|
|
7
|
+
use polars::io::RowIndex;
|
|
3
8
|
use polars::lazy::frame::LazyFrame;
|
|
4
9
|
use polars::prelude::*;
|
|
5
|
-
use
|
|
6
|
-
use
|
|
7
|
-
use
|
|
10
|
+
use polars_core::query_result::QueryResult;
|
|
11
|
+
use polars_plan::dsl::ScanSources;
|
|
12
|
+
use polars_plan::plans::{HintIR, Sorted};
|
|
8
13
|
use std::num::NonZeroUsize;
|
|
9
|
-
use std::path::PathBuf;
|
|
10
14
|
|
|
15
|
+
use super::{RbLazyFrame, RbOptFlags};
|
|
11
16
|
use crate::conversion::*;
|
|
12
|
-
use crate::expr::
|
|
13
|
-
use crate::
|
|
14
|
-
use crate::
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
use crate::expr::ToExprs;
|
|
18
|
+
use crate::expr::selector::RbSelector;
|
|
19
|
+
use crate::io::cloud_options::OptRbCloudOptions;
|
|
20
|
+
use crate::io::scan_options::RbScanOptions;
|
|
21
|
+
use crate::io::sink_options::RbSinkOptions;
|
|
22
|
+
use crate::io::sink_output::RbFileSinkDestination;
|
|
23
|
+
use crate::ruby::gvl::GvlExt;
|
|
24
|
+
use crate::ruby::lazy::RubyUdfLazyFrameExt;
|
|
25
|
+
use crate::ruby::plan_callback::PlanCallbackExt;
|
|
26
|
+
use crate::ruby::ruby_function::RubyObject;
|
|
27
|
+
use crate::ruby::utils::TryIntoValue;
|
|
28
|
+
use crate::utils::{EnterPolarsExt, to_rb_err};
|
|
29
|
+
use crate::{
|
|
30
|
+
RbArrowArrayStream, RbDataFrame, RbExpr, RbLazyGroupBy, RbPolarsErr, RbResult, RbTypeError,
|
|
31
|
+
RbValueError,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
fn rbobject_to_first_path_and_scan_sources(
|
|
35
|
+
obj: Value,
|
|
36
|
+
) -> RbResult<(Option<PlRefPath>, ScanSources)> {
|
|
37
|
+
use crate::file::{RubyScanSourceInput, get_ruby_scan_source_input};
|
|
18
38
|
Ok(match get_ruby_scan_source_input(obj, false)? {
|
|
19
|
-
RubyScanSourceInput::Path(path) => (
|
|
39
|
+
RubyScanSourceInput::Path(path) => (
|
|
40
|
+
Some(path.clone()),
|
|
41
|
+
ScanSources::Paths(FromIterator::from_iter([path])),
|
|
42
|
+
),
|
|
20
43
|
RubyScanSourceInput::File(file) => (None, ScanSources::Files([file].into())),
|
|
21
44
|
RubyScanSourceInput::Buffer(buff) => (None, ScanSources::Buffers([buff].into())),
|
|
22
45
|
})
|
|
23
46
|
}
|
|
24
47
|
|
|
25
48
|
impl RbLazyFrame {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
let
|
|
49
|
+
pub fn new_from_ndjson(arguments: &[Value]) -> RbResult<Self> {
|
|
50
|
+
let source = Option::<Value>::try_convert(arguments[0])?;
|
|
51
|
+
let sources = Wrap::<ScanSources>::try_convert(arguments[1])?;
|
|
52
|
+
let infer_schema_length = Option::<usize>::try_convert(arguments[2])?;
|
|
53
|
+
let schema = Option::<Wrap<Schema>>::try_convert(arguments[3])?;
|
|
54
|
+
let schema_overrides = Option::<Wrap<Schema>>::try_convert(arguments[4])?;
|
|
55
|
+
let batch_size = Option::<NonZeroUsize>::try_convert(arguments[5])?;
|
|
56
|
+
let n_rows = Option::<usize>::try_convert(arguments[6])?;
|
|
57
|
+
let low_memory = bool::try_convert(arguments[7])?;
|
|
58
|
+
let rechunk = bool::try_convert(arguments[8])?;
|
|
59
|
+
let row_index = Option::<(String, IdxSize)>::try_convert(arguments[9])?;
|
|
60
|
+
let ignore_errors = bool::try_convert(arguments[10])?;
|
|
61
|
+
let include_file_paths = Option::<String>::try_convert(arguments[11])?;
|
|
62
|
+
let cloud_options = OptRbCloudOptions::try_convert(arguments[12])?;
|
|
63
|
+
let credential_provider = Option::<Value>::try_convert(arguments[13])?;
|
|
64
|
+
|
|
38
65
|
let row_index = row_index.map(|(name, offset)| RowIndex {
|
|
39
66
|
name: name.into(),
|
|
40
67
|
offset,
|
|
41
68
|
});
|
|
42
69
|
|
|
43
70
|
let sources = sources.0;
|
|
44
|
-
let (
|
|
45
|
-
None => (sources.first_path().
|
|
71
|
+
let (first_path, sources) = match source {
|
|
72
|
+
None => (sources.first_path().cloned(), sources),
|
|
46
73
|
Some(source) => rbobject_to_first_path_and_scan_sources(source)?,
|
|
47
74
|
};
|
|
48
75
|
|
|
49
|
-
let r = LazyJsonLineReader::new_with_sources(sources);
|
|
76
|
+
let mut r = LazyJsonLineReader::new_with_sources(sources);
|
|
77
|
+
|
|
78
|
+
if let Some(first_path) = first_path {
|
|
79
|
+
let first_path_url = first_path.as_str();
|
|
80
|
+
|
|
81
|
+
let cloud_options = cloud_options.extract_opt_cloud_options(
|
|
82
|
+
CloudScheme::from_path(first_path_url),
|
|
83
|
+
credential_provider,
|
|
84
|
+
)?;
|
|
85
|
+
|
|
86
|
+
r = r.with_cloud_options(cloud_options);
|
|
87
|
+
};
|
|
50
88
|
|
|
51
89
|
let lf = r
|
|
52
90
|
.with_infer_schema_length(infer_schema_length.and_then(NonZeroUsize::new))
|
|
@@ -54,11 +92,11 @@ impl RbLazyFrame {
|
|
|
54
92
|
.with_n_rows(n_rows)
|
|
55
93
|
.low_memory(low_memory)
|
|
56
94
|
.with_rechunk(rechunk)
|
|
57
|
-
|
|
58
|
-
|
|
95
|
+
.with_schema(schema.map(|schema| Arc::new(schema.0)))
|
|
96
|
+
.with_schema_overwrite(schema_overrides.map(|x| Arc::new(x.0)))
|
|
59
97
|
.with_row_index(row_index)
|
|
60
|
-
|
|
61
|
-
|
|
98
|
+
.with_ignore_errors(ignore_errors)
|
|
99
|
+
.with_include_file_paths(include_file_paths.map(|x| x.into()))
|
|
62
100
|
.finish()
|
|
63
101
|
.map_err(RbPolarsErr::from)?;
|
|
64
102
|
|
|
@@ -69,27 +107,37 @@ impl RbLazyFrame {
|
|
|
69
107
|
// start arguments
|
|
70
108
|
// this pattern is needed for more than 16
|
|
71
109
|
let source = Option::<Value>::try_convert(arguments[0])?;
|
|
72
|
-
let sources = Wrap::<ScanSources>::try_convert(arguments[
|
|
73
|
-
let separator = String::try_convert(arguments[
|
|
74
|
-
let has_header = bool::try_convert(arguments[
|
|
75
|
-
let ignore_errors = bool::try_convert(arguments[
|
|
76
|
-
let skip_rows = usize::try_convert(arguments[
|
|
77
|
-
let
|
|
78
|
-
let
|
|
79
|
-
let
|
|
80
|
-
let
|
|
81
|
-
let
|
|
82
|
-
let
|
|
83
|
-
let
|
|
84
|
-
let
|
|
85
|
-
let
|
|
86
|
-
let
|
|
87
|
-
let
|
|
88
|
-
let
|
|
89
|
-
let
|
|
90
|
-
let
|
|
91
|
-
let
|
|
92
|
-
let
|
|
110
|
+
let sources = Wrap::<ScanSources>::try_convert(arguments[1])?;
|
|
111
|
+
let separator = String::try_convert(arguments[2])?;
|
|
112
|
+
let has_header = bool::try_convert(arguments[3])?;
|
|
113
|
+
let ignore_errors = bool::try_convert(arguments[4])?;
|
|
114
|
+
let skip_rows = usize::try_convert(arguments[5])?;
|
|
115
|
+
let skip_lines = usize::try_convert(arguments[6])?;
|
|
116
|
+
let n_rows = Option::<usize>::try_convert(arguments[7])?;
|
|
117
|
+
let cache = bool::try_convert(arguments[8])?;
|
|
118
|
+
let overwrite_dtype = Option::<Vec<(String, Wrap<DataType>)>>::try_convert(arguments[9])?;
|
|
119
|
+
let low_memory = bool::try_convert(arguments[10])?;
|
|
120
|
+
let comment_prefix = Option::<String>::try_convert(arguments[11])?;
|
|
121
|
+
let quote_char = Option::<String>::try_convert(arguments[12])?;
|
|
122
|
+
let null_values = Option::<Wrap<NullValues>>::try_convert(arguments[13])?;
|
|
123
|
+
let missing_utf8_is_empty_string = bool::try_convert(arguments[14])?;
|
|
124
|
+
let infer_schema_length = Option::<usize>::try_convert(arguments[15])?;
|
|
125
|
+
let with_schema_modify = Option::<Value>::try_convert(arguments[16])?;
|
|
126
|
+
let rechunk = bool::try_convert(arguments[17])?;
|
|
127
|
+
let skip_rows_after_header = usize::try_convert(arguments[18])?;
|
|
128
|
+
let encoding = Wrap::<CsvEncoding>::try_convert(arguments[19])?;
|
|
129
|
+
let row_index = Option::<(String, IdxSize)>::try_convert(arguments[20])?;
|
|
130
|
+
let try_parse_dates = bool::try_convert(arguments[21])?;
|
|
131
|
+
let eol_char = String::try_convert(arguments[22])?;
|
|
132
|
+
let raise_if_empty = bool::try_convert(arguments[23])?;
|
|
133
|
+
let truncate_ragged_lines = bool::try_convert(arguments[24])?;
|
|
134
|
+
let decimal_comma = bool::try_convert(arguments[25])?;
|
|
135
|
+
let glob = bool::try_convert(arguments[26])?;
|
|
136
|
+
let schema = Option::<Wrap<Schema>>::try_convert(arguments[27])?;
|
|
137
|
+
let cloud_options = OptRbCloudOptions::try_convert(arguments[28])?;
|
|
138
|
+
let credential_provider = Option::<Value>::try_convert(arguments[29])?;
|
|
139
|
+
let include_file_paths = Option::<String>::try_convert(arguments[30])?;
|
|
140
|
+
let missing_columns = Option::<Wrap<MissingColumnsPolicy>>::try_convert(arguments[31])?;
|
|
93
141
|
// end arguments
|
|
94
142
|
|
|
95
143
|
let null_values = null_values.map(|w| w.0);
|
|
@@ -109,23 +157,33 @@ impl RbLazyFrame {
|
|
|
109
157
|
});
|
|
110
158
|
|
|
111
159
|
let sources = sources.0;
|
|
112
|
-
let (
|
|
113
|
-
None => (sources.first_path().
|
|
160
|
+
let (first_path, sources) = match source {
|
|
161
|
+
None => (sources.first_path().cloned(), sources),
|
|
114
162
|
Some(source) => rbobject_to_first_path_and_scan_sources(source)?,
|
|
115
163
|
};
|
|
116
164
|
|
|
117
|
-
let r = LazyCsvReader::new_with_sources(sources);
|
|
165
|
+
let mut r = LazyCsvReader::new_with_sources(sources);
|
|
118
166
|
|
|
119
|
-
let
|
|
167
|
+
if let Some(first_path) = first_path {
|
|
168
|
+
let first_path_url = first_path.as_str();
|
|
169
|
+
let cloud_options = cloud_options.extract_opt_cloud_options(
|
|
170
|
+
CloudScheme::from_path(first_path_url),
|
|
171
|
+
credential_provider,
|
|
172
|
+
)?;
|
|
173
|
+
r = r.with_cloud_options(cloud_options);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
let mut r = r
|
|
120
177
|
.with_infer_schema_length(infer_schema_length)
|
|
121
178
|
.with_separator(separator)
|
|
122
179
|
.with_has_header(has_header)
|
|
123
180
|
.with_ignore_errors(ignore_errors)
|
|
124
181
|
.with_skip_rows(skip_rows)
|
|
182
|
+
.with_skip_lines(skip_lines)
|
|
125
183
|
.with_n_rows(n_rows)
|
|
126
184
|
.with_cache(cache)
|
|
127
185
|
.with_dtype_overwrite(overwrite_dtype.map(Arc::new))
|
|
128
|
-
|
|
186
|
+
.with_schema(schema.map(|schema| Arc::new(schema.0)))
|
|
129
187
|
.with_low_memory(low_memory)
|
|
130
188
|
.with_comment_prefix(comment_prefix.map(|x| x.into()))
|
|
131
189
|
.with_quote_char(quote_char)
|
|
@@ -136,182 +194,136 @@ impl RbLazyFrame {
|
|
|
136
194
|
.with_row_index(row_index)
|
|
137
195
|
.with_try_parse_dates(try_parse_dates)
|
|
138
196
|
.with_null_values(null_values)
|
|
139
|
-
|
|
140
|
-
.with_truncate_ragged_lines(truncate_ragged_lines)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
197
|
+
.with_missing_is_null(!missing_utf8_is_empty_string)
|
|
198
|
+
.with_truncate_ragged_lines(truncate_ragged_lines)
|
|
199
|
+
.with_decimal_comma(decimal_comma)
|
|
200
|
+
.with_glob(glob)
|
|
201
|
+
.with_raise_if_empty(raise_if_empty)
|
|
202
|
+
.with_include_file_paths(include_file_paths.map(|x| x.into()))
|
|
203
|
+
.with_missing_columns_policy(missing_columns.map(|x| x.0));
|
|
204
|
+
|
|
205
|
+
if let Some(lambda) = with_schema_modify {
|
|
206
|
+
let f = |schema: Schema| {
|
|
207
|
+
let iter = schema.iter_names().map(|s| s.as_str());
|
|
208
|
+
Ruby::attach(|rb| {
|
|
209
|
+
let names = rb.ary_from_iter(iter);
|
|
210
|
+
|
|
211
|
+
let out = lambda
|
|
212
|
+
.funcall("call", (names,))
|
|
213
|
+
.expect("ruby function failed");
|
|
214
|
+
let new_names = Vec::<String>::try_convert(out)
|
|
215
|
+
.expect("ruby function should return Array[String]");
|
|
216
|
+
polars_ensure!(new_names.len() == schema.len(),
|
|
217
|
+
ShapeMismatch: "The length of the new names list should be equal to or less than the original column length",
|
|
218
|
+
);
|
|
219
|
+
Ok(schema
|
|
220
|
+
.iter_values()
|
|
221
|
+
.zip(new_names)
|
|
222
|
+
.map(|(dtype, name)| Field::new(name.into(), dtype.clone()))
|
|
223
|
+
.collect())
|
|
224
|
+
})
|
|
225
|
+
};
|
|
226
|
+
r = r.with_schema_modify(f).map_err(RbPolarsErr::from)?
|
|
144
227
|
}
|
|
145
228
|
|
|
146
229
|
Ok(r.finish().map_err(RbPolarsErr::from)?.into())
|
|
147
230
|
}
|
|
148
231
|
|
|
149
|
-
pub fn new_from_parquet(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
let cloud_options = Option::<Vec<(String, String)>>::try_convert(arguments[8])?;
|
|
159
|
-
let _credential_provider = Option::<Value>::try_convert(arguments[9])?;
|
|
160
|
-
let use_statistics = bool::try_convert(arguments[10])?;
|
|
161
|
-
let hive_partitioning = Option::<bool>::try_convert(arguments[11])?;
|
|
162
|
-
let schema = Option::<Wrap<Schema>>::try_convert(arguments[12])?;
|
|
163
|
-
let hive_schema = Option::<Wrap<Schema>>::try_convert(arguments[13])?;
|
|
164
|
-
let try_parse_hive_dates = bool::try_convert(arguments[14])?;
|
|
165
|
-
let retries = usize::try_convert(arguments[15])?;
|
|
166
|
-
let glob = bool::try_convert(arguments[16])?;
|
|
167
|
-
let include_file_paths = Option::<String>::try_convert(arguments[17])?;
|
|
168
|
-
let allow_missing_columns = bool::try_convert(arguments[18])?;
|
|
232
|
+
pub fn new_from_parquet(
|
|
233
|
+
sources: Wrap<ScanSources>,
|
|
234
|
+
schema: Option<Wrap<Schema>>,
|
|
235
|
+
scan_options: RbScanOptions,
|
|
236
|
+
parallel: Wrap<ParallelStrategy>,
|
|
237
|
+
low_memory: bool,
|
|
238
|
+
use_statistics: bool,
|
|
239
|
+
) -> RbResult<Self> {
|
|
240
|
+
use crate::utils::to_rb_err;
|
|
169
241
|
|
|
170
242
|
let parallel = parallel.0;
|
|
171
|
-
let hive_schema = hive_schema.map(|s| Arc::new(s.0));
|
|
172
|
-
|
|
173
|
-
let row_index = row_index.map(|(name, offset)| RowIndex {
|
|
174
|
-
name: name.into(),
|
|
175
|
-
offset,
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
let hive_options = HiveOptions {
|
|
179
|
-
enabled: hive_partitioning,
|
|
180
|
-
hive_start_idx: 0,
|
|
181
|
-
schema: hive_schema,
|
|
182
|
-
try_parse_dates: try_parse_hive_dates,
|
|
183
|
-
};
|
|
184
243
|
|
|
185
|
-
let
|
|
186
|
-
|
|
187
|
-
cache,
|
|
244
|
+
let options = ParquetOptions {
|
|
245
|
+
schema: schema.map(|x| Arc::new(x.0)),
|
|
188
246
|
parallel,
|
|
189
|
-
rechunk,
|
|
190
|
-
row_index,
|
|
191
247
|
low_memory,
|
|
192
|
-
cloud_options: None,
|
|
193
248
|
use_statistics,
|
|
194
|
-
schema: schema.map(|x| Arc::new(x.0)),
|
|
195
|
-
hive_options,
|
|
196
|
-
glob,
|
|
197
|
-
include_file_paths: include_file_paths.map(|x| x.into()),
|
|
198
|
-
allow_missing_columns,
|
|
199
249
|
};
|
|
200
250
|
|
|
201
251
|
let sources = sources.0;
|
|
202
|
-
let
|
|
203
|
-
None => (sources.first_path().map(|p| p.to_path_buf()), sources),
|
|
204
|
-
Some(source) => rbobject_to_first_path_and_scan_sources(source)?,
|
|
205
|
-
};
|
|
252
|
+
let first_path = sources.first_path();
|
|
206
253
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
let cloud_options =
|
|
210
|
-
parse_cloud_options(&first_path_url, cloud_options.unwrap_or_default())?;
|
|
211
|
-
args.cloud_options = Some(cloud_options.with_max_retries(retries));
|
|
212
|
-
}
|
|
254
|
+
let unified_scan_args =
|
|
255
|
+
scan_options.extract_unified_scan_args(first_path.and_then(|x| x.scheme()))?;
|
|
213
256
|
|
|
214
|
-
let lf =
|
|
257
|
+
let lf: LazyFrame = DslBuilder::scan_parquet(sources, options, unified_scan_args)
|
|
258
|
+
.map_err(to_rb_err)?
|
|
259
|
+
.build()
|
|
260
|
+
.into();
|
|
215
261
|
|
|
216
262
|
Ok(lf.into())
|
|
217
263
|
}
|
|
218
264
|
|
|
219
|
-
#[allow(clippy::too_many_arguments)]
|
|
220
265
|
pub fn new_from_ipc(
|
|
221
|
-
source: Option<Value>,
|
|
222
266
|
sources: Wrap<ScanSources>,
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
rechunk: bool,
|
|
226
|
-
row_index: Option<(String, IdxSize)>,
|
|
227
|
-
hive_partitioning: Option<bool>,
|
|
228
|
-
hive_schema: Option<Wrap<Schema>>,
|
|
229
|
-
try_parse_hive_dates: bool,
|
|
230
|
-
include_file_paths: Option<String>,
|
|
267
|
+
record_batch_statistics: bool,
|
|
268
|
+
scan_options: RbScanOptions,
|
|
231
269
|
) -> RbResult<Self> {
|
|
232
|
-
let
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
let hive_options = HiveOptions {
|
|
238
|
-
enabled: hive_partitioning,
|
|
239
|
-
hive_start_idx: 0,
|
|
240
|
-
schema: hive_schema.map(|x| Arc::new(x.0)),
|
|
241
|
-
try_parse_dates: try_parse_hive_dates,
|
|
270
|
+
let options = IpcScanOptions {
|
|
271
|
+
record_batch_statistics,
|
|
272
|
+
checked: Default::default(),
|
|
242
273
|
};
|
|
243
274
|
|
|
244
|
-
let
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
275
|
+
let sources = sources.0;
|
|
276
|
+
let first_path = sources.first_path().cloned();
|
|
277
|
+
|
|
278
|
+
let unified_scan_args =
|
|
279
|
+
scan_options.extract_unified_scan_args(first_path.as_ref().and_then(|x| x.scheme()))?;
|
|
280
|
+
|
|
281
|
+
let lf = LazyFrame::scan_ipc_sources(sources, options, unified_scan_args)
|
|
282
|
+
.map_err(RbPolarsErr::from)?;
|
|
283
|
+
Ok(lf.into())
|
|
284
|
+
}
|
|
253
285
|
|
|
286
|
+
pub fn new_from_scan_lines(
|
|
287
|
+
sources: Wrap<ScanSources>,
|
|
288
|
+
scan_options: RbScanOptions,
|
|
289
|
+
name: String,
|
|
290
|
+
) -> RbResult<Self> {
|
|
254
291
|
let sources = sources.0;
|
|
255
|
-
let
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
292
|
+
let first_path = sources.first_path();
|
|
293
|
+
|
|
294
|
+
let unified_scan_args =
|
|
295
|
+
scan_options.extract_unified_scan_args(first_path.and_then(|x| x.scheme()))?;
|
|
296
|
+
|
|
297
|
+
let dsl: DslPlan = DslBuilder::scan_lines(sources, unified_scan_args, (&*name).into())
|
|
298
|
+
.map_err(to_rb_err)?
|
|
299
|
+
.build();
|
|
300
|
+
let lf: LazyFrame = dsl.into();
|
|
259
301
|
|
|
260
|
-
let lf = LazyFrame::scan_ipc_sources(sources, args).map_err(RbPolarsErr::from)?;
|
|
261
302
|
Ok(lf.into())
|
|
262
303
|
}
|
|
263
304
|
|
|
264
|
-
pub fn
|
|
265
|
-
|
|
266
|
-
serde_json::to_writer(file, &self.ldf.borrow().logical_plan)
|
|
267
|
-
.map_err(|err| RbValueError::new_err(format!("{:?}", err)))?;
|
|
268
|
-
Ok(())
|
|
305
|
+
pub fn describe_plan(rb: &Ruby, self_: &Self) -> RbResult<String> {
|
|
306
|
+
rb.enter_polars(|| self_.ldf.read().describe_plan())
|
|
269
307
|
}
|
|
270
308
|
|
|
271
|
-
pub fn
|
|
272
|
-
|
|
273
|
-
.borrow()
|
|
274
|
-
.describe_plan()
|
|
275
|
-
.map_err(RbPolarsErr::from)
|
|
276
|
-
.map_err(Into::into)
|
|
309
|
+
pub fn describe_optimized_plan(rb: &Ruby, self_: &Self) -> RbResult<String> {
|
|
310
|
+
rb.enter_polars(|| self_.ldf.read().describe_optimized_plan())
|
|
277
311
|
}
|
|
278
312
|
|
|
279
|
-
pub fn
|
|
280
|
-
|
|
281
|
-
.ldf
|
|
282
|
-
.borrow()
|
|
283
|
-
.describe_optimized_plan()
|
|
284
|
-
.map_err(RbPolarsErr::from)?;
|
|
285
|
-
Ok(result)
|
|
313
|
+
pub fn describe_plan_tree(rb: &Ruby, self_: &Self) -> RbResult<String> {
|
|
314
|
+
rb.enter_polars(|| self_.ldf.read().describe_plan_tree())
|
|
286
315
|
}
|
|
287
316
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
allow_streaming: bool,
|
|
299
|
-
_eager: bool,
|
|
300
|
-
) -> RbLazyFrame {
|
|
301
|
-
let ldf = self.ldf.borrow().clone();
|
|
302
|
-
let mut ldf = ldf
|
|
303
|
-
.with_type_coercion(type_coercion)
|
|
304
|
-
.with_predicate_pushdown(predicate_pushdown)
|
|
305
|
-
.with_simplify_expr(simplify_expr)
|
|
306
|
-
.with_slice_pushdown(slice_pushdown)
|
|
307
|
-
.with_streaming(allow_streaming)
|
|
308
|
-
._with_eager(_eager)
|
|
309
|
-
.with_projection_pushdown(projection_pushdown);
|
|
310
|
-
|
|
311
|
-
ldf = ldf.with_comm_subplan_elim(comm_subplan_elim);
|
|
312
|
-
ldf = ldf.with_comm_subexpr_elim(comm_subexpr_elim);
|
|
313
|
-
|
|
314
|
-
ldf.into()
|
|
317
|
+
pub fn describe_optimized_plan_tree(rb: &Ruby, self_: &Self) -> RbResult<String> {
|
|
318
|
+
rb.enter_polars(|| self_.ldf.read().describe_optimized_plan_tree())
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
pub fn to_dot(rb: &Ruby, self_: &Self, optimized: bool) -> RbResult<String> {
|
|
322
|
+
rb.enter_polars(|| self_.ldf.read().to_dot(optimized))
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
pub fn to_dot_streaming_phys(rb: &Ruby, self_: &Self, optimized: bool) -> RbResult<String> {
|
|
326
|
+
rb.enter_polars(|| self_.ldf.read().to_dot_streaming_phys(optimized))
|
|
315
327
|
}
|
|
316
328
|
|
|
317
329
|
pub fn sort(
|
|
@@ -322,7 +334,7 @@ impl RbLazyFrame {
|
|
|
322
334
|
maintain_order: bool,
|
|
323
335
|
multithreaded: bool,
|
|
324
336
|
) -> Self {
|
|
325
|
-
let ldf = self.ldf.
|
|
337
|
+
let ldf = self.ldf.read().clone();
|
|
326
338
|
ldf.sort(
|
|
327
339
|
[&by_column],
|
|
328
340
|
SortMultipleOptions {
|
|
@@ -330,6 +342,7 @@ impl RbLazyFrame {
|
|
|
330
342
|
nulls_last: vec![nulls_last],
|
|
331
343
|
multithreaded,
|
|
332
344
|
maintain_order,
|
|
345
|
+
limit: None,
|
|
333
346
|
},
|
|
334
347
|
)
|
|
335
348
|
.into()
|
|
@@ -343,8 +356,8 @@ impl RbLazyFrame {
|
|
|
343
356
|
maintain_order: bool,
|
|
344
357
|
multithreaded: bool,
|
|
345
358
|
) -> RbResult<Self> {
|
|
346
|
-
let ldf = self.ldf.
|
|
347
|
-
let exprs =
|
|
359
|
+
let ldf = self.ldf.read().clone();
|
|
360
|
+
let exprs = by.to_exprs()?;
|
|
348
361
|
Ok(ldf
|
|
349
362
|
.sort_by_exprs(
|
|
350
363
|
exprs,
|
|
@@ -353,33 +366,101 @@ impl RbLazyFrame {
|
|
|
353
366
|
nulls_last,
|
|
354
367
|
maintain_order,
|
|
355
368
|
multithreaded,
|
|
369
|
+
limit: None,
|
|
356
370
|
},
|
|
357
371
|
)
|
|
358
372
|
.into())
|
|
359
373
|
}
|
|
360
374
|
|
|
375
|
+
pub fn top_k(&self, k: IdxSize, by: RArray, reverse: Vec<bool>) -> RbResult<Self> {
|
|
376
|
+
let ldf = self.ldf.read().clone();
|
|
377
|
+
let exprs = by.to_exprs()?;
|
|
378
|
+
Ok(ldf
|
|
379
|
+
.top_k(
|
|
380
|
+
k,
|
|
381
|
+
exprs,
|
|
382
|
+
SortMultipleOptions::new().with_order_descending_multi(reverse),
|
|
383
|
+
)
|
|
384
|
+
.into())
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
pub fn bottom_k(&self, k: IdxSize, by: RArray, reverse: Vec<bool>) -> RbResult<Self> {
|
|
388
|
+
let ldf = self.ldf.read().clone();
|
|
389
|
+
let exprs = by.to_exprs()?;
|
|
390
|
+
Ok(ldf
|
|
391
|
+
.bottom_k(
|
|
392
|
+
k,
|
|
393
|
+
exprs,
|
|
394
|
+
SortMultipleOptions::new().with_order_descending_multi(reverse),
|
|
395
|
+
)
|
|
396
|
+
.into())
|
|
397
|
+
}
|
|
398
|
+
|
|
361
399
|
pub fn cache(&self) -> Self {
|
|
362
|
-
let ldf = self.ldf.
|
|
400
|
+
let ldf = self.ldf.read().clone();
|
|
363
401
|
ldf.cache().into()
|
|
364
402
|
}
|
|
365
403
|
|
|
366
|
-
pub fn
|
|
367
|
-
let ldf = self.ldf.
|
|
368
|
-
|
|
369
|
-
|
|
404
|
+
pub fn with_optimizations(&self, optflags: &RbOptFlags) -> Self {
|
|
405
|
+
let ldf = self.ldf.read().clone();
|
|
406
|
+
ldf.with_optimizations(optflags.clone().inner.into_inner())
|
|
407
|
+
.into()
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
pub fn profile(rb: &Ruby, self_: &Self) -> RbResult<(RbDataFrame, RbDataFrame)> {
|
|
411
|
+
let (df, time_df) = rb.enter_polars(|| {
|
|
412
|
+
let ldf = self_.ldf.read().clone();
|
|
413
|
+
ldf.profile()
|
|
414
|
+
})?;
|
|
415
|
+
Ok((df.into(), time_df.into()))
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
pub fn collect(rb: &Ruby, self_: &Self, engine: Wrap<Engine>) -> RbResult<RbDataFrame> {
|
|
419
|
+
rb.enter_polars_df(|| {
|
|
420
|
+
let ldf = self_.ldf.read().clone();
|
|
421
|
+
ldf.collect_with_engine(engine.0).map(|r| match r {
|
|
422
|
+
QueryResult::Single(df) => df,
|
|
423
|
+
// TODO: Should return query results
|
|
424
|
+
QueryResult::Multiple(_) => DataFrame::empty(),
|
|
425
|
+
})
|
|
426
|
+
})
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
pub fn collect_batches(
|
|
430
|
+
rb: &Ruby,
|
|
431
|
+
self_: &Self,
|
|
432
|
+
engine: Wrap<Engine>,
|
|
433
|
+
maintain_order: bool,
|
|
434
|
+
chunk_size: Option<NonZeroUsize>,
|
|
435
|
+
lazy: bool,
|
|
436
|
+
) -> RbResult<RbCollectBatches> {
|
|
437
|
+
rb.enter_polars(|| {
|
|
438
|
+
let ldf = self_.ldf.read().clone();
|
|
439
|
+
|
|
440
|
+
let collect_batches =
|
|
441
|
+
ldf.clone()
|
|
442
|
+
.collect_batches(engine.0, maintain_order, chunk_size, lazy)?;
|
|
443
|
+
|
|
444
|
+
PolarsResult::Ok(RbCollectBatches {
|
|
445
|
+
inner: Arc::new(Mutex::new(collect_batches)),
|
|
446
|
+
ldf,
|
|
447
|
+
})
|
|
448
|
+
})
|
|
370
449
|
}
|
|
371
450
|
|
|
372
|
-
#[allow(clippy::too_many_arguments)]
|
|
373
451
|
pub fn sink_parquet(
|
|
374
|
-
&
|
|
375
|
-
|
|
452
|
+
rb: &Ruby,
|
|
453
|
+
self_: &Self,
|
|
454
|
+
target: RbFileSinkDestination,
|
|
455
|
+
sink_options: RbSinkOptions,
|
|
376
456
|
compression: String,
|
|
377
457
|
compression_level: Option<i32>,
|
|
378
458
|
statistics: Wrap<StatisticsOptions>,
|
|
379
459
|
row_group_size: Option<usize>,
|
|
380
460
|
data_page_size: Option<usize>,
|
|
381
|
-
|
|
382
|
-
|
|
461
|
+
metadata: Wrap<Option<KeyValueMetadata>>,
|
|
462
|
+
arrow_schema: Option<Wrap<ArrowSchema>>,
|
|
463
|
+
) -> RbResult<RbLazyFrame> {
|
|
383
464
|
let compression = parse_parquet_compression(&compression, compression_level)?;
|
|
384
465
|
|
|
385
466
|
let options = ParquetWriteOptions {
|
|
@@ -387,120 +468,190 @@ impl RbLazyFrame {
|
|
|
387
468
|
statistics: statistics.0,
|
|
388
469
|
row_group_size,
|
|
389
470
|
data_page_size,
|
|
390
|
-
|
|
471
|
+
key_value_metadata: metadata.0,
|
|
472
|
+
arrow_schema: arrow_schema.map(|x| Arc::new(x.0)),
|
|
473
|
+
compat_level: None,
|
|
391
474
|
};
|
|
392
475
|
|
|
393
|
-
let
|
|
394
|
-
|
|
395
|
-
|
|
476
|
+
let target = target.extract_file_sink_destination()?;
|
|
477
|
+
let unified_sink_args = sink_options.extract_unified_sink_args(target.cloud_scheme())?;
|
|
478
|
+
|
|
479
|
+
rb.enter_polars(|| {
|
|
480
|
+
self_.ldf.read().clone().sink(
|
|
481
|
+
target,
|
|
482
|
+
FileWriteFormat::Parquet(Arc::new(options)),
|
|
483
|
+
unified_sink_args,
|
|
484
|
+
)
|
|
485
|
+
})
|
|
486
|
+
.map(Into::into)
|
|
396
487
|
}
|
|
397
488
|
|
|
398
489
|
pub fn sink_ipc(
|
|
399
|
-
&
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
490
|
+
rb: &Ruby,
|
|
491
|
+
self_: &Self,
|
|
492
|
+
target: RbFileSinkDestination,
|
|
493
|
+
sink_options: RbSinkOptions,
|
|
494
|
+
compression: Wrap<Option<IpcCompression>>,
|
|
495
|
+
compat_level: RbCompatLevel,
|
|
496
|
+
record_batch_size: Option<usize>,
|
|
497
|
+
record_batch_statistics: bool,
|
|
498
|
+
) -> RbResult<RbLazyFrame> {
|
|
404
499
|
let options = IpcWriterOptions {
|
|
405
|
-
compression: compression.
|
|
406
|
-
|
|
500
|
+
compression: compression.0,
|
|
501
|
+
compat_level: compat_level.0,
|
|
502
|
+
record_batch_size,
|
|
503
|
+
record_batch_statistics,
|
|
407
504
|
};
|
|
408
505
|
|
|
409
|
-
let
|
|
410
|
-
|
|
411
|
-
|
|
506
|
+
let target = target.extract_file_sink_destination()?;
|
|
507
|
+
let unified_sink_args = sink_options.extract_unified_sink_args(target.cloud_scheme())?;
|
|
508
|
+
|
|
509
|
+
rb.enter_polars(|| {
|
|
510
|
+
self_
|
|
511
|
+
.ldf
|
|
512
|
+
.read()
|
|
513
|
+
.clone()
|
|
514
|
+
.sink(target, FileWriteFormat::Ipc(options), unified_sink_args)
|
|
515
|
+
})
|
|
516
|
+
.map(Into::into)
|
|
412
517
|
}
|
|
413
518
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
519
|
+
pub fn sink_csv(rb: &Ruby, self_: &Self, arguments: &[Value]) -> RbResult<RbLazyFrame> {
|
|
520
|
+
let target = RbFileSinkDestination::try_convert(arguments[0])?;
|
|
521
|
+
let sink_options = RbSinkOptions::try_convert(arguments[1])?;
|
|
522
|
+
let include_bom = bool::try_convert(arguments[2])?;
|
|
523
|
+
let compression = String::try_convert(arguments[3])?;
|
|
524
|
+
let compression_level = Option::<u32>::try_convert(arguments[4])?;
|
|
525
|
+
let check_extension = bool::try_convert(arguments[5])?;
|
|
526
|
+
let include_header = bool::try_convert(arguments[6])?;
|
|
527
|
+
let separator = u8::try_convert(arguments[7])?;
|
|
528
|
+
let line_terminator = Wrap::<PlSmallStr>::try_convert(arguments[8])?;
|
|
529
|
+
let quote_char = u8::try_convert(arguments[9])?;
|
|
530
|
+
let batch_size = NonZeroUsize::try_convert(arguments[10])?;
|
|
531
|
+
let datetime_format = Option::<Wrap<PlSmallStr>>::try_convert(arguments[11])?;
|
|
532
|
+
let date_format = Option::<Wrap<PlSmallStr>>::try_convert(arguments[12])?;
|
|
533
|
+
let time_format = Option::<Wrap<PlSmallStr>>::try_convert(arguments[13])?;
|
|
534
|
+
let float_scientific = Option::<bool>::try_convert(arguments[14])?;
|
|
535
|
+
let float_precision = Option::<usize>::try_convert(arguments[15])?;
|
|
536
|
+
let decimal_comma = bool::try_convert(arguments[16])?;
|
|
537
|
+
let null_value = Option::<Wrap<PlSmallStr>>::try_convert(arguments[17])?;
|
|
538
|
+
let quote_style = Option::<Wrap<QuoteStyle>>::try_convert(arguments[18])?;
|
|
539
|
+
|
|
433
540
|
let quote_style = quote_style.map_or(QuoteStyle::default(), |wrap| wrap.0);
|
|
434
|
-
let null_value = null_value
|
|
541
|
+
let null_value = null_value
|
|
542
|
+
.map(|x| x.0)
|
|
543
|
+
.unwrap_or(SerializeOptions::default().null);
|
|
435
544
|
|
|
436
545
|
let serialize_options = SerializeOptions {
|
|
437
|
-
date_format,
|
|
438
|
-
time_format,
|
|
439
|
-
datetime_format,
|
|
546
|
+
date_format: date_format.map(|x| x.0),
|
|
547
|
+
time_format: time_format.map(|x| x.0),
|
|
548
|
+
datetime_format: datetime_format.map(|x| x.0),
|
|
440
549
|
float_scientific,
|
|
441
550
|
float_precision,
|
|
551
|
+
decimal_comma,
|
|
442
552
|
separator,
|
|
443
553
|
quote_char,
|
|
444
554
|
null: null_value,
|
|
445
|
-
line_terminator,
|
|
555
|
+
line_terminator: line_terminator.0,
|
|
446
556
|
quote_style,
|
|
447
557
|
};
|
|
448
558
|
|
|
449
559
|
let options = CsvWriterOptions {
|
|
450
560
|
include_bom,
|
|
561
|
+
compression: ExternalCompression::try_from(&compression, compression_level)
|
|
562
|
+
.map_err(RbPolarsErr::from)?,
|
|
563
|
+
check_extension,
|
|
451
564
|
include_header,
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
serialize_options,
|
|
565
|
+
batch_size,
|
|
566
|
+
serialize_options: serialize_options.into(),
|
|
455
567
|
};
|
|
456
568
|
|
|
457
|
-
let
|
|
458
|
-
|
|
459
|
-
|
|
569
|
+
let target = target.extract_file_sink_destination()?;
|
|
570
|
+
let unified_sink_args = sink_options.extract_unified_sink_args(target.cloud_scheme())?;
|
|
571
|
+
|
|
572
|
+
rb.enter_polars(|| {
|
|
573
|
+
self_
|
|
574
|
+
.ldf
|
|
575
|
+
.read()
|
|
576
|
+
.clone()
|
|
577
|
+
.sink(target, FileWriteFormat::Csv(options), unified_sink_args)
|
|
578
|
+
})
|
|
579
|
+
.map(Into::into)
|
|
460
580
|
}
|
|
461
581
|
|
|
462
|
-
pub fn
|
|
463
|
-
|
|
582
|
+
pub fn sink_ndjson(
|
|
583
|
+
rb: &Ruby,
|
|
584
|
+
self_: &Self,
|
|
585
|
+
target: RbFileSinkDestination,
|
|
586
|
+
compression: String,
|
|
587
|
+
compression_level: Option<u32>,
|
|
588
|
+
check_extension: bool,
|
|
589
|
+
sink_options: RbSinkOptions,
|
|
590
|
+
) -> RbResult<RbLazyFrame> {
|
|
591
|
+
let options = NDJsonWriterOptions {
|
|
592
|
+
compression: ExternalCompression::try_from(&compression, compression_level)
|
|
593
|
+
.map_err(RbPolarsErr::from)?,
|
|
594
|
+
check_extension,
|
|
595
|
+
};
|
|
464
596
|
|
|
465
|
-
let
|
|
466
|
-
|
|
467
|
-
|
|
597
|
+
let target = target.extract_file_sink_destination()?;
|
|
598
|
+
let unified_sink_args = sink_options.extract_unified_sink_args(target.cloud_scheme())?;
|
|
599
|
+
|
|
600
|
+
rb.enter_polars(|| {
|
|
601
|
+
self_.ldf.read().clone().sink(
|
|
602
|
+
target,
|
|
603
|
+
FileWriteFormat::NDJson(options),
|
|
604
|
+
unified_sink_args,
|
|
605
|
+
)
|
|
606
|
+
})
|
|
607
|
+
.map(Into::into)
|
|
468
608
|
}
|
|
469
609
|
|
|
470
|
-
pub fn
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
610
|
+
pub fn sink_batches(
|
|
611
|
+
rb: &Ruby,
|
|
612
|
+
self_: &Self,
|
|
613
|
+
function: Value,
|
|
614
|
+
maintain_order: bool,
|
|
615
|
+
chunk_size: Option<NonZeroUsize>,
|
|
616
|
+
) -> RbResult<RbLazyFrame> {
|
|
617
|
+
let ldf = self_.ldf.read().clone();
|
|
618
|
+
// ensure new_ruby is called with GVL
|
|
619
|
+
let callback = PlanCallback::new_ruby(RubyObject::from(function));
|
|
620
|
+
rb.enter_polars(|| ldf.sink_batches(callback, maintain_order, chunk_size))
|
|
621
|
+
.map(Into::into)
|
|
474
622
|
}
|
|
475
623
|
|
|
476
624
|
pub fn filter(&self, predicate: &RbExpr) -> Self {
|
|
477
|
-
let ldf = self.ldf.
|
|
625
|
+
let ldf = self.ldf.read().clone();
|
|
478
626
|
ldf.filter(predicate.inner.clone()).into()
|
|
479
627
|
}
|
|
480
628
|
|
|
629
|
+
pub fn remove(&self, predicate: &RbExpr) -> Self {
|
|
630
|
+
let ldf = self.ldf.read().clone();
|
|
631
|
+
ldf.remove(predicate.inner.clone()).into()
|
|
632
|
+
}
|
|
633
|
+
|
|
481
634
|
pub fn select(&self, exprs: RArray) -> RbResult<Self> {
|
|
482
|
-
let ldf = self.ldf.
|
|
483
|
-
let exprs =
|
|
635
|
+
let ldf = self.ldf.read().clone();
|
|
636
|
+
let exprs = exprs.to_exprs()?;
|
|
484
637
|
Ok(ldf.select(exprs).into())
|
|
485
638
|
}
|
|
486
639
|
|
|
487
640
|
pub fn select_seq(&self, exprs: RArray) -> RbResult<Self> {
|
|
488
|
-
let ldf = self.ldf.
|
|
489
|
-
let exprs =
|
|
641
|
+
let ldf = self.ldf.read().clone();
|
|
642
|
+
let exprs = exprs.to_exprs()?;
|
|
490
643
|
Ok(ldf.select_seq(exprs).into())
|
|
491
644
|
}
|
|
492
645
|
|
|
493
646
|
pub fn group_by(&self, by: RArray, maintain_order: bool) -> RbResult<RbLazyGroupBy> {
|
|
494
|
-
let ldf = self.ldf.
|
|
495
|
-
let by =
|
|
647
|
+
let ldf = self.ldf.read().clone();
|
|
648
|
+
let by = by.to_exprs()?;
|
|
496
649
|
let lazy_gb = if maintain_order {
|
|
497
650
|
ldf.group_by_stable(by)
|
|
498
651
|
} else {
|
|
499
652
|
ldf.group_by(by)
|
|
500
653
|
};
|
|
501
|
-
Ok(RbLazyGroupBy {
|
|
502
|
-
lgb: RefCell::new(Some(lazy_gb)),
|
|
503
|
-
})
|
|
654
|
+
Ok(RbLazyGroupBy { lgb: Some(lazy_gb) })
|
|
504
655
|
}
|
|
505
656
|
|
|
506
657
|
pub fn rolling(
|
|
@@ -512,8 +663,8 @@ impl RbLazyFrame {
|
|
|
512
663
|
by: RArray,
|
|
513
664
|
) -> RbResult<RbLazyGroupBy> {
|
|
514
665
|
let closed_window = closed.0;
|
|
515
|
-
let ldf = self.ldf.
|
|
516
|
-
let by =
|
|
666
|
+
let ldf = self.ldf.read().clone();
|
|
667
|
+
let by = by.to_exprs()?;
|
|
517
668
|
let lazy_gb = ldf.rolling(
|
|
518
669
|
index_column.inner.clone(),
|
|
519
670
|
by,
|
|
@@ -525,12 +676,9 @@ impl RbLazyFrame {
|
|
|
525
676
|
},
|
|
526
677
|
);
|
|
527
678
|
|
|
528
|
-
Ok(RbLazyGroupBy {
|
|
529
|
-
lgb: RefCell::new(Some(lazy_gb)),
|
|
530
|
-
})
|
|
679
|
+
Ok(RbLazyGroupBy { lgb: Some(lazy_gb) })
|
|
531
680
|
}
|
|
532
681
|
|
|
533
|
-
#[allow(clippy::too_many_arguments)]
|
|
534
682
|
pub fn group_by_dynamic(
|
|
535
683
|
&self,
|
|
536
684
|
index_column: &RbExpr,
|
|
@@ -544,8 +692,8 @@ impl RbLazyFrame {
|
|
|
544
692
|
start_by: Wrap<StartBy>,
|
|
545
693
|
) -> RbResult<RbLazyGroupBy> {
|
|
546
694
|
let closed_window = closed.0;
|
|
547
|
-
let by =
|
|
548
|
-
let ldf = self.ldf.
|
|
695
|
+
let by = by.to_exprs()?;
|
|
696
|
+
let ldf = self.ldf.read().clone();
|
|
549
697
|
let lazy_gb = ldf.group_by_dynamic(
|
|
550
698
|
index_column.inner.clone(),
|
|
551
699
|
by,
|
|
@@ -561,21 +709,9 @@ impl RbLazyFrame {
|
|
|
561
709
|
},
|
|
562
710
|
);
|
|
563
711
|
|
|
564
|
-
Ok(RbLazyGroupBy {
|
|
565
|
-
lgb: RefCell::new(Some(lazy_gb)),
|
|
566
|
-
})
|
|
712
|
+
Ok(RbLazyGroupBy { lgb: Some(lazy_gb) })
|
|
567
713
|
}
|
|
568
714
|
|
|
569
|
-
pub fn with_context(&self, contexts: RArray) -> RbResult<Self> {
|
|
570
|
-
let contexts = contexts.typecheck::<Obj<RbLazyFrame>>()?;
|
|
571
|
-
let contexts = contexts
|
|
572
|
-
.into_iter()
|
|
573
|
-
.map(|ldf| ldf.ldf.borrow().clone())
|
|
574
|
-
.collect::<Vec<_>>();
|
|
575
|
-
Ok(self.ldf.borrow().clone().with_context(contexts).into())
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
#[allow(clippy::too_many_arguments)]
|
|
579
715
|
pub fn join_asof(
|
|
580
716
|
&self,
|
|
581
717
|
other: &RbLazyFrame,
|
|
@@ -590,14 +726,16 @@ impl RbLazyFrame {
|
|
|
590
726
|
tolerance: Option<Wrap<AnyValue<'_>>>,
|
|
591
727
|
tolerance_str: Option<String>,
|
|
592
728
|
coalesce: bool,
|
|
729
|
+
allow_eq: bool,
|
|
730
|
+
check_sortedness: bool,
|
|
593
731
|
) -> RbResult<Self> {
|
|
594
732
|
let coalesce = if coalesce {
|
|
595
733
|
JoinCoalesce::CoalesceColumns
|
|
596
734
|
} else {
|
|
597
735
|
JoinCoalesce::KeepColumns
|
|
598
736
|
};
|
|
599
|
-
let ldf = self.ldf.
|
|
600
|
-
let other = other.ldf.
|
|
737
|
+
let ldf = self.ldf.read().clone();
|
|
738
|
+
let other = other.ldf.read().clone();
|
|
601
739
|
let left_on = left_on.inner.clone();
|
|
602
740
|
let right_on = right_on.inner.clone();
|
|
603
741
|
Ok(ldf
|
|
@@ -608,19 +746,24 @@ impl RbLazyFrame {
|
|
|
608
746
|
.allow_parallel(allow_parallel)
|
|
609
747
|
.force_parallel(force_parallel)
|
|
610
748
|
.coalesce(coalesce)
|
|
611
|
-
.how(JoinType::AsOf(AsOfOptions {
|
|
749
|
+
.how(JoinType::AsOf(Box::new(AsOfOptions {
|
|
612
750
|
strategy: strategy.0,
|
|
613
751
|
left_by: left_by.map(strings_to_pl_smallstr),
|
|
614
752
|
right_by: right_by.map(strings_to_pl_smallstr),
|
|
615
|
-
tolerance: tolerance.map(|t|
|
|
753
|
+
tolerance: tolerance.map(|t| {
|
|
754
|
+
let av = t.0.into_static();
|
|
755
|
+
let dtype = av.dtype();
|
|
756
|
+
Scalar::new(dtype, av)
|
|
757
|
+
}),
|
|
616
758
|
tolerance_str: tolerance_str.map(|s| s.into()),
|
|
617
|
-
|
|
759
|
+
allow_eq,
|
|
760
|
+
check_sortedness,
|
|
761
|
+
})))
|
|
618
762
|
.suffix(suffix)
|
|
619
763
|
.finish()
|
|
620
764
|
.into())
|
|
621
765
|
}
|
|
622
766
|
|
|
623
|
-
#[allow(clippy::too_many_arguments)]
|
|
624
767
|
pub fn join(
|
|
625
768
|
&self,
|
|
626
769
|
other: &RbLazyFrame,
|
|
@@ -632,6 +775,7 @@ impl RbLazyFrame {
|
|
|
632
775
|
how: Wrap<JoinType>,
|
|
633
776
|
suffix: String,
|
|
634
777
|
validate: Wrap<JoinValidation>,
|
|
778
|
+
maintain_order: Wrap<MaintainOrderJoin>,
|
|
635
779
|
coalesce: Option<bool>,
|
|
636
780
|
) -> RbResult<Self> {
|
|
637
781
|
let coalesce = match coalesce {
|
|
@@ -639,10 +783,10 @@ impl RbLazyFrame {
|
|
|
639
783
|
Some(true) => JoinCoalesce::CoalesceColumns,
|
|
640
784
|
Some(false) => JoinCoalesce::KeepColumns,
|
|
641
785
|
};
|
|
642
|
-
let ldf = self.ldf.
|
|
643
|
-
let other = other.ldf.
|
|
644
|
-
let left_on =
|
|
645
|
-
let right_on =
|
|
786
|
+
let ldf = self.ldf.read().clone();
|
|
787
|
+
let other = other.ldf.read().clone();
|
|
788
|
+
let left_on = left_on.to_exprs()?;
|
|
789
|
+
let right_on = right_on.to_exprs()?;
|
|
646
790
|
|
|
647
791
|
Ok(ldf
|
|
648
792
|
.join_builder()
|
|
@@ -655,38 +799,180 @@ impl RbLazyFrame {
|
|
|
655
799
|
.how(how.0)
|
|
656
800
|
.validate(validate.0)
|
|
657
801
|
.coalesce(coalesce)
|
|
802
|
+
.maintain_order(maintain_order.0)
|
|
658
803
|
.suffix(suffix)
|
|
659
804
|
.finish()
|
|
660
805
|
.into())
|
|
661
806
|
}
|
|
662
807
|
|
|
808
|
+
pub fn join_where(&self, other: &Self, predicates: RArray, suffix: String) -> RbResult<Self> {
|
|
809
|
+
let ldf = self.ldf.read().clone();
|
|
810
|
+
let other = other.ldf.read().clone();
|
|
811
|
+
|
|
812
|
+
let predicates = predicates.to_exprs()?;
|
|
813
|
+
|
|
814
|
+
Ok(ldf
|
|
815
|
+
.join_builder()
|
|
816
|
+
.with(other)
|
|
817
|
+
.suffix(suffix)
|
|
818
|
+
.join_where(predicates)
|
|
819
|
+
.into())
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
pub fn gather(&self, idxs: &Self, null_on_oob: bool) -> Self {
|
|
823
|
+
let ldf = self.ldf.read().clone();
|
|
824
|
+
let idxs = idxs.clone().ldf.into_inner();
|
|
825
|
+
ldf.gather(idxs, null_on_oob).into()
|
|
826
|
+
}
|
|
827
|
+
|
|
663
828
|
pub fn with_column(&self, expr: &RbExpr) -> Self {
|
|
664
|
-
let ldf = self.ldf.
|
|
829
|
+
let ldf = self.ldf.read().clone();
|
|
665
830
|
ldf.with_column(expr.inner.clone()).into()
|
|
666
831
|
}
|
|
667
832
|
|
|
668
833
|
pub fn with_columns(&self, exprs: RArray) -> RbResult<Self> {
|
|
669
|
-
let ldf = self.ldf.
|
|
670
|
-
Ok(ldf.with_columns(
|
|
834
|
+
let ldf = self.ldf.read().clone();
|
|
835
|
+
Ok(ldf.with_columns(exprs.to_exprs()?).into())
|
|
671
836
|
}
|
|
672
837
|
|
|
673
838
|
pub fn with_columns_seq(&self, exprs: RArray) -> RbResult<Self> {
|
|
674
|
-
let ldf = self.ldf.
|
|
675
|
-
Ok(ldf.with_columns_seq(
|
|
839
|
+
let ldf = self.ldf.read().clone();
|
|
840
|
+
Ok(ldf.with_columns_seq(exprs.to_exprs()?).into())
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
pub fn match_to_schema(
|
|
844
|
+
&self,
|
|
845
|
+
schema: Wrap<Schema>,
|
|
846
|
+
missing_columns: Value,
|
|
847
|
+
missing_struct_fields: Value,
|
|
848
|
+
extra_columns: Wrap<ExtraColumnsPolicy>,
|
|
849
|
+
extra_struct_fields: Value,
|
|
850
|
+
integer_cast: Value,
|
|
851
|
+
float_cast: Value,
|
|
852
|
+
) -> RbResult<Self> {
|
|
853
|
+
fn parse_missing_columns(
|
|
854
|
+
schema: &Schema,
|
|
855
|
+
missing_columns: Value,
|
|
856
|
+
) -> RbResult<Vec<MissingColumnsPolicyOrExpr>> {
|
|
857
|
+
let mut out = Vec::with_capacity(schema.len());
|
|
858
|
+
if let Ok(policy) = Wrap::<MissingColumnsPolicyOrExpr>::try_convert(missing_columns) {
|
|
859
|
+
out.extend(std::iter::repeat_n(policy.0, schema.len()));
|
|
860
|
+
} else if let Ok(dict) = RHash::try_convert(missing_columns) {
|
|
861
|
+
out.extend(std::iter::repeat_n(
|
|
862
|
+
MissingColumnsPolicyOrExpr::Raise,
|
|
863
|
+
schema.len(),
|
|
864
|
+
));
|
|
865
|
+
dict.foreach(|key: String, value: Wrap<MissingColumnsPolicyOrExpr>| {
|
|
866
|
+
out[schema.try_index_of(&key).map_err(to_rb_err)?] = value.0;
|
|
867
|
+
Ok(ForEach::Continue)
|
|
868
|
+
})?;
|
|
869
|
+
} else {
|
|
870
|
+
return Err(RbTypeError::new_err("Invalid value for `missing_columns`"));
|
|
871
|
+
}
|
|
872
|
+
Ok(out)
|
|
873
|
+
}
|
|
874
|
+
fn parse_missing_struct_fields(
|
|
875
|
+
schema: &Schema,
|
|
876
|
+
missing_struct_fields: Value,
|
|
877
|
+
) -> RbResult<Vec<MissingColumnsPolicy>> {
|
|
878
|
+
let mut out = Vec::with_capacity(schema.len());
|
|
879
|
+
if let Ok(policy) = Wrap::<MissingColumnsPolicy>::try_convert(missing_struct_fields) {
|
|
880
|
+
out.extend(std::iter::repeat_n(policy.0, schema.len()));
|
|
881
|
+
} else if let Ok(dict) = RHash::try_convert(missing_struct_fields) {
|
|
882
|
+
out.extend(std::iter::repeat_n(
|
|
883
|
+
MissingColumnsPolicy::Raise,
|
|
884
|
+
schema.len(),
|
|
885
|
+
));
|
|
886
|
+
dict.foreach(|key: String, value: Wrap<MissingColumnsPolicy>| {
|
|
887
|
+
out[schema.try_index_of(&key).map_err(to_rb_err)?] = value.0;
|
|
888
|
+
Ok(ForEach::Continue)
|
|
889
|
+
})?;
|
|
890
|
+
} else {
|
|
891
|
+
return Err(RbTypeError::new_err(
|
|
892
|
+
"Invalid value for `missing_struct_fields`",
|
|
893
|
+
));
|
|
894
|
+
}
|
|
895
|
+
Ok(out)
|
|
896
|
+
}
|
|
897
|
+
fn parse_extra_struct_fields(
|
|
898
|
+
schema: &Schema,
|
|
899
|
+
extra_struct_fields: Value,
|
|
900
|
+
) -> RbResult<Vec<ExtraColumnsPolicy>> {
|
|
901
|
+
let mut out = Vec::with_capacity(schema.len());
|
|
902
|
+
if let Ok(policy) = Wrap::<ExtraColumnsPolicy>::try_convert(extra_struct_fields) {
|
|
903
|
+
out.extend(std::iter::repeat_n(policy.0, schema.len()));
|
|
904
|
+
} else if let Ok(dict) = RHash::try_convert(extra_struct_fields) {
|
|
905
|
+
out.extend(std::iter::repeat_n(ExtraColumnsPolicy::Raise, schema.len()));
|
|
906
|
+
dict.foreach(|key: String, value: Wrap<ExtraColumnsPolicy>| {
|
|
907
|
+
out[schema.try_index_of(&key).map_err(to_rb_err)?] = value.0;
|
|
908
|
+
Ok(ForEach::Continue)
|
|
909
|
+
})?;
|
|
910
|
+
} else {
|
|
911
|
+
return Err(RbTypeError::new_err(
|
|
912
|
+
"Invalid value for `extra_struct_fields`",
|
|
913
|
+
));
|
|
914
|
+
}
|
|
915
|
+
Ok(out)
|
|
916
|
+
}
|
|
917
|
+
fn parse_cast(schema: &Schema, cast: Value) -> RbResult<Vec<UpcastOrForbid>> {
|
|
918
|
+
let mut out = Vec::with_capacity(schema.len());
|
|
919
|
+
if let Ok(policy) = Wrap::<UpcastOrForbid>::try_convert(cast) {
|
|
920
|
+
out.extend(std::iter::repeat_n(policy.0, schema.len()));
|
|
921
|
+
} else if let Ok(dict) = RHash::try_convert(cast) {
|
|
922
|
+
out.extend(std::iter::repeat_n(UpcastOrForbid::Forbid, schema.len()));
|
|
923
|
+
dict.foreach(|key: String, value: Wrap<UpcastOrForbid>| {
|
|
924
|
+
out[schema.try_index_of(&key).map_err(to_rb_err)?] = value.0;
|
|
925
|
+
Ok(ForEach::Continue)
|
|
926
|
+
})?;
|
|
927
|
+
} else {
|
|
928
|
+
return Err(RbTypeError::new_err(
|
|
929
|
+
"Invalid value for `integer_cast` / `float_cast`",
|
|
930
|
+
));
|
|
931
|
+
}
|
|
932
|
+
Ok(out)
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
let missing_columns = parse_missing_columns(&schema.0, missing_columns)?;
|
|
936
|
+
let missing_struct_fields = parse_missing_struct_fields(&schema.0, missing_struct_fields)?;
|
|
937
|
+
let extra_struct_fields = parse_extra_struct_fields(&schema.0, extra_struct_fields)?;
|
|
938
|
+
let integer_cast = parse_cast(&schema.0, integer_cast)?;
|
|
939
|
+
let float_cast = parse_cast(&schema.0, float_cast)?;
|
|
940
|
+
|
|
941
|
+
let per_column = (0..schema.0.len())
|
|
942
|
+
.map(|i| MatchToSchemaPerColumn {
|
|
943
|
+
missing_columns: missing_columns[i].clone(),
|
|
944
|
+
missing_struct_fields: missing_struct_fields[i],
|
|
945
|
+
extra_struct_fields: extra_struct_fields[i],
|
|
946
|
+
integer_cast: integer_cast[i],
|
|
947
|
+
float_cast: float_cast[i],
|
|
948
|
+
})
|
|
949
|
+
.collect();
|
|
950
|
+
|
|
951
|
+
let ldf = self.ldf.read().clone();
|
|
952
|
+
Ok(ldf
|
|
953
|
+
.match_to_schema(Arc::new(schema.0), per_column, extra_columns.0)
|
|
954
|
+
.into())
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
pub fn pipe_with_schema(&self, callback: Value) -> Self {
|
|
958
|
+
let ldf = self.ldf.read().clone();
|
|
959
|
+
let function = RubyObject::from(callback);
|
|
960
|
+
ldf.pipe_with_schema(PlanCallback::new_ruby(function))
|
|
961
|
+
.into()
|
|
676
962
|
}
|
|
677
963
|
|
|
678
964
|
pub fn rename(&self, existing: Vec<String>, new: Vec<String>, strict: bool) -> Self {
|
|
679
|
-
let ldf = self.ldf.
|
|
965
|
+
let ldf = self.ldf.read().clone();
|
|
680
966
|
ldf.rename(existing, new, strict).into()
|
|
681
967
|
}
|
|
682
968
|
|
|
683
969
|
pub fn reverse(&self) -> Self {
|
|
684
|
-
let ldf = self.ldf.
|
|
970
|
+
let ldf = self.ldf.read().clone();
|
|
685
971
|
ldf.reverse().into()
|
|
686
972
|
}
|
|
687
973
|
|
|
688
974
|
pub fn shift(&self, n: &RbExpr, fill_value: Option<&RbExpr>) -> Self {
|
|
689
|
-
let lf = self.ldf.
|
|
975
|
+
let lf = self.ldf.read().clone();
|
|
690
976
|
let out = match fill_value {
|
|
691
977
|
Some(v) => lf.shift_and_fill(n.inner.clone(), v.inner.clone()),
|
|
692
978
|
None => lf.shift(n.inner.clone()),
|
|
@@ -695,76 +981,88 @@ impl RbLazyFrame {
|
|
|
695
981
|
}
|
|
696
982
|
|
|
697
983
|
pub fn fill_nan(&self, fill_value: &RbExpr) -> Self {
|
|
698
|
-
let ldf = self.ldf.
|
|
984
|
+
let ldf = self.ldf.read().clone();
|
|
699
985
|
ldf.fill_nan(fill_value.inner.clone()).into()
|
|
700
986
|
}
|
|
701
987
|
|
|
702
988
|
pub fn min(&self) -> Self {
|
|
703
|
-
let ldf = self.ldf.
|
|
989
|
+
let ldf = self.ldf.read().clone();
|
|
704
990
|
let out = ldf.min();
|
|
705
991
|
out.into()
|
|
706
992
|
}
|
|
707
993
|
|
|
708
994
|
pub fn max(&self) -> Self {
|
|
709
|
-
let ldf = self.ldf.
|
|
995
|
+
let ldf = self.ldf.read().clone();
|
|
710
996
|
let out = ldf.max();
|
|
711
997
|
out.into()
|
|
712
998
|
}
|
|
713
999
|
|
|
714
1000
|
pub fn sum(&self) -> Self {
|
|
715
|
-
let ldf = self.ldf.
|
|
1001
|
+
let ldf = self.ldf.read().clone();
|
|
716
1002
|
let out = ldf.sum();
|
|
717
1003
|
out.into()
|
|
718
1004
|
}
|
|
719
1005
|
|
|
720
1006
|
pub fn mean(&self) -> Self {
|
|
721
|
-
let ldf = self.ldf.
|
|
1007
|
+
let ldf = self.ldf.read().clone();
|
|
722
1008
|
let out = ldf.mean();
|
|
723
1009
|
out.into()
|
|
724
1010
|
}
|
|
725
1011
|
|
|
726
1012
|
pub fn std(&self, ddof: u8) -> Self {
|
|
727
|
-
let ldf = self.ldf.
|
|
1013
|
+
let ldf = self.ldf.read().clone();
|
|
728
1014
|
let out = ldf.std(ddof);
|
|
729
1015
|
out.into()
|
|
730
1016
|
}
|
|
731
1017
|
|
|
732
1018
|
pub fn var(&self, ddof: u8) -> Self {
|
|
733
|
-
let ldf = self.ldf.
|
|
1019
|
+
let ldf = self.ldf.read().clone();
|
|
734
1020
|
let out = ldf.var(ddof);
|
|
735
1021
|
out.into()
|
|
736
1022
|
}
|
|
737
1023
|
|
|
738
1024
|
pub fn median(&self) -> Self {
|
|
739
|
-
let ldf = self.ldf.
|
|
1025
|
+
let ldf = self.ldf.read().clone();
|
|
740
1026
|
let out = ldf.median();
|
|
741
1027
|
out.into()
|
|
742
1028
|
}
|
|
743
1029
|
|
|
744
1030
|
pub fn quantile(&self, quantile: &RbExpr, interpolation: Wrap<QuantileMethod>) -> Self {
|
|
745
|
-
let ldf = self.ldf.
|
|
1031
|
+
let ldf = self.ldf.read().clone();
|
|
746
1032
|
let out = ldf.quantile(quantile.inner.clone(), interpolation.0);
|
|
747
1033
|
out.into()
|
|
748
1034
|
}
|
|
749
1035
|
|
|
750
|
-
pub fn explode(&self,
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
1036
|
+
pub fn explode(&self, subset: &RbSelector, empty_as_null: bool, keep_nulls: bool) -> Self {
|
|
1037
|
+
self.ldf
|
|
1038
|
+
.read()
|
|
1039
|
+
.clone()
|
|
1040
|
+
.explode(
|
|
1041
|
+
subset.inner.clone(),
|
|
1042
|
+
ExplodeOptions {
|
|
1043
|
+
empty_as_null,
|
|
1044
|
+
keep_nulls,
|
|
1045
|
+
},
|
|
1046
|
+
)
|
|
1047
|
+
.into()
|
|
754
1048
|
}
|
|
755
1049
|
|
|
756
1050
|
pub fn null_count(&self) -> Self {
|
|
757
|
-
let ldf = self.ldf.
|
|
1051
|
+
let ldf = self.ldf.read().clone();
|
|
758
1052
|
ldf.null_count().into()
|
|
759
1053
|
}
|
|
760
1054
|
|
|
761
1055
|
pub fn unique(
|
|
762
1056
|
&self,
|
|
763
1057
|
maintain_order: bool,
|
|
764
|
-
subset: Option<
|
|
1058
|
+
subset: Option<RArray>,
|
|
765
1059
|
keep: Wrap<UniqueKeepStrategy>,
|
|
766
1060
|
) -> RbResult<Self> {
|
|
767
|
-
let ldf = self.ldf.
|
|
1061
|
+
let ldf = self.ldf.read().clone();
|
|
1062
|
+
let subset = match subset {
|
|
1063
|
+
Some(e) => Some(e.to_exprs()?),
|
|
1064
|
+
None => None,
|
|
1065
|
+
};
|
|
768
1066
|
Ok(match maintain_order {
|
|
769
1067
|
true => ldf.unique_stable_generic(subset, keep.0),
|
|
770
1068
|
false => ldf.unique_generic(subset, keep.0),
|
|
@@ -772,50 +1070,110 @@ impl RbLazyFrame {
|
|
|
772
1070
|
.into())
|
|
773
1071
|
}
|
|
774
1072
|
|
|
775
|
-
pub fn
|
|
776
|
-
|
|
777
|
-
|
|
1073
|
+
pub fn drop_nans(&self, subset: Option<&RbSelector>) -> Self {
|
|
1074
|
+
self.ldf
|
|
1075
|
+
.read()
|
|
1076
|
+
.clone()
|
|
1077
|
+
.drop_nans(subset.map(|e| e.inner.clone()))
|
|
1078
|
+
.into()
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
pub fn drop_nulls(&self, subset: Option<&RbSelector>) -> Self {
|
|
1082
|
+
self.ldf
|
|
1083
|
+
.read()
|
|
1084
|
+
.clone()
|
|
1085
|
+
.drop_nulls(subset.map(|e| e.inner.clone()))
|
|
778
1086
|
.into()
|
|
779
1087
|
}
|
|
780
1088
|
|
|
781
1089
|
pub fn slice(&self, offset: i64, len: Option<IdxSize>) -> Self {
|
|
782
|
-
let ldf = self.ldf.
|
|
1090
|
+
let ldf = self.ldf.read().clone();
|
|
783
1091
|
ldf.slice(offset, len.unwrap_or(IdxSize::MAX)).into()
|
|
784
1092
|
}
|
|
785
1093
|
|
|
786
1094
|
pub fn tail(&self, n: IdxSize) -> Self {
|
|
787
|
-
let ldf = self.ldf.
|
|
1095
|
+
let ldf = self.ldf.read().clone();
|
|
788
1096
|
ldf.tail(n).into()
|
|
789
1097
|
}
|
|
790
1098
|
|
|
1099
|
+
pub fn pivot(
|
|
1100
|
+
&self,
|
|
1101
|
+
on: &RbSelector,
|
|
1102
|
+
on_columns: &RbDataFrame,
|
|
1103
|
+
index: &RbSelector,
|
|
1104
|
+
values: &RbSelector,
|
|
1105
|
+
agg: &RbExpr,
|
|
1106
|
+
maintain_order: bool,
|
|
1107
|
+
separator: String,
|
|
1108
|
+
column_naming: Wrap<PivotColumnNaming>,
|
|
1109
|
+
) -> Self {
|
|
1110
|
+
let ldf = self.ldf.read().clone();
|
|
1111
|
+
ldf.pivot(
|
|
1112
|
+
on.inner.clone(),
|
|
1113
|
+
Arc::new(on_columns.df.read().clone()),
|
|
1114
|
+
index.inner.clone(),
|
|
1115
|
+
values.inner.clone(),
|
|
1116
|
+
agg.inner.clone(),
|
|
1117
|
+
maintain_order,
|
|
1118
|
+
separator.into(),
|
|
1119
|
+
column_naming.0,
|
|
1120
|
+
)
|
|
1121
|
+
.into()
|
|
1122
|
+
}
|
|
1123
|
+
|
|
791
1124
|
pub fn unpivot(
|
|
792
1125
|
&self,
|
|
793
|
-
on:
|
|
794
|
-
index:
|
|
1126
|
+
on: Option<&RbSelector>,
|
|
1127
|
+
index: &RbSelector,
|
|
795
1128
|
value_name: Option<String>,
|
|
796
1129
|
variable_name: Option<String>,
|
|
797
1130
|
) -> RbResult<Self> {
|
|
798
|
-
let on = rb_exprs_to_exprs(on)?;
|
|
799
|
-
let index = rb_exprs_to_exprs(index)?;
|
|
800
1131
|
let args = UnpivotArgsDSL {
|
|
801
|
-
on: on.
|
|
802
|
-
index: index.
|
|
1132
|
+
on: on.map(|on| on.inner.clone()),
|
|
1133
|
+
index: index.inner.clone(),
|
|
803
1134
|
value_name: value_name.map(|s| s.into()),
|
|
804
1135
|
variable_name: variable_name.map(|s| s.into()),
|
|
805
1136
|
};
|
|
806
1137
|
|
|
807
|
-
let ldf = self.ldf.
|
|
1138
|
+
let ldf = self.ldf.read().clone();
|
|
808
1139
|
Ok(ldf.unpivot(args).into())
|
|
809
1140
|
}
|
|
810
1141
|
|
|
811
1142
|
pub fn with_row_index(&self, name: String, offset: Option<IdxSize>) -> Self {
|
|
812
|
-
let ldf = self.ldf.
|
|
1143
|
+
let ldf = self.ldf.read().clone();
|
|
813
1144
|
ldf.with_row_index(&name, offset).into()
|
|
814
1145
|
}
|
|
815
1146
|
|
|
816
|
-
pub fn
|
|
817
|
-
|
|
818
|
-
|
|
1147
|
+
pub fn map_batches(
|
|
1148
|
+
&self,
|
|
1149
|
+
function: Value,
|
|
1150
|
+
predicate_pushdown: bool,
|
|
1151
|
+
projection_pushdown: bool,
|
|
1152
|
+
slice_pushdown: bool,
|
|
1153
|
+
streamable: bool,
|
|
1154
|
+
schema: Option<Wrap<Schema>>,
|
|
1155
|
+
validate_output: bool,
|
|
1156
|
+
) -> Self {
|
|
1157
|
+
let mut opt = OptFlags::default();
|
|
1158
|
+
opt.set(OptFlags::PREDICATE_PUSHDOWN, predicate_pushdown);
|
|
1159
|
+
opt.set(OptFlags::PROJECTION_PUSHDOWN, projection_pushdown);
|
|
1160
|
+
opt.set(OptFlags::SLICE_PUSHDOWN, slice_pushdown);
|
|
1161
|
+
opt.set(OptFlags::STREAMING, streamable);
|
|
1162
|
+
|
|
1163
|
+
self.ldf
|
|
1164
|
+
.read()
|
|
1165
|
+
.clone()
|
|
1166
|
+
.map_ruby(
|
|
1167
|
+
function.into(),
|
|
1168
|
+
opt,
|
|
1169
|
+
schema.map(|s| Arc::new(s.0)),
|
|
1170
|
+
validate_output,
|
|
1171
|
+
)
|
|
1172
|
+
.into()
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
pub fn drop(&self, columns: &RbSelector) -> Self {
|
|
1176
|
+
self.ldf.read().clone().drop(columns.inner.clone()).into()
|
|
819
1177
|
}
|
|
820
1178
|
|
|
821
1179
|
pub fn cast(&self, rb_dtypes: RHash, strict: bool) -> RbResult<Self> {
|
|
@@ -826,52 +1184,172 @@ impl RbLazyFrame {
|
|
|
826
1184
|
})?;
|
|
827
1185
|
let mut cast_map = PlHashMap::with_capacity(dtypes.len());
|
|
828
1186
|
cast_map.extend(dtypes.iter().map(|(k, v)| (k.as_ref(), v.clone())));
|
|
829
|
-
Ok(self.ldf.
|
|
1187
|
+
Ok(self.ldf.read().clone().cast(cast_map, strict).into())
|
|
830
1188
|
}
|
|
831
1189
|
|
|
832
1190
|
pub fn cast_all(&self, dtype: Wrap<DataType>, strict: bool) -> Self {
|
|
833
|
-
self.ldf.
|
|
1191
|
+
self.ldf.read().clone().cast_all(dtype.0, strict).into()
|
|
834
1192
|
}
|
|
835
1193
|
|
|
836
1194
|
pub fn clone(&self) -> Self {
|
|
837
|
-
self.ldf.
|
|
1195
|
+
self.ldf.read().clone().into()
|
|
838
1196
|
}
|
|
839
1197
|
|
|
840
|
-
pub fn collect_schema(&
|
|
841
|
-
let schema =
|
|
842
|
-
.ldf
|
|
843
|
-
.borrow_mut()
|
|
844
|
-
.collect_schema()
|
|
845
|
-
.map_err(RbPolarsErr::from)?;
|
|
1198
|
+
pub fn collect_schema(rb: &Ruby, self_: &Self) -> RbResult<RHash> {
|
|
1199
|
+
let schema = rb.enter_polars(|| self_.ldf.write().collect_schema())?;
|
|
846
1200
|
|
|
847
|
-
let schema_dict =
|
|
848
|
-
schema.iter_fields()
|
|
849
|
-
schema_dict
|
|
850
|
-
.
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
.unwrap();
|
|
855
|
-
});
|
|
1201
|
+
let schema_dict = rb.hash_new();
|
|
1202
|
+
for fld in schema.iter_fields() {
|
|
1203
|
+
schema_dict.aset(
|
|
1204
|
+
fld.name().to_string(),
|
|
1205
|
+
Wrap(fld.dtype().clone()).try_into_value_with(rb)?,
|
|
1206
|
+
)?;
|
|
1207
|
+
}
|
|
856
1208
|
Ok(schema_dict)
|
|
857
1209
|
}
|
|
858
1210
|
|
|
859
|
-
pub fn unnest(&self,
|
|
860
|
-
self.ldf
|
|
1211
|
+
pub fn unnest(&self, columns: &RbSelector, separator: Option<String>) -> Self {
|
|
1212
|
+
self.ldf
|
|
1213
|
+
.read()
|
|
1214
|
+
.clone()
|
|
1215
|
+
.unnest(
|
|
1216
|
+
columns.inner.clone(),
|
|
1217
|
+
separator.as_deref().map(PlSmallStr::from_str),
|
|
1218
|
+
)
|
|
1219
|
+
.into()
|
|
861
1220
|
}
|
|
862
1221
|
|
|
863
1222
|
pub fn count(&self) -> Self {
|
|
864
|
-
let ldf = self.ldf.
|
|
1223
|
+
let ldf = self.ldf.read().clone();
|
|
865
1224
|
ldf.count().into()
|
|
866
1225
|
}
|
|
867
1226
|
|
|
868
|
-
pub fn merge_sorted(&self, other: &Self, key: String) -> RbResult<Self> {
|
|
1227
|
+
pub fn merge_sorted(&self, other: &Self, key: String, maintain_order: bool) -> RbResult<Self> {
|
|
869
1228
|
let out = self
|
|
870
1229
|
.ldf
|
|
871
|
-
.
|
|
1230
|
+
.read()
|
|
872
1231
|
.clone()
|
|
873
|
-
.merge_sorted(other.ldf.
|
|
1232
|
+
.merge_sorted(other.ldf.read().clone(), &key, maintain_order)
|
|
874
1233
|
.map_err(RbPolarsErr::from)?;
|
|
875
1234
|
Ok(out.into())
|
|
876
1235
|
}
|
|
1236
|
+
|
|
1237
|
+
pub fn hint_sorted(
|
|
1238
|
+
&self,
|
|
1239
|
+
columns: Vec<String>,
|
|
1240
|
+
descending: Vec<bool>,
|
|
1241
|
+
nulls_last: Vec<bool>,
|
|
1242
|
+
) -> RbResult<Self> {
|
|
1243
|
+
if columns.len() != descending.len() && descending.len() != 1 {
|
|
1244
|
+
return Err(RbValueError::new_err(
|
|
1245
|
+
"`set_sorted` expects the same amount of `columns` as `descending` values.",
|
|
1246
|
+
));
|
|
1247
|
+
}
|
|
1248
|
+
if columns.len() != nulls_last.len() && nulls_last.len() != 1 {
|
|
1249
|
+
return Err(RbValueError::new_err(
|
|
1250
|
+
"`set_sorted` expects the same amount of `columns` as `nulls_last` values.",
|
|
1251
|
+
));
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
let mut sorted = columns
|
|
1255
|
+
.iter()
|
|
1256
|
+
.map(|c| Sorted {
|
|
1257
|
+
column: PlSmallStr::from_str(c.as_str()),
|
|
1258
|
+
descending: Some(false),
|
|
1259
|
+
nulls_last: Some(false),
|
|
1260
|
+
})
|
|
1261
|
+
.collect::<Vec<_>>();
|
|
1262
|
+
|
|
1263
|
+
if !columns.is_empty() {
|
|
1264
|
+
if descending.len() != 1 {
|
|
1265
|
+
sorted
|
|
1266
|
+
.iter_mut()
|
|
1267
|
+
.zip(descending)
|
|
1268
|
+
.for_each(|(s, d)| s.descending = Some(d));
|
|
1269
|
+
} else if descending[0] {
|
|
1270
|
+
sorted.iter_mut().for_each(|s| s.descending = Some(true));
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
if nulls_last.len() != 1 {
|
|
1274
|
+
sorted
|
|
1275
|
+
.iter_mut()
|
|
1276
|
+
.zip(nulls_last)
|
|
1277
|
+
.for_each(|(s, d)| s.nulls_last = Some(d));
|
|
1278
|
+
} else if nulls_last[0] {
|
|
1279
|
+
sorted.iter_mut().for_each(|s| s.nulls_last = Some(true));
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
let out = self
|
|
1284
|
+
.ldf
|
|
1285
|
+
.read()
|
|
1286
|
+
.clone()
|
|
1287
|
+
.hint(HintIR::Sorted(sorted.into()))
|
|
1288
|
+
.map_err(RbPolarsErr::from)?;
|
|
1289
|
+
Ok(out.into())
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
#[magnus::wrap(class = "Polars::RbCollectBatches")]
|
|
1294
|
+
pub struct RbCollectBatches {
|
|
1295
|
+
inner: Arc<Mutex<CollectBatches>>,
|
|
1296
|
+
ldf: LazyFrame,
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
impl RbCollectBatches {
|
|
1300
|
+
pub fn next(rb: &Ruby, slf: &Self) -> RbResult<Option<RbDataFrame>> {
|
|
1301
|
+
let inner = Arc::clone(&slf.inner);
|
|
1302
|
+
rb.enter_polars(|| PolarsResult::Ok(inner.lock().next().transpose()?.map(RbDataFrame::new)))
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
pub fn __arrow_c_stream__(rb: &Ruby, self_: &Self) -> RbResult<Value> {
|
|
1306
|
+
let mut ldf = self_.ldf.clone();
|
|
1307
|
+
let schema = ldf
|
|
1308
|
+
.collect_schema()
|
|
1309
|
+
.map_err(RbPolarsErr::from)?
|
|
1310
|
+
.to_arrow(CompatLevel::newest());
|
|
1311
|
+
|
|
1312
|
+
let dtype = ArrowDataType::Struct(schema.into_iter_values().collect());
|
|
1313
|
+
|
|
1314
|
+
let iter = Box::new(ArrowStreamIterator::new(self_.inner.clone(), dtype.clone()));
|
|
1315
|
+
let field = ArrowField::new(PlSmallStr::EMPTY, dtype, false);
|
|
1316
|
+
let stream = export_iterator(iter, field);
|
|
1317
|
+
Ok(RbArrowArrayStream { stream }.into_value_with(rb))
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
pub struct ArrowStreamIterator {
|
|
1322
|
+
inner: Arc<Mutex<CollectBatches>>,
|
|
1323
|
+
dtype: ArrowDataType,
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
impl ArrowStreamIterator {
|
|
1327
|
+
fn new(inner: Arc<Mutex<CollectBatches>>, schema: ArrowDataType) -> Self {
|
|
1328
|
+
Self {
|
|
1329
|
+
inner,
|
|
1330
|
+
dtype: schema,
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
impl Iterator for ArrowStreamIterator {
|
|
1336
|
+
type Item = PolarsResult<ArrayRef>;
|
|
1337
|
+
|
|
1338
|
+
fn next(&mut self) -> Option<Self::Item> {
|
|
1339
|
+
let next = self.inner.lock().next();
|
|
1340
|
+
match next {
|
|
1341
|
+
None => None,
|
|
1342
|
+
Some(Err(err)) => Some(Err(err)),
|
|
1343
|
+
Some(Ok(df)) => {
|
|
1344
|
+
let height = df.height();
|
|
1345
|
+
let arrays = df.rechunk_into_arrow(CompatLevel::newest());
|
|
1346
|
+
Some(Ok(Box::new(arrow::array::StructArray::new(
|
|
1347
|
+
self.dtype.clone(),
|
|
1348
|
+
height,
|
|
1349
|
+
arrays,
|
|
1350
|
+
None,
|
|
1351
|
+
))))
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
877
1355
|
}
|