File tree Expand file tree Collapse file tree 7 files changed +91
-2
lines changed
Expand file tree Collapse file tree 7 files changed +91
-2
lines changed Original file line number Diff line number Diff line change 11## 0.21.2 (unreleased)
22
33- Added ` serialize ` and ` deserialize ` methods to ` LazyFrame `
4+ - Added ` serialize ` and ` deserialize ` methods to ` Expr `
45- Added ` storage_options ` and ` retries ` options to ` sink_ipc ` method
56- Added experimental support for Iceberg
67- Added experimental ` cast_options ` option to ` scan_parquet ` method
Original file line number Diff line number Diff line change @@ -10,6 +10,7 @@ mod meta;
1010mod name;
1111mod rolling;
1212pub mod selector;
13+ mod serde;
1314mod string;
1415mod r#struct;
1516
Original file line number Diff line number Diff line change 1+ use std:: io:: { BufReader , BufWriter } ;
2+
3+ use magnus:: Value ;
4+ use polars:: lazy:: prelude:: Expr ;
5+ use polars_utils:: pl_serialize;
6+
7+ use crate :: exceptions:: ComputeError ;
8+ use crate :: file:: get_file_like;
9+ use crate :: { RbExpr , RbResult } ;
10+
11+ impl RbExpr {
12+ pub fn serialize_binary ( & self , rb_f : Value ) -> RbResult < ( ) > {
13+ let file = get_file_like ( rb_f, true ) ?;
14+ let writer = BufWriter :: new ( file) ;
15+ pl_serialize:: SerializeOptions :: default ( )
16+ . serialize_into_writer :: < _ , _ , true > ( writer, & self . inner )
17+ . map_err ( |err| ComputeError :: new_err ( err. to_string ( ) ) )
18+ }
19+
20+ pub fn deserialize_binary ( rb_f : Value ) -> RbResult < RbExpr > {
21+ let file = get_file_like ( rb_f, false ) ?;
22+ let reader = BufReader :: new ( file) ;
23+ let expr: Expr = pl_serialize:: SerializeOptions :: default ( )
24+ . deserialize_from_reader :: < _ , _ , true > ( reader)
25+ . map_err ( |err| ComputeError :: new_err ( err. to_string ( ) ) ) ?;
26+ Ok ( expr. into ( ) )
27+ }
28+ }
Original file line number Diff line number Diff line change @@ -578,6 +578,11 @@ fn init(ruby: &Ruby) -> RbResult<()> {
578578 class. define_method ( "hist" , method ! ( RbExpr :: hist, 4 ) ) ?;
579579 class. define_method ( "into_selector" , method ! ( RbExpr :: into_selector, 0 ) ) ?;
580580 class. define_singleton_method ( "new_selector" , function ! ( RbExpr :: new_selector, 1 ) ) ?;
581+ class. define_method ( "serialize_binary" , method ! ( RbExpr :: serialize_binary, 1 ) ) ?;
582+ class. define_singleton_method (
583+ "deserialize_binary" ,
584+ function ! ( RbExpr :: deserialize_binary, 1 ) ,
585+ ) ?;
581586
582587 // bitwise
583588 class. define_method ( "bitwise_count_ones" , method ! ( RbExpr :: bitwise_count_ones, 0 ) ) ?;
Original file line number Diff line number Diff line change @@ -146,6 +146,38 @@ def -@
146146 wrap_expr ( _rbexpr . neg )
147147 end
148148
149+ # Read a serialized expression from a file.
150+ #
151+ # @param source [Object]
152+ # Path to a file or a file-like object (by file-like object, we refer to
153+ # objects that have a `read` method, such as a file handler or `StringIO`).
154+ #
155+ # @return [Expr]
156+ #
157+ # @note
158+ # This function uses marshaling if the logical plan contains Ruby UDFs,
159+ # and as such inherits the security implications. Deserializing can execute
160+ # arbitrary code, so it should only be attempted on trusted data.
161+ #
162+ # @note
163+ # Serialization is not stable across Polars versions: a LazyFrame serialized
164+ # in one Polars version may not be deserializable in another Polars version.
165+ #
166+ # @example
167+ # expr = Polars.col("foo").sum.over("bar")
168+ # bytes = expr.meta.serialize
169+ # Polars::Expr.deserialize(StringIO.new(bytes))
170+ # # => col("foo").sum().over([col("bar")])
171+ def self . deserialize ( source )
172+ if Utils . pathlike? ( source )
173+ source = Utils . normalize_filepath ( source )
174+ end
175+
176+ deserializer = RbExpr . method ( :deserialize_binary )
177+
178+ _from_rbexpr ( deserializer . ( source ) )
179+ end
180+
149181 # Cast to physical representation of the logical dtype.
150182 #
151183 # - `:date` -> `:i32`
Original file line number Diff line number Diff line change @@ -45,8 +45,7 @@ def self.read_json(file)
4545 #
4646 # @param source [Object]
4747 # Path to a file or a file-like object (by file-like object, we refer to
48- # objects that have a `read` method, such as a file handler (e.g.
49- # via builtin `open` function) or `StringIO`).
48+ # objects that have a `read` method, such as a file handler or `StringIO`).
5049 #
5150 # @return [LazyFrame]
5251 #
Original file line number Diff line number Diff line change @@ -248,6 +248,29 @@ def as_selector
248248 Selector . _from_rbselector ( _rbexpr . into_selector )
249249 end
250250
251+ # Serialize this expression to a file or string.
252+ #
253+ # @param file [Object]
254+ # File path to which the result should be written. If set to `nil`
255+ # (default), the output is returned as a string instead.
256+ #
257+ # @return [Object]
258+ #
259+ # @note
260+ # Serialization is not stable across Polars versions: a LazyFrame serialized
261+ # in one Polars version may not be deserializable in another Polars version.
262+ #
263+ # @example Serialize the expression into a binary representation.
264+ # expr = Polars.col("foo").sum.over("bar")
265+ # bytes = expr.meta.serialize
266+ # Polars::Expr.deserialize(StringIO.new(bytes))
267+ # # => col("foo").sum().over([col("bar")])
268+ def serialize ( file = nil )
269+ serializer = _rbexpr . method ( :serialize_binary )
270+
271+ Utils . serialize_polars_object ( serializer , file )
272+ end
273+
251274 # Format the expression as a tree.
252275 #
253276 # @param return_as_string [Boolean]
You can’t perform that action at this time.
0 commit comments