polars-df 0.19.0 → 0.21.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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/Cargo.lock +211 -320
  4. data/LICENSE.txt +1 -1
  5. data/ext/polars/Cargo.toml +13 -9
  6. data/ext/polars/src/batched_csv.rs +2 -2
  7. data/ext/polars/src/catalog/mod.rs +1 -0
  8. data/ext/polars/src/catalog/unity.rs +450 -0
  9. data/ext/polars/src/conversion/any_value.rs +9 -19
  10. data/ext/polars/src/conversion/categorical.rs +30 -0
  11. data/ext/polars/src/conversion/chunked_array.rs +8 -8
  12. data/ext/polars/src/conversion/mod.rs +187 -109
  13. data/ext/polars/src/dataframe/construction.rs +2 -2
  14. data/ext/polars/src/dataframe/export.rs +2 -2
  15. data/ext/polars/src/dataframe/general.rs +4 -2
  16. data/ext/polars/src/dataframe/io.rs +2 -2
  17. data/ext/polars/src/exceptions.rs +1 -1
  18. data/ext/polars/src/expr/datatype.rs +14 -0
  19. data/ext/polars/src/expr/general.rs +36 -44
  20. data/ext/polars/src/expr/list.rs +27 -17
  21. data/ext/polars/src/expr/meta.rs +18 -41
  22. data/ext/polars/src/expr/mod.rs +3 -1
  23. data/ext/polars/src/expr/name.rs +2 -2
  24. data/ext/polars/src/expr/rolling.rs +1 -1
  25. data/ext/polars/src/expr/selector.rs +219 -0
  26. data/ext/polars/src/expr/string.rs +14 -7
  27. data/ext/polars/src/file.rs +12 -6
  28. data/ext/polars/src/functions/io.rs +2 -11
  29. data/ext/polars/src/functions/lazy.rs +22 -54
  30. data/ext/polars/src/functions/meta.rs +2 -2
  31. data/ext/polars/src/functions/misc.rs +1 -1
  32. data/ext/polars/src/functions/range.rs +14 -10
  33. data/ext/polars/src/functions/string_cache.rs +4 -5
  34. data/ext/polars/src/interop/numo/numo_rs.rs +1 -1
  35. data/ext/polars/src/interop/numo/to_numo_series.rs +1 -1
  36. data/ext/polars/src/io/mod.rs +102 -0
  37. data/ext/polars/src/lazyframe/general.rs +75 -113
  38. data/ext/polars/src/lazyframe/serde.rs +1 -1
  39. data/ext/polars/src/lazyframe/sink.rs +6 -6
  40. data/ext/polars/src/lib.rs +104 -26
  41. data/ext/polars/src/map/dataframe.rs +7 -7
  42. data/ext/polars/src/map/lazy.rs +1 -1
  43. data/ext/polars/src/map/mod.rs +31 -19
  44. data/ext/polars/src/map/series.rs +8 -8
  45. data/ext/polars/src/on_startup.rs +5 -2
  46. data/ext/polars/src/rb_modules.rs +1 -1
  47. data/ext/polars/src/series/construction.rs +11 -7
  48. data/ext/polars/src/series/export.rs +6 -4
  49. data/ext/polars/src/series/general.rs +12 -207
  50. data/ext/polars/src/series/import.rs +2 -2
  51. data/ext/polars/src/series/map.rs +227 -0
  52. data/ext/polars/src/series/mod.rs +2 -1
  53. data/ext/polars/src/series/scatter.rs +1 -1
  54. data/ext/polars/src/utils.rs +10 -2
  55. data/lib/polars/cat_name_space.rb +3 -43
  56. data/lib/polars/catalog/unity/catalog_info.rb +20 -0
  57. data/lib/polars/catalog/unity/column_info.rb +31 -0
  58. data/lib/polars/catalog/unity/namespace_info.rb +21 -0
  59. data/lib/polars/catalog/unity/table_info.rb +50 -0
  60. data/lib/polars/catalog.rb +448 -0
  61. data/lib/polars/convert.rb +10 -0
  62. data/lib/polars/data_frame.rb +151 -30
  63. data/lib/polars/data_types.rb +47 -3
  64. data/lib/polars/exceptions.rb +7 -2
  65. data/lib/polars/expr.rb +48 -39
  66. data/lib/polars/functions/col.rb +6 -5
  67. data/lib/polars/functions/eager.rb +1 -1
  68. data/lib/polars/functions/lazy.rb +114 -15
  69. data/lib/polars/functions/repeat.rb +4 -0
  70. data/lib/polars/io/csv.rb +18 -0
  71. data/lib/polars/io/json.rb +16 -0
  72. data/lib/polars/io/ndjson.rb +13 -0
  73. data/lib/polars/io/parquet.rb +45 -63
  74. data/lib/polars/io/scan_options.rb +47 -0
  75. data/lib/polars/lazy_frame.rb +163 -75
  76. data/lib/polars/list_expr.rb +213 -17
  77. data/lib/polars/list_name_space.rb +121 -8
  78. data/lib/polars/meta_expr.rb +14 -29
  79. data/lib/polars/scan_cast_options.rb +64 -0
  80. data/lib/polars/schema.rb +6 -1
  81. data/lib/polars/selector.rb +138 -0
  82. data/lib/polars/selectors.rb +931 -202
  83. data/lib/polars/series.rb +46 -19
  84. data/lib/polars/string_expr.rb +24 -3
  85. data/lib/polars/string_name_space.rb +12 -1
  86. data/lib/polars/utils/parse.rb +40 -0
  87. data/lib/polars/utils.rb +5 -1
  88. data/lib/polars/version.rb +1 -1
  89. data/lib/polars.rb +8 -0
  90. metadata +17 -2
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2020 Ritchie Vink
1
+ Copyright (c) 2025 Ritchie Vink
2
2
  Copyright (c) 2022-2025 Andrew Kane
3
3
  Some portions Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4
4
 
@@ -1,9 +1,9 @@
1
1
  [package]
2
2
  name = "polars"
3
- version = "0.19.0"
3
+ version = "0.21.0"
4
4
  license = "MIT"
5
5
  authors = ["Andrew Kane <andrew@ankane.org>"]
6
- edition = "2021"
6
+ edition = "2024"
7
7
  rust-version = "1.85.0"
8
8
  publish = false
9
9
 
@@ -12,22 +12,25 @@ crate-type = ["cdylib"]
12
12
 
13
13
  [dependencies]
14
14
  ahash = "0.8"
15
- arrow = { package = "polars-arrow", version = "=0.48.0" }
15
+ arrow = { package = "polars-arrow", version = "=0.50.0" }
16
16
  bytes = "1"
17
17
  chrono = "0.4"
18
18
  either = "1.8"
19
- magnus = "0.7"
19
+ magnus = { git = "https://github.com/matsadler/magnus.git", rev = "4125ee2ab5a405d17aa6d7503961c1ecdbe499ef", features = ["chrono"] }
20
20
  num-traits = "0.2"
21
- polars-core = "=0.48.0"
22
- polars-plan = "=0.48.0"
23
- polars-parquet = "=0.48.0"
24
- polars-utils = "=0.48.0"
21
+ polars-core = "=0.50.0"
22
+ polars-dtype = "=0.50.0"
23
+ polars-io = "=0.50.0"
24
+ polars-lazy = { version = "=0.50.0", features = ["catalog"] }
25
+ polars-plan = "=0.50.0"
26
+ polars-parquet = "=0.50.0"
27
+ polars-utils = "=0.50.0"
25
28
  rayon = "1.9"
26
29
  regex = "1"
27
30
  serde_json = "1"
28
31
 
29
32
  [dependencies.polars]
30
- version = "=0.48.0"
33
+ version = "=0.50.0"
31
34
  features = [
32
35
  "abs",
33
36
  "approx_unique",
@@ -80,6 +83,7 @@ features = [
80
83
  "list_eval",
81
84
  "list_gather",
82
85
  "list_sample",
86
+ "list_sets",
83
87
  "list_to_struct",
84
88
  "log",
85
89
  "merge_sorted",
@@ -2,10 +2,10 @@ use std::cell::RefCell;
2
2
  use std::path::PathBuf;
3
3
  use std::sync::Mutex;
4
4
 
5
- use magnus::{prelude::*, RArray, Value};
5
+ use magnus::{RArray, Value, prelude::*};
6
+ use polars::io::RowIndex;
6
7
  use polars::io::csv::read::OwnedBatchedCsvReader;
7
8
  use polars::io::mmap::MmapBytesReader;
8
- use polars::io::RowIndex;
9
9
  use polars::prelude::*;
10
10
 
11
11
  use crate::conversion::*;
@@ -0,0 +1 @@
1
+ pub mod unity;
@@ -0,0 +1,450 @@
1
+ use std::str::FromStr;
2
+
3
+ use magnus::value::{Lazy, ReprValue};
4
+ use magnus::{IntoValue, Module, RArray, RClass, RHash, RModule, Ruby, Value};
5
+ use polars::prelude::{PlHashMap, PlSmallStr, Schema};
6
+ use polars_io::catalog::unity::client::{CatalogClient, CatalogClientBuilder};
7
+ use polars_io::catalog::unity::models::{
8
+ CatalogInfo, ColumnInfo, DataSourceFormat, NamespaceInfo, TableInfo, TableType,
9
+ };
10
+ use polars_io::catalog::unity::schema::parse_type_json_str;
11
+ use polars_io::pl_async;
12
+
13
+ use crate::rb_modules::polars;
14
+ use crate::utils::to_rb_err;
15
+ use crate::{RbResult, RbValueError, Wrap};
16
+
17
+ macro_rules! rbdict_insert_keys {
18
+ ($dict:expr, {$a:expr}) => {
19
+ $dict.aset(stringify!($a), $a)?;
20
+ };
21
+
22
+ ($dict:expr, {$a:expr, $($args:expr),+}) => {
23
+ rbdict_insert_keys!($dict, { $a });
24
+ rbdict_insert_keys!($dict, { $($args),+ });
25
+ };
26
+
27
+ ($dict:expr, {$a:expr, $($args:expr),+,}) => {
28
+ rbdict_insert_keys!($dict, {$a, $($args),+});
29
+ };
30
+ }
31
+
32
+ static CATALOG_INFO_CLS: Lazy<RClass> = Lazy::new(|_| {
33
+ polars()
34
+ .const_get::<_, RClass>("Catalog")
35
+ .unwrap()
36
+ .const_get::<_, RModule>("Unity")
37
+ .unwrap()
38
+ .const_get("CatalogInfo")
39
+ .unwrap()
40
+ });
41
+
42
+ static NAMESPACE_INFO_CLS: Lazy<RClass> = Lazy::new(|_| {
43
+ polars()
44
+ .const_get::<_, RClass>("Catalog")
45
+ .unwrap()
46
+ .const_get::<_, RModule>("Unity")
47
+ .unwrap()
48
+ .const_get("NamespaceInfo")
49
+ .unwrap()
50
+ });
51
+
52
+ static TABLE_INFO_CLS: Lazy<RClass> = Lazy::new(|_| {
53
+ polars()
54
+ .const_get::<_, RClass>("Catalog")
55
+ .unwrap()
56
+ .const_get::<_, RModule>("Unity")
57
+ .unwrap()
58
+ .const_get("TableInfo")
59
+ .unwrap()
60
+ });
61
+
62
+ static COLUMN_INFO_CLS: Lazy<RClass> = Lazy::new(|_| {
63
+ polars()
64
+ .const_get::<_, RClass>("Catalog")
65
+ .unwrap()
66
+ .const_get::<_, RModule>("Unity")
67
+ .unwrap()
68
+ .const_get("ColumnInfo")
69
+ .unwrap()
70
+ });
71
+
72
+ #[magnus::wrap(class = "Polars::RbCatalogClient")]
73
+ pub struct RbCatalogClient(CatalogClient);
74
+
75
+ impl RbCatalogClient {
76
+ pub fn new(workspace_url: String, bearer_token: Option<String>) -> RbResult<Self> {
77
+ let builder = CatalogClientBuilder::new().with_workspace_url(workspace_url);
78
+
79
+ let builder = if let Some(bearer_token) = bearer_token {
80
+ builder.with_bearer_token(bearer_token)
81
+ } else {
82
+ builder
83
+ };
84
+
85
+ builder.build().map(RbCatalogClient).map_err(to_rb_err)
86
+ }
87
+
88
+ pub fn list_catalogs(&self) -> RbResult<Value> {
89
+ let v = pl_async::get_runtime()
90
+ .block_in_place_on(self.client().list_catalogs())
91
+ .map_err(to_rb_err)?;
92
+
93
+ let mut opt_err = None;
94
+
95
+ let out = RArray::from_iter(v.into_iter().map(|x| {
96
+ let v = catalog_info_to_rbobject(x);
97
+ if let Ok(v) = v {
98
+ Some(v)
99
+ } else {
100
+ opt_err.replace(v);
101
+ None
102
+ }
103
+ }));
104
+
105
+ opt_err.transpose()?;
106
+
107
+ Ok(out.into_value())
108
+ }
109
+
110
+ pub fn list_namespaces(&self, catalog_name: String) -> RbResult<Value> {
111
+ let v = pl_async::get_runtime()
112
+ .block_in_place_on(self.client().list_namespaces(&catalog_name))
113
+ .map_err(to_rb_err)?;
114
+
115
+ let mut opt_err = None;
116
+
117
+ let out = RArray::from_iter(v.into_iter().map(|x| {
118
+ let v = namespace_info_to_rbobject(x);
119
+ match v {
120
+ Ok(v) => Some(v),
121
+ Err(_) => {
122
+ opt_err.replace(v);
123
+ None
124
+ }
125
+ }
126
+ }));
127
+
128
+ opt_err.transpose()?;
129
+
130
+ Ok(out.into_value())
131
+ }
132
+
133
+ pub fn list_tables(&self, catalog_name: String, namespace: String) -> RbResult<Value> {
134
+ let v = pl_async::get_runtime()
135
+ .block_in_place_on(self.client().list_tables(&catalog_name, &namespace))
136
+ .map_err(to_rb_err)?;
137
+
138
+ let mut opt_err = None;
139
+
140
+ let out = RArray::from_iter(v.into_iter().map(|table_info| {
141
+ let v = table_info_to_rbobject(table_info);
142
+
143
+ if let Ok(v) = v {
144
+ Some(v)
145
+ } else {
146
+ opt_err.replace(v);
147
+ None
148
+ }
149
+ }))
150
+ .into_value();
151
+
152
+ opt_err.transpose()?;
153
+
154
+ Ok(out)
155
+ }
156
+
157
+ pub fn get_table_info(
158
+ &self,
159
+ table_name: String,
160
+ catalog_name: String,
161
+ namespace: String,
162
+ ) -> RbResult<Value> {
163
+ let table_info = pl_async::get_runtime()
164
+ .block_in_place_on(
165
+ self.client()
166
+ .get_table_info(&table_name, &catalog_name, &namespace),
167
+ )
168
+ .map_err(to_rb_err)?;
169
+
170
+ table_info_to_rbobject(table_info)
171
+ }
172
+
173
+ pub fn create_catalog(
174
+ &self,
175
+ catalog_name: String,
176
+ comment: Option<String>,
177
+ storage_root: Option<String>,
178
+ ) -> RbResult<Value> {
179
+ let catalog_info = pl_async::get_runtime()
180
+ .block_in_place_on(self.client().create_catalog(
181
+ &catalog_name,
182
+ comment.as_deref(),
183
+ storage_root.as_deref(),
184
+ ))
185
+ .map_err(to_rb_err)?;
186
+
187
+ catalog_info_to_rbobject(catalog_info)
188
+ }
189
+
190
+ pub fn delete_catalog(&self, catalog_name: String, force: bool) -> RbResult<()> {
191
+ pl_async::get_runtime()
192
+ .block_in_place_on(self.client().delete_catalog(&catalog_name, force))
193
+ .map_err(to_rb_err)
194
+ }
195
+
196
+ pub fn create_namespace(
197
+ &self,
198
+ catalog_name: String,
199
+ namespace: String,
200
+ comment: Option<String>,
201
+ storage_root: Option<String>,
202
+ ) -> RbResult<Value> {
203
+ let namespace_info = pl_async::get_runtime()
204
+ .block_in_place_on(self.client().create_namespace(
205
+ &catalog_name,
206
+ &namespace,
207
+ comment.as_deref(),
208
+ storage_root.as_deref(),
209
+ ))
210
+ .map_err(to_rb_err)?;
211
+
212
+ namespace_info_to_rbobject(namespace_info)
213
+ }
214
+
215
+ pub fn delete_namespace(
216
+ &self,
217
+ catalog_name: String,
218
+ namespace: String,
219
+ force: bool,
220
+ ) -> RbResult<()> {
221
+ pl_async::get_runtime()
222
+ .block_in_place_on(
223
+ self.client()
224
+ .delete_namespace(&catalog_name, &namespace, force),
225
+ )
226
+ .map_err(to_rb_err)
227
+ }
228
+
229
+ #[allow(clippy::too_many_arguments)]
230
+ pub fn create_table(
231
+ &self,
232
+ catalog_name: String,
233
+ namespace: String,
234
+ table_name: String,
235
+ schema: Option<Wrap<Schema>>,
236
+ table_type: String,
237
+ data_source_format: Option<String>,
238
+ comment: Option<String>,
239
+ storage_root: Option<String>,
240
+ properties: Vec<(String, String)>,
241
+ ) -> RbResult<Value> {
242
+ let table_info = pl_async::get_runtime()
243
+ .block_in_place_on(
244
+ self.client().create_table(
245
+ &catalog_name,
246
+ &namespace,
247
+ &table_name,
248
+ schema.as_ref().map(|x| &x.0),
249
+ &TableType::from_str(&table_type)
250
+ .map_err(|e| RbValueError::new_err(e.to_string()))?,
251
+ data_source_format
252
+ .as_deref()
253
+ .map(DataSourceFormat::from_str)
254
+ .transpose()
255
+ .map_err(|e| RbValueError::new_err(e.to_string()))?
256
+ .as_ref(),
257
+ comment.as_deref(),
258
+ storage_root.as_deref(),
259
+ &mut properties.iter().map(|(a, b)| (a.as_str(), b.as_str())),
260
+ ),
261
+ )
262
+ .map_err(to_rb_err)?;
263
+
264
+ table_info_to_rbobject(table_info)
265
+ }
266
+
267
+ pub fn delete_table(
268
+ &self,
269
+ catalog_name: String,
270
+ namespace: String,
271
+ table_name: String,
272
+ ) -> RbResult<()> {
273
+ pl_async::get_runtime()
274
+ .block_in_place_on(
275
+ self.client()
276
+ .delete_table(&catalog_name, &namespace, &table_name),
277
+ )
278
+ .map_err(to_rb_err)
279
+ }
280
+
281
+ pub fn type_json_to_polars_type(type_json: String) -> RbResult<Value> {
282
+ Ok(Wrap(parse_type_json_str(&type_json).map_err(to_rb_err)?).into_value())
283
+ }
284
+ }
285
+
286
+ impl RbCatalogClient {
287
+ fn client(&self) -> &CatalogClient {
288
+ &self.0
289
+ }
290
+ }
291
+
292
+ fn catalog_info_to_rbobject(
293
+ CatalogInfo {
294
+ name,
295
+ comment,
296
+ storage_location,
297
+ properties,
298
+ options,
299
+ created_at,
300
+ created_by,
301
+ updated_at,
302
+ updated_by,
303
+ }: CatalogInfo,
304
+ ) -> RbResult<Value> {
305
+ let dict = RHash::new();
306
+
307
+ let properties = properties_to_rbobject(properties);
308
+ let options = properties_to_rbobject(options);
309
+
310
+ rbdict_insert_keys!(dict, {
311
+ name,
312
+ comment,
313
+ storage_location,
314
+ properties,
315
+ options,
316
+ created_at,
317
+ created_by,
318
+ updated_at,
319
+ updated_by
320
+ });
321
+
322
+ Ruby::get()
323
+ .unwrap()
324
+ .get_inner(&CATALOG_INFO_CLS)
325
+ .funcall("new", (dict,))
326
+ }
327
+
328
+ fn namespace_info_to_rbobject(
329
+ NamespaceInfo {
330
+ name,
331
+ comment,
332
+ properties,
333
+ storage_location,
334
+ created_at,
335
+ created_by,
336
+ updated_at,
337
+ updated_by,
338
+ }: NamespaceInfo,
339
+ ) -> RbResult<Value> {
340
+ let dict = RHash::new();
341
+
342
+ let properties = properties_to_rbobject(properties);
343
+
344
+ rbdict_insert_keys!(dict, {
345
+ name,
346
+ comment,
347
+ properties,
348
+ storage_location,
349
+ created_at,
350
+ created_by,
351
+ updated_at,
352
+ updated_by
353
+ });
354
+
355
+ Ruby::get()
356
+ .unwrap()
357
+ .get_inner(&NAMESPACE_INFO_CLS)
358
+ .funcall("new", (dict,))
359
+ }
360
+
361
+ fn table_info_to_rbobject(table_info: TableInfo) -> RbResult<Value> {
362
+ let TableInfo {
363
+ name,
364
+ table_id,
365
+ table_type,
366
+ comment,
367
+ storage_location,
368
+ data_source_format,
369
+ columns,
370
+ properties,
371
+ created_at,
372
+ created_by,
373
+ updated_at,
374
+ updated_by,
375
+ } = table_info;
376
+
377
+ let column_info_cls = Ruby::get().unwrap().get_inner(&COLUMN_INFO_CLS);
378
+
379
+ let columns = columns
380
+ .map(|columns| {
381
+ Ruby::get()
382
+ .unwrap()
383
+ .ary_try_from_iter(columns.into_iter().map(
384
+ |ColumnInfo {
385
+ name,
386
+ type_name,
387
+ type_text,
388
+ type_json,
389
+ position,
390
+ comment,
391
+ partition_index,
392
+ }| {
393
+ let dict = RHash::new();
394
+
395
+ let name = name.as_str();
396
+ let type_name = type_name.as_str();
397
+ let type_text = type_text.as_str();
398
+
399
+ rbdict_insert_keys!(dict, {
400
+ name,
401
+ type_name,
402
+ type_text,
403
+ type_json,
404
+ position,
405
+ comment,
406
+ partition_index,
407
+ });
408
+
409
+ column_info_cls.funcall::<_, _, Value>("new", (dict,))
410
+ },
411
+ ))
412
+ })
413
+ .transpose()?;
414
+
415
+ let dict = RHash::new();
416
+
417
+ let data_source_format = data_source_format.map(|x| x.to_string());
418
+ let table_type = table_type.to_string();
419
+ let properties = properties_to_rbobject(properties);
420
+
421
+ rbdict_insert_keys!(dict, {
422
+ name,
423
+ comment,
424
+ table_id,
425
+ table_type,
426
+ storage_location,
427
+ data_source_format,
428
+ columns,
429
+ properties,
430
+ created_at,
431
+ created_by,
432
+ updated_at,
433
+ updated_by,
434
+ });
435
+
436
+ Ruby::get()
437
+ .unwrap()
438
+ .get_inner(&TABLE_INFO_CLS)
439
+ .funcall("new", (dict,))
440
+ }
441
+
442
+ fn properties_to_rbobject(properties: PlHashMap<PlSmallStr, String>) -> RHash {
443
+ let dict = RHash::new();
444
+
445
+ for (key, value) in properties.into_iter() {
446
+ dict.aset(key.as_str(), value).unwrap();
447
+ }
448
+
449
+ dict
450
+ }
@@ -1,11 +1,11 @@
1
1
  use magnus::encoding::{EncodingCapable, Index};
2
2
  use magnus::{
3
- class, prelude::*, r_hash::ForEach, IntoValue, RArray, RHash, RString, Ruby, TryConvert, Value,
3
+ IntoValue, RArray, RHash, RString, Ruby, TryConvert, Value, class, prelude::*, r_hash::ForEach,
4
4
  };
5
5
  use polars::prelude::*;
6
6
  use polars_core::utils::any_values_to_supertype_and_n_dtypes;
7
7
 
8
- use super::{struct_dict, ObjectValue, Wrap};
8
+ use super::{ObjectValue, Wrap, struct_dict};
9
9
 
10
10
  use crate::exceptions::RbOverflowError;
11
11
  use crate::rb_modules::utils;
@@ -40,22 +40,12 @@ pub(crate) fn any_value_into_rb_object(av: AnyValue, ruby: &Ruby) -> Value {
40
40
  AnyValue::Boolean(v) => ruby.into_value(v),
41
41
  AnyValue::String(v) => ruby.into_value(v),
42
42
  AnyValue::StringOwned(v) => ruby.into_value(v.as_str()),
43
- AnyValue::Categorical(idx, rev, arr) | AnyValue::Enum(idx, rev, arr) => {
44
- let s = if arr.is_null() {
45
- rev.get(idx)
46
- } else {
47
- unsafe { arr.deref_unchecked().value(idx as usize) }
48
- };
49
- s.into_value()
50
- }
51
- AnyValue::CategoricalOwned(idx, rev, arr) | AnyValue::EnumOwned(idx, rev, arr) => {
52
- let s = if arr.is_null() {
53
- rev.get(idx)
54
- } else {
55
- unsafe { arr.deref_unchecked().value(idx as usize) }
56
- };
57
- s.into_value()
58
- }
43
+ AnyValue::Categorical(cat, map) | AnyValue::Enum(cat, map) => unsafe {
44
+ map.cat_to_str_unchecked(cat).into_value()
45
+ },
46
+ AnyValue::CategoricalOwned(cat, map) | AnyValue::EnumOwned(cat, map) => unsafe {
47
+ map.cat_to_str_unchecked(cat).into_value()
48
+ },
59
49
  AnyValue::Date(v) => utils().funcall("_to_ruby_date", (v,)).unwrap(),
60
50
  AnyValue::Datetime(v, time_unit, time_zone) => {
61
51
  datetime_to_rb_object(v, time_unit, time_zone)
@@ -273,6 +263,6 @@ pub(crate) fn rb_object_to_any_value<'s>(ob: Value, strict: bool) -> RbResult<An
273
263
  } else if ob.is_kind_of(crate::rb_modules::bigdecimal()) {
274
264
  get_decimal(ob, strict)
275
265
  } else {
276
- Err(RbPolarsErr::Other(format!("object type not supported {:?}", ob)).into())
266
+ Err(RbPolarsErr::Other(format!("object type not supported {ob:?}")).into())
277
267
  }
278
268
  }
@@ -0,0 +1,30 @@
1
+ use std::sync::Arc;
2
+
3
+ use polars_dtype::categorical::Categories;
4
+
5
+ #[magnus::wrap(class = "Polars::RbCategories")]
6
+ #[repr(transparent)]
7
+ #[derive(Clone)]
8
+ pub struct RbCategories {
9
+ categories: Arc<Categories>,
10
+ }
11
+
12
+ impl RbCategories {
13
+ pub fn categories(&self) -> &Arc<Categories> {
14
+ &self.categories
15
+ }
16
+ }
17
+
18
+ impl RbCategories {
19
+ pub fn global_categories() -> Self {
20
+ Self {
21
+ categories: Categories::global(),
22
+ }
23
+ }
24
+ }
25
+
26
+ impl From<Arc<Categories>> for RbCategories {
27
+ fn from(categories: Arc<Categories>) -> Self {
28
+ Self { categories }
29
+ }
30
+ }
@@ -1,10 +1,10 @@
1
- use magnus::{prelude::*, IntoValue, RArray, RString, Ruby, TryConvert, Value};
1
+ use magnus::{IntoValue, RArray, RString, Ruby, TryConvert, Value, prelude::*};
2
2
  use polars::prelude::*;
3
3
 
4
- use super::{get_rbseq, struct_dict, Wrap};
4
+ use super::{Wrap, get_rbseq, struct_dict};
5
5
 
6
- use crate::rb_modules::utils;
7
6
  use crate::RbResult;
7
+ use crate::rb_modules::utils;
8
8
 
9
9
  impl TryConvert for Wrap<StringChunked> {
10
10
  fn try_convert(obj: Value) -> RbResult<Self> {
@@ -75,7 +75,7 @@ impl IntoValue for Wrap<&DurationChunked> {
75
75
  fn into_value_with(self, _: &Ruby) -> Value {
76
76
  let utils = utils();
77
77
  let time_unit = Wrap(self.0.time_unit()).into_value();
78
- let iter = self.0.into_iter().map(|opt_v| {
78
+ let iter = self.0.physical().into_iter().map(|opt_v| {
79
79
  opt_v.map(|v| {
80
80
  utils
81
81
  .funcall::<_, _, Value>("_to_ruby_duration", (v, time_unit))
@@ -91,7 +91,7 @@ impl IntoValue for Wrap<&DatetimeChunked> {
91
91
  let utils = utils();
92
92
  let time_unit = Wrap(self.0.time_unit()).into_value();
93
93
  let time_zone = self.0.time_zone().as_deref().map(|v| v.into_value());
94
- let iter = self.0.into_iter().map(|opt_v| {
94
+ let iter = self.0.physical().into_iter().map(|opt_v| {
95
95
  opt_v.map(|v| {
96
96
  utils
97
97
  .funcall::<_, _, Value>("_to_ruby_datetime", (v, time_unit, time_zone))
@@ -105,7 +105,7 @@ impl IntoValue for Wrap<&DatetimeChunked> {
105
105
  impl IntoValue for Wrap<&TimeChunked> {
106
106
  fn into_value_with(self, _: &Ruby) -> Value {
107
107
  let utils = utils();
108
- let iter = self.0.into_iter().map(|opt_v| {
108
+ let iter = self.0.physical().into_iter().map(|opt_v| {
109
109
  opt_v.map(|v| utils.funcall::<_, _, Value>("_to_ruby_time", (v,)).unwrap())
110
110
  });
111
111
  RArray::from_iter(iter).into_value()
@@ -115,7 +115,7 @@ impl IntoValue for Wrap<&TimeChunked> {
115
115
  impl IntoValue for Wrap<&DateChunked> {
116
116
  fn into_value_with(self, _: &Ruby) -> Value {
117
117
  let utils = utils();
118
- let iter = self.0.into_iter().map(|opt_v| {
118
+ let iter = self.0.physical().into_iter().map(|opt_v| {
119
119
  opt_v.map(|v| utils.funcall::<_, _, Value>("_to_ruby_date", (v,)).unwrap())
120
120
  });
121
121
  RArray::from_iter(iter).into_value()
@@ -126,7 +126,7 @@ impl IntoValue for Wrap<&DecimalChunked> {
126
126
  fn into_value_with(self, _: &Ruby) -> Value {
127
127
  let utils = utils();
128
128
  let rb_scale = (-(self.0.scale() as i32)).into_value();
129
- let iter = self.0.into_iter().map(|opt_v| {
129
+ let iter = self.0.physical().into_iter().map(|opt_v| {
130
130
  opt_v.map(|v| {
131
131
  utils
132
132
  .funcall::<_, _, Value>("_to_ruby_decimal", (v.to_string(), rb_scale))