1use chrono::{DateTime, Duration, NaiveDate};
7use num_traits::identities::Zero;
8use polars::prelude::*;
9#[cfg(not(target_arch = "wasm32"))]
10use rayon::iter::IntoParallelIterator;
11#[cfg(not(target_arch = "wasm32"))]
12use rayon::iter::ParallelIterator;
13use serde::ser::{SerializeMap, SerializeSeq};
14use serde_json::{Number as JsonNumber, Value as JsonValue};
15use std::collections::HashMap;
16
17#[derive(Clone)]
18pub enum Value {
19 Null,
21 Bool(bool),
23 Int(i64),
25 BigInt(num_bigint::BigInt),
27 Float(f64),
29 String(String),
31 Array(Vec<Value>),
33 Object(HashMap<String, Value>),
35 DataFrame(polars::prelude::DataFrame),
37 LazyFrame(Box<polars::prelude::LazyFrame>),
39 Series(polars::prelude::Series),
41}
42
43impl Value {
44 #[must_use]
46 pub fn null() -> Self {
47 Value::Null
48 }
49
50 #[must_use]
52 pub fn bool(b: bool) -> Self {
53 Value::Bool(b)
54 }
55
56 #[must_use]
58 pub fn int(i: i64) -> Self {
59 Value::Int(i)
60 }
61
62 #[must_use]
64 pub fn bigint(i: num_bigint::BigInt) -> Self {
65 Value::BigInt(i)
66 }
67
68 #[must_use]
70 pub fn float(f: f64) -> Self {
71 Value::Float(f)
72 }
73
74 pub fn string(s: impl Into<String>) -> Self {
76 Value::String(s.into())
77 }
78
79 #[must_use]
81 pub fn array(arr: Vec<Value>) -> Self {
82 Value::Array(arr)
83 }
84
85 #[must_use]
87 pub fn object(obj: HashMap<String, Value>) -> Self {
88 Value::Object(obj)
89 }
90
91 #[must_use]
93 pub fn dataframe(df: polars::prelude::DataFrame) -> Self {
94 Value::DataFrame(df)
95 }
96
97 #[must_use]
99 pub fn lazy_frame(lf: polars::prelude::LazyFrame) -> Self {
100 Value::LazyFrame(Box::new(lf))
101 }
102
103 #[must_use]
105 pub fn series(s: polars::prelude::Series) -> Self {
106 Value::Series(s)
107 }
108}
109
110impl std::fmt::Debug for Value {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 match self {
113 Value::Null => write!(f, "Null"),
114 Value::Bool(b) => f.debug_tuple("Bool").field(b).finish(),
115 Value::Int(i) => f.debug_tuple("Int").field(i).finish(),
116 Value::BigInt(bi) => f.debug_tuple("BigInt").field(bi).finish(),
117 Value::Float(fl) => f.debug_tuple("Float").field(fl).finish(),
118 Value::String(s) => f.debug_tuple("String").field(s).finish(),
119 Value::Array(arr) => f.debug_tuple("Array").field(arr).finish(),
120 Value::Object(obj) => f.debug_tuple("Object").field(obj).finish(),
121 Value::DataFrame(df) => f
122 .debug_tuple("DataFrame")
123 .field(&format!("{}x{} DataFrame", df.height(), df.width()))
124 .finish(),
125 Value::LazyFrame(_) => f.debug_tuple("LazyFrame").field(&"<LazyFrame>").finish(),
126 Value::Series(s) => f
127 .debug_tuple("Series")
128 .field(&format!("{} Series[{}]", s.len(), s.dtype()))
129 .finish(),
130 }
131 }
132}
133
134impl Value {
135 #[must_use]
137 pub fn is_null(&self) -> bool {
138 matches!(self, Value::Null)
139 }
140
141 #[must_use]
143 pub fn is_dataframe(&self) -> bool {
144 matches!(self, Value::DataFrame(_))
145 }
146
147 #[must_use]
149 pub fn is_lazy_frame(&self) -> bool {
150 matches!(self, Value::LazyFrame(_))
151 }
152
153 #[must_use]
155 pub fn is_series(&self) -> bool {
156 matches!(self, Value::Series(_))
157 }
158
159 #[must_use]
161 pub fn type_name(&self) -> &'static str {
162 match self {
163 Value::Null => "null",
164 Value::Bool(_) => "boolean",
165 Value::Int(_) => "integer",
166 Value::BigInt(_) => "biginteger",
167 Value::Float(_) => "float",
168 Value::String(_) => "string",
169 Value::Array(_) => "array",
170 Value::Object(_) => "object",
171 Value::DataFrame(_) => "dataframe",
172 Value::LazyFrame(_) => "lazyframe",
173 Value::Series(_) => "series",
174 }
175 }
176
177 pub fn to_json(&self) -> crate::Result<JsonValue> {
179 match self {
180 Value::Null => Ok(JsonValue::Null),
181 Value::Bool(b) => Ok(JsonValue::Bool(*b)),
182 Value::Int(i) => Ok(JsonValue::Number(JsonNumber::from(*i))),
183 Value::BigInt(bi) => Ok(JsonValue::String(bi.to_string())),
184 Value::Float(f) => JsonNumber::from_f64(*f)
185 .map(JsonValue::Number)
186 .ok_or_else(|| crate::error::operation_error(format!("Invalid float: {f}"))),
187 Value::String(s) => Ok(JsonValue::String(s.clone())),
188 Value::Array(arr) => {
189 let json_arr: crate::Result<Vec<JsonValue>> =
190 arr.iter().map(Value::to_json).collect();
191 Ok(JsonValue::Array(json_arr?))
192 }
193 Value::Object(obj) => {
194 let json_obj: crate::Result<serde_json::Map<String, JsonValue>> = obj
195 .iter()
196 .map(|(k, v)| v.to_json().map(|json_v| (k.clone(), json_v)))
197 .collect();
198 Ok(JsonValue::Object(json_obj?))
199 }
200 Value::DataFrame(df) => {
201 Self::dataframe_to_json_array(df)
203 }
204 Value::LazyFrame(lf) => {
205 let df = lf.clone().collect().map_err(|e| {
207 crate::error::operation_error(format!("LazyFrame collect error: {e}"))
208 })?;
209 Self::dataframe_to_json_array(&df)
210 }
211 Value::Series(s) => {
212 Self::series_to_json_array(s)
214 }
215 }
216 }
217
218 #[cfg(not(target_arch = "wasm32"))]
220 fn dataframe_to_json_array(df: &polars::prelude::DataFrame) -> crate::Result<JsonValue> {
221 let height = df.height();
222 let columns = df.get_column_names();
223 let num_cols = columns.len();
224
225 let series_vec: crate::Result<Vec<_>> = columns
227 .iter()
228 .map(|col_name| {
229 df.column(col_name)
230 .map_err(|e| crate::error::operation_error(format!("Column access error: {e}")))
231 })
232 .collect();
233 let series_vec = series_vec?;
234
235 let rows: crate::Result<Vec<_>> = {
237 #[cfg(not(target_arch = "wasm32"))]
238 {
239 if height > 10_000 {
240 (0..height)
241 .into_par_iter()
242 .map(|row_idx| {
243 let mut row_obj = serde_json::Map::with_capacity(num_cols);
244
245 for (col_idx, col_name) in columns.iter().enumerate() {
246 let series = &series_vec[col_idx];
247 let value = Self::series_value_to_json(
248 series.as_materialized_series(),
249 row_idx,
250 )?;
251 row_obj.insert((*col_name).to_string(), value);
252 }
253
254 Ok(JsonValue::Object(row_obj))
255 })
256 .collect()
257 } else {
258 (0..height)
259 .map(|row_idx| {
260 let mut row_obj = serde_json::Map::with_capacity(num_cols);
261
262 for (col_idx, col_name) in columns.iter().enumerate() {
263 let series = &series_vec[col_idx];
264 let value = Self::series_value_to_json(
265 series.as_materialized_series(),
266 row_idx,
267 )?;
268 row_obj.insert((*col_name).to_string(), value);
269 }
270
271 Ok(JsonValue::Object(row_obj))
272 })
273 .collect()
274 }
275 }
276 #[cfg(target_arch = "wasm32")]
277 {
278 (0..height)
279 .map(|row_idx| {
280 let mut row_obj = serde_json::Map::with_capacity(num_cols);
281
282 for (col_idx, col_name) in columns.iter().enumerate() {
283 let series = &series_vec[col_idx];
284 let value = Self::series_value_to_json(
285 series.as_materialized_series(),
286 row_idx,
287 )?;
288 row_obj.insert((*col_name).to_string(), value);
289 }
290
291 Ok(JsonValue::Object(row_obj))
292 })
293 .collect()
294 }
295 };
296
297 Ok(JsonValue::Array(rows?))
298 }
299
300 #[cfg(target_arch = "wasm32")]
302 fn dataframe_to_json_array(df: &polars::prelude::DataFrame) -> crate::Result<JsonValue> {
303 let height = df.height();
304 let columns = df.get_column_names();
305 let num_cols = columns.len();
306
307 let series_vec: crate::Result<Vec<_>> = columns
309 .iter()
310 .map(|col_name| {
311 df.column(col_name)
312 .map_err(|e| crate::error::operation_error(format!("Column access error: {e}")))
313 })
314 .collect();
315 let series_vec = series_vec?;
316
317 let rows: crate::Result<Vec<_>> = (0..height)
318 .map(|row_idx| {
319 let mut row_obj = serde_json::Map::with_capacity(num_cols);
320
321 for (col_idx, col_name) in columns.iter().enumerate() {
322 let series = &series_vec[col_idx];
323 let value =
324 Self::series_value_to_json(series.as_materialized_series(), row_idx)?;
325 row_obj.insert((*col_name).to_string(), value);
326 }
327
328 Ok(JsonValue::Object(row_obj))
329 })
330 .collect();
331
332 Ok(JsonValue::Array(rows?))
333 }
334
335 fn series_to_json_array(series: &polars::prelude::Series) -> crate::Result<JsonValue> {
337 let len = series.len();
338 let mut values = Vec::with_capacity(len);
339
340 for i in 0..len {
341 let value = Self::series_value_to_json(series, i)?;
342 values.push(value);
343 }
344
345 Ok(JsonValue::Array(values))
346 }
347
348 fn series_value_to_json(
350 series: &polars::prelude::Series,
351 index: usize,
352 ) -> crate::Result<JsonValue> {
353 use polars::prelude::DataType;
354
355 if series.is_null().get(index).unwrap_or(false) {
356 return Ok(JsonValue::Null);
357 }
358
359 match series.dtype() {
360 DataType::Boolean => {
361 let val = series
362 .bool()
363 .map_err(|e| {
364 crate::error::operation_error(format!("Boolean access error: {e}"))
365 })?
366 .get(index);
367 Ok(JsonValue::Bool(val.unwrap_or(false)))
368 }
369 DataType::Int8 | DataType::Int16 | DataType::Int32 | DataType::Int64 => {
370 let val = series
371 .i64()
372 .map_err(|e| crate::error::operation_error(format!("Int access error: {e}")))?
373 .get(index);
374 Ok(JsonValue::Number(JsonNumber::from(val.unwrap_or(0))))
375 }
376 DataType::UInt8 | DataType::UInt16 | DataType::UInt32 | DataType::UInt64 => {
377 let val = series
378 .u64()
379 .map_err(|e| crate::error::operation_error(format!("UInt access error: {e}")))?
380 .get(index);
381 Ok(JsonValue::Number(JsonNumber::from(val.unwrap_or(0))))
382 }
383 DataType::Float32 | DataType::Float64 => {
384 let val = series
385 .f64()
386 .map_err(|e| crate::error::operation_error(format!("Float access error: {e}")))?
387 .get(index);
388 JsonNumber::from_f64(val.unwrap_or(0.0))
389 .map(JsonValue::Number)
390 .ok_or_else(|| crate::error::operation_error("Invalid float value"))
391 }
392 DataType::String => {
393 let val = series
394 .str()
395 .map_err(|e| {
396 crate::error::operation_error(format!("String access error: {e}"))
397 })?
398 .get(index);
399 Ok(JsonValue::String(val.unwrap_or("").to_string()))
400 }
401 DataType::Binary => {
402 let val = series
403 .binary()
404 .map_err(|e| {
405 crate::error::operation_error(format!("Binary access error: {e}"))
406 })?
407 .get(index);
408 if let Some(bytes) = val {
410 use base64::{engine::general_purpose, Engine as _};
411 Ok(JsonValue::String(general_purpose::STANDARD.encode(bytes)))
412 } else {
413 Ok(JsonValue::Null)
414 }
415 }
416 DataType::Date => {
417 let val = series
418 .date()
419 .map_err(|e| crate::error::operation_error(format!("Date access error: {e}")))?
420 .phys
421 .get(index);
422 if let Some(days) = val {
423 let epoch = chrono::NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
424 let actual_date = epoch + chrono::Duration::days(i64::from(days));
425 Ok(JsonValue::String(
426 actual_date.format("%Y-%m-%d").to_string(),
427 ))
428 } else {
429 Ok(JsonValue::Null)
430 }
431 }
432 DataType::Datetime(_, _) => {
433 let val = series
434 .datetime()
435 .map_err(|e| {
436 crate::error::operation_error(format!("Datetime access error: {e}"))
437 })?
438 .phys
439 .get(index);
440 if let Some(ns) = val {
441 let secs = ns / 1_000_000_000;
442 #[allow(clippy::cast_sign_loss)]
443 let nsecs = (ns % 1_000_000_000) as u32;
444 let dt = chrono::DateTime::from_timestamp(secs, nsecs)
445 .unwrap()
446 .naive_utc();
447 Ok(JsonValue::String(
448 dt.format("%Y-%m-%d %H:%M:%S%.f").to_string(),
449 ))
450 } else {
451 Ok(JsonValue::Null)
452 }
453 }
454 _ => Err(crate::error::operation_error(format!(
455 "Unsupported series type: {:?}",
456 series.dtype()
457 ))),
458 }
459 }
460
461 pub fn from_json(json: JsonValue) -> Self {
463 match json {
464 JsonValue::Null => Value::Null,
465 JsonValue::Bool(b) => Value::Bool(b),
466 JsonValue::Number(n) => {
467 if let Some(i) = n.as_i64() {
468 Value::Int(i)
469 } else if let Some(f) = n.as_f64() {
470 Value::Float(f)
471 } else {
472 Value::Null }
474 }
475 JsonValue::String(s) => {
476 if let Ok(bi) = s.parse::<num_bigint::BigInt>() {
478 return Value::BigInt(bi);
479 }
480 Value::String(s)
481 }
482 JsonValue::Array(arr) => {
483 let values = arr.into_iter().map(Value::from_json).collect();
484 Value::Array(values)
485 }
486 JsonValue::Object(obj) => {
487 let map = obj
488 .into_iter()
489 .map(|(k, v)| (k, Value::from_json(v)))
490 .collect();
491 Value::Object(map)
492 }
493 }
494 }
495
496 pub fn to_dataframe(&self) -> crate::Result<polars::prelude::DataFrame> {
498 match self {
499 Value::DataFrame(df) => Ok(df.clone()),
500 Value::LazyFrame(lf) => lf.clone().collect().map_err(|e| {
501 crate::error::operation_error(format!("LazyFrame collect error: {e}"))
502 }),
503 Value::Array(arr) => {
504 if arr.is_empty() {
506 return Ok(DataFrame::empty());
507 }
508
509 let Value::Object(first_obj) = &arr[0] else {
511 return Err(crate::error::operation_error(
512 "Cannot convert array to DataFrame: not all elements are objects",
513 ));
514 };
515
516 let columns: Vec<String> = first_obj.keys().cloned().collect();
517 let num_rows = arr.len();
518 let num_cols = columns.len();
519
520 let mut column_data: Vec<Vec<AnyValue>> = Vec::with_capacity(num_cols);
523 for _ in 0..num_cols {
524 column_data.push(Vec::with_capacity(num_rows));
525 }
526
527 for value in arr {
529 match value {
530 Value::Object(obj) => {
531 for (col_idx, col) in columns.iter().enumerate() {
532 let val = obj.get(col).unwrap_or(&Value::Null);
533 let any_val = Self::value_to_any_value(val)?;
534 column_data[col_idx].push(any_val);
536 }
537 }
538 _ => {
539 return Err(crate::error::operation_error(
540 "Cannot convert array to DataFrame: not all elements are objects",
541 ));
542 }
543 }
544 }
545
546 let mut series_vec = Vec::with_capacity(num_cols);
548 for (col_idx, col_name) in columns.into_iter().enumerate() {
549 let values = std::mem::take(&mut column_data[col_idx]);
550 let series = Series::new(col_name.into(), values);
551 series_vec.push(series.into());
552 }
553
554 DataFrame::new(series_vec).map_err(|e| {
555 crate::error::operation_error(format!("DataFrame creation error: {e}"))
556 })
557 }
558 _ => Err(crate::error::operation_error(format!(
559 "Cannot convert {} to DataFrame",
560 self.type_name()
561 ))),
562 }
563 }
564
565 fn value_to_any_value(value: &Value) -> crate::Result<polars::prelude::AnyValue<'_>> {
567 match value {
568 Value::Null => Ok(AnyValue::Null),
569 Value::Bool(b) => Ok(AnyValue::Boolean(*b)),
570 Value::Int(i) => Ok(AnyValue::Int64(*i)),
571 Value::BigInt(_) => Err(crate::error::operation_error(
572 "Cannot convert BigInt to AnyValue",
573 )),
574 Value::Float(f) => Ok(AnyValue::Float64(*f)),
575 Value::String(s) => Ok(AnyValue::String(s)),
576 _ => Err(crate::error::operation_error(format!(
577 "Cannot convert {} to AnyValue",
578 value.type_name()
579 ))),
580 }
581 }
582
583 #[must_use]
585 pub fn len(&self) -> Option<usize> {
586 match self {
587 Value::Array(arr) => Some(arr.len()),
588 Value::String(s) => Some(s.len()),
589 Value::DataFrame(df) => Some(df.height()),
590 Value::Series(s) => Some(s.len()),
591 _ => None,
592 }
593 }
594
595 #[must_use]
597 pub fn is_empty(&self) -> bool {
598 self.len() == Some(0)
599 }
600
601 pub fn index(&self, idx: i64) -> crate::Result<Value> {
603 match self {
604 Value::Array(arr) => {
605 #[allow(clippy::cast_possible_wrap)]
606 let len = arr.len() as i64;
607 let index = if idx < 0 { len + idx } else { idx };
608
609 if index >= 0 && index < len {
610 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
611 Ok(arr[index as usize].clone())
612 } else {
613 Ok(Value::Null)
614 }
615 }
616 Value::String(s) => {
617 let byte_len = s.len();
620
621 if byte_len == 0 {
623 return Ok(Value::Null);
624 }
625
626 if s.is_ascii() {
628 let bytes = s.as_bytes();
629 #[allow(clippy::cast_possible_wrap)]
630 let len = bytes.len() as i64;
631 let index = if idx < 0 { len + idx } else { idx };
632
633 if index >= 0 && index < len {
634 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
635 let ch = bytes[index as usize] as char;
636 Ok(Value::String(ch.to_string()))
637 } else {
638 Ok(Value::Null)
639 }
640 } else {
641 #[allow(clippy::cast_possible_wrap)]
644 let char_count = s.chars().count() as i64;
645 let index = if idx < 0 { char_count + idx } else { idx };
646
647 if index >= 0 && index < char_count {
648 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
649 if let Some(ch) = s.chars().nth(index as usize) {
650 Ok(Value::String(ch.to_string()))
651 } else {
652 Ok(Value::Null)
653 }
654 } else {
655 Ok(Value::Null)
656 }
657 }
658 }
659 Value::DataFrame(df) => {
660 #[allow(clippy::cast_possible_wrap)]
661 let len = df.height() as i64;
662 let index = if idx < 0 { len + idx } else { idx };
663
664 if index >= 0 && index < len {
665 let mut row_obj = HashMap::new();
667 for col_name in df.get_column_names() {
668 let series = df.column(col_name).map_err(|e| {
669 crate::error::operation_error(format!("Column access error: {e}"))
670 })?;
671 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
672 let value = Self::series_value_to_json(
673 series.as_materialized_series(),
674 index as usize,
675 )?;
676 row_obj.insert(col_name.to_string(), Value::from_json(value));
677 }
678 Ok(Value::Object(row_obj))
679 } else {
680 Ok(Value::Null)
681 }
682 }
683 _ => Err(crate::error::operation_error(format!(
684 "Cannot index into {}",
685 self.type_name()
686 ))),
687 }
688 }
689
690 pub fn field(&self, key: &str) -> crate::Result<Value> {
692 match self {
693 Value::Null => Ok(Value::Null),
694 Value::Object(obj) => Ok(obj.get(key).cloned().unwrap_or(Value::Null)),
695 Value::Array(arr) => {
696 let mut result = Vec::new();
697 for item in arr {
698 result.push(item.field(key)?);
699 }
700 Ok(Value::Array(result))
701 }
702 Value::DataFrame(df) => {
703 match df.column(key) {
705 Ok(series) => Ok(Value::Series(series.as_materialized_series().clone())),
706 Err(_) => Ok(Value::Null),
707 }
708 }
709 _ => Err(crate::error::operation_error(format!(
710 "Cannot access field '{}' on {}",
711 key,
712 self.type_name()
713 ))),
714 }
715 }
716
717 pub fn field_path(&self, fields: &[&str]) -> crate::Result<Value> {
719 let mut result = self.clone();
720 for &field in fields {
721 result = result.field(field)?;
722 }
723 Ok(result)
724 }
725}
726
727impl PartialEq<&Value> for Value {
728 fn eq(&self, other: &&Value) -> bool {
729 self == *other
730 }
731}
732
733impl PartialEq<Value> for &Value {
734 fn eq(&self, other: &Value) -> bool {
735 *self == other
736 }
737}
738
739impl PartialEq for Value {
740 fn eq(&self, other: &Self) -> bool {
741 match (self, other) {
742 (Value::Null, Value::Null) => true,
743 (Value::Bool(a), Value::Bool(b)) => a == b,
744 (Value::Int(a), Value::Int(b)) => a == b,
745 (Value::BigInt(a), Value::BigInt(b)) => a == b,
746 (Value::Float(a), Value::Float(b)) => a == b,
747 (Value::String(a), Value::String(b)) => a == b,
748 (Value::Array(a), Value::Array(b)) => a == b,
749 (Value::Object(a), Value::Object(b)) => a == b,
750 (Value::DataFrame(_), Value::DataFrame(_)) => false,
752 (Value::Series(_), Value::Series(_)) => false,
754 #[allow(clippy::cast_precision_loss)]
756 (Value::Int(a), Value::Float(b)) => *a as f64 == *b,
757 #[allow(clippy::cast_precision_loss)]
758 (Value::Float(a), Value::Int(b)) => *a == *b as f64,
759 #[cfg(not(target_arch = "wasm32"))]
760 (Value::Int(a), Value::BigInt(b)) => num_bigint::BigInt::from(*a) == *b,
761 #[cfg(not(target_arch = "wasm32"))]
762 (Value::BigInt(a), Value::Int(b)) => *a == num_bigint::BigInt::from(*b),
763 _ => false,
765 }
766 }
767}
768
769impl std::fmt::Display for Value {
770 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
771 match self {
772 Value::Null => write!(f, "null"),
773 Value::Bool(b) => write!(f, "{b}"),
774 Value::Int(i) => write!(f, "{i}"),
775 Value::BigInt(bi) => write!(f, "{bi}"),
776 Value::Float(fl) => write!(f, "{fl}"),
777 Value::String(s) => write!(f, "\"{s}\""),
778 Value::Array(arr) => {
779 write!(f, "[")?;
780 for (i, item) in arr.iter().enumerate() {
781 if i > 0 {
782 write!(f, ", ")?;
783 }
784 write!(f, "{item}")?;
785 }
786 write!(f, "]")
787 }
788 Value::Object(obj) => {
789 write!(f, "{{")?;
790 for (i, (key, value)) in obj.iter().enumerate() {
791 if i > 0 {
792 write!(f, ", ")?;
793 }
794 write!(f, "\"{key}\": {value}")?;
795 }
796 write!(f, "}}")
797 }
798 Value::DataFrame(df) => {
799 write!(
800 f,
801 "DataFrame({} rows × {} columns)",
802 df.height(),
803 df.width()
804 )
805 }
806 Value::LazyFrame(_) => write!(f, "LazyFrame"),
807 Value::Series(s) => write!(f, "Series[{}]({} values)", s.dtype(), s.len()),
808 }
809 }
810}
811
812impl serde::Serialize for Value {
813 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
814 where
815 S: serde::Serializer,
816 {
817 match self {
818 Value::Null => serializer.serialize_none(),
819 Value::Bool(b) => serializer.serialize_bool(*b),
820 Value::Int(i) => serializer.serialize_i64(*i),
821 Value::BigInt(bi) => bi.serialize(serializer),
822 Value::Float(f) => serializer.serialize_f64(*f),
823 Value::String(s) => serializer.serialize_str(s),
824 Value::Array(arr) => {
825 let mut seq = serializer.serialize_seq(Some(arr.len()))?;
826 for item in arr {
827 seq.serialize_element(item)?;
828 }
829 seq.end()
830 }
831 Value::Object(obj) => {
832 let mut map = serializer.serialize_map(Some(obj.len()))?;
833 for (key, value) in obj {
834 map.serialize_entry(key, value)?;
835 }
836 map.end()
837 }
838 Value::DataFrame(df) => {
839 let mut map = serializer.serialize_map(Some(3))?;
841 map.serialize_entry("type", "DataFrame")?;
842 map.serialize_entry("shape", &vec![df.height(), df.width()])?;
843 map.serialize_entry("columns", &df.get_column_names())?;
844 map.end()
845 }
846 Value::LazyFrame(_) => {
847 let mut map = serializer.serialize_map(Some(1))?;
848 map.serialize_entry("type", "LazyFrame")?;
849 map.end()
850 }
851 Value::Series(s) => {
852 let mut map = serializer.serialize_map(Some(3))?;
854 map.serialize_entry("type", "Series")?;
855 map.serialize_entry("name", s.name())?;
856 map.serialize_entry("dtype", &s.dtype().to_string())?;
857 map.end()
858 }
859 }
860 }
861}
862
863#[must_use]
865#[allow(clippy::needless_pass_by_value)]
866pub fn value_from_any_value(av: polars::prelude::AnyValue<'_>) -> Option<Value> {
867 match av {
868 AnyValue::Null => Some(Value::Null),
869 AnyValue::Boolean(b) => Some(Value::Bool(b)),
870 AnyValue::String(s) => Some(Value::String(s.to_string())),
871 AnyValue::Int8(i) => Some(Value::Int(i64::from(i))),
872 AnyValue::Int16(i) => Some(Value::Int(i64::from(i))),
873 AnyValue::Int32(i) => Some(Value::Int(i64::from(i))),
874 AnyValue::Int64(i) => Some(Value::Int(i)),
875 AnyValue::UInt8(i) => Some(Value::Int(i64::from(i))),
876 AnyValue::UInt16(i) => Some(Value::Int(i64::from(i))),
877 AnyValue::UInt32(i) => Some(Value::Int(i64::from(i))),
878 #[allow(clippy::cast_possible_wrap)]
879 AnyValue::UInt64(i) => Some(Value::Int(i as i64)),
880 AnyValue::Float32(f) => Some(Value::Float(f64::from(f))),
881 AnyValue::Float64(f) => Some(Value::Float(f)),
882 _ => None,
883 }
884}
885
886pub fn df_row_to_value(df: &polars::prelude::DataFrame, row_idx: usize) -> crate::Result<Value> {
888 let mut obj = HashMap::new();
889
890 for col_name in df.get_column_names() {
891 let series = df
892 .column(col_name)
893 .map_err(|e| crate::error::operation_error(format!("Failed to get column: {e}")))?;
894 let value = series_value_at(series.as_materialized_series(), row_idx)?;
895 obj.insert(col_name.to_string(), value);
896 }
897
898 Ok(Value::Object(obj))
899}
900
901fn series_value_at(series: &polars::prelude::Series, idx: usize) -> crate::Result<Value> {
903 if idx >= series.len() {
904 return Ok(Value::Null);
905 }
906
907 if series.is_null().get(idx).unwrap_or(false) {
908 return Ok(Value::Null);
909 }
910
911 match series.dtype() {
912 DataType::Boolean => {
913 let val = series
914 .bool()
915 .map_err(|e| crate::error::operation_error(format!("Boolean access error: {e}")))?
916 .get(idx);
917 Ok(Value::Bool(val.unwrap_or(false)))
918 }
919 DataType::Int8 | DataType::Int16 | DataType::Int32 | DataType::Int64 => {
920 let val = series
921 .i64()
922 .map_err(|e| crate::error::operation_error(format!("Int access error: {e}")))?
923 .get(idx);
924 Ok(Value::Int(val.unwrap_or(0)))
925 }
926 DataType::UInt8 | DataType::UInt16 | DataType::UInt32 | DataType::UInt64 => {
927 let val = series
928 .u64()
929 .map_err(|e| crate::error::operation_error(format!("UInt access error: {e}")))?
930 .get(idx);
931 #[allow(clippy::cast_possible_wrap)]
932 Ok(Value::Int(val.unwrap_or(0) as i64))
933 }
934 DataType::Float32 | DataType::Float64 => {
935 let val = series
936 .f64()
937 .map_err(|e| crate::error::operation_error(format!("Float access error: {e}")))?
938 .get(idx);
939 Ok(Value::Float(val.unwrap_or(0.0)))
940 }
941 DataType::String => {
942 let val = series
943 .str()
944 .map_err(|e| crate::error::operation_error(format!("String access error: {e}")))?
945 .get(idx);
946 Ok(Value::String(val.unwrap_or("").to_string()))
947 }
948 DataType::Date => {
949 let val = series
950 .date()
951 .map_err(|e| crate::error::operation_error(format!("Date access error: {e}")))?
952 .phys
953 .get(idx);
954 if let Some(days) = val {
955 let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
956 let actual_date = epoch + Duration::days(i64::from(days));
957 Ok(Value::String(actual_date.format("%Y-%m-%d").to_string()))
958 } else {
959 Ok(Value::Null)
960 }
961 }
962 DataType::Datetime(_, _) => {
963 let val = series
964 .datetime()
965 .map_err(|e| crate::error::operation_error(format!("Datetime access error: {e}")))?
966 .phys
967 .get(idx);
968 if let Some(ns) = val {
969 let secs = ns / 1_000_000_000;
970 #[allow(clippy::cast_sign_loss)]
971 let nsecs = (ns % 1_000_000_000) as u32;
972 let dt = DateTime::from_timestamp(secs, nsecs).unwrap().naive_utc();
973 Ok(Value::String(dt.format("%Y-%m-%d %H:%M:%S%.f").to_string()))
974 } else {
975 Ok(Value::Null)
976 }
977 }
978 _ => Ok(Value::Null), }
980}
981
982#[must_use]
984pub fn is_truthy(v: &Value) -> bool {
985 match v {
986 Value::Null => false,
987 Value::Bool(b) => *b,
988 Value::Int(i) => *i != 0,
989 Value::BigInt(bi) => !bi.is_zero(),
990 Value::Float(f) => *f != 0.0 && !f.is_nan(),
991 Value::String(s) => !s.is_empty(),
992 Value::Array(a) => !a.is_empty(),
993 Value::Object(o) => !o.is_empty(),
994 Value::DataFrame(df) => df.height() > 0,
995 Value::Series(s) => !s.is_empty(),
996 Value::LazyFrame(_) => true, }
998}
999
1000#[cfg(test)]
1001mod tests {
1002 use super::*;
1003 use num_bigint::BigInt;
1004
1005 use serde_json::json;
1006
1007 #[test]
1008 fn test_value_creation() {
1009 assert_eq!(Value::null(), Value::Null);
1010 assert_eq!(Value::bool(true), Value::Bool(true));
1011 assert_eq!(Value::bool(false), Value::Bool(false));
1012 assert_eq!(Value::int(42), Value::Int(42));
1013 assert_eq!(Value::int(-1), Value::Int(-1));
1014 assert_eq!(
1015 Value::bigint(BigInt::from(123456789012345678901234567890i128)),
1016 Value::BigInt(BigInt::from(123456789012345678901234567890i128))
1017 );
1018 assert_eq!(
1019 Value::float(std::f64::consts::PI),
1020 Value::Float(std::f64::consts::PI)
1021 );
1022 assert_eq!(Value::float(-2.5), Value::Float(-2.5));
1023 assert_eq!(Value::string("hello"), Value::String("hello".to_string()));
1024 assert_eq!(Value::string(""), Value::String("".to_string()));
1025
1026 let arr = vec![Value::int(1), Value::int(2)];
1027 assert_eq!(Value::array(arr.clone()), Value::Array(arr));
1028
1029 let obj = HashMap::from([("key".to_string(), Value::string("value"))]);
1030 assert_eq!(Value::object(obj.clone()), Value::Object(obj));
1031
1032 let df = DataFrame::new(vec![Series::new("a".into(), vec![1, 2, 3]).into()]).unwrap();
1033 let df_val = Value::dataframe(df.clone());
1034 assert!(df_val.is_dataframe());
1035
1036 let lf = df.clone().lazy();
1037 let lf_val = Value::lazy_frame(lf.clone());
1038 assert!(lf_val.is_lazy_frame());
1039
1040 let series = Series::new("test".into(), vec![1, 2, 3]);
1041 let series_val = Value::series(series.clone());
1042 assert!(series_val.is_series());
1043 }
1044
1045 #[test]
1046 fn test_value_is_methods() {
1047 let df = DataFrame::new(vec![Series::new("a".into(), vec![1, 2, 3]).into()]).unwrap();
1048 let lf = df.clone().lazy();
1049 let series = Series::new("test".into(), vec![1, 2, 3]);
1050
1051 assert!(Value::Null.is_null());
1052 assert!(!Value::int(1).is_null());
1053
1054 assert!(Value::dataframe(df.clone()).is_dataframe());
1055 assert!(!Value::int(1).is_dataframe());
1056
1057 assert!(Value::lazy_frame(lf.clone()).is_lazy_frame());
1058 assert!(!Value::int(1).is_lazy_frame());
1059
1060 assert!(Value::series(series.clone()).is_series());
1061 assert!(!Value::int(1).is_series());
1062
1063 assert!(is_truthy(&Value::Bool(true)));
1064 assert!(!is_truthy(&Value::Bool(false)));
1065 assert!(is_truthy(&Value::int(1)));
1066 assert!(!is_truthy(&Value::int(0)));
1067 assert!(is_truthy(&Value::string("hello")));
1068 assert!(!is_truthy(&Value::string("")));
1069 assert!(is_truthy(&Value::array(vec![Value::int(1)])));
1070 assert!(!is_truthy(&Value::array(vec![])));
1071 assert!(is_truthy(&Value::object(HashMap::from([(
1072 "k".to_string(),
1073 Value::int(1)
1074 )]))));
1075 assert!(!is_truthy(&Value::object(HashMap::new())));
1076 assert!(is_truthy(&Value::dataframe(df)));
1077 assert!(is_truthy(&Value::series(series)));
1078 assert!(is_truthy(&Value::lazy_frame(lf)));
1079 }
1080
1081 #[test]
1082 fn test_value_len_and_empty() {
1083 let df = DataFrame::new(vec![Series::new("a".into(), vec![1, 2, 3]).into()]).unwrap();
1084 let empty_df = DataFrame::empty();
1085 let series = Series::new("test".into(), vec![1, 2, 3]);
1086 let empty_series = Series::new("empty".into(), Vec::<i32>::new());
1087 let lf = df.clone().lazy();
1088
1089 assert_eq!(Value::Null.len(), None);
1090 assert_eq!(Value::int(1).len(), None);
1091 assert_eq!(Value::string("hello").len(), Some(5));
1092 assert_eq!(Value::string("").len(), Some(0));
1093 assert_eq!(
1094 Value::array(vec![Value::int(1), Value::int(2)]).len(),
1095 Some(2)
1096 );
1097 assert_eq!(Value::array(vec![]).len(), Some(0));
1098 assert_eq!(Value::dataframe(df.clone()).len(), Some(3));
1099 assert_eq!(Value::dataframe(empty_df.clone()).len(), Some(0));
1100 assert_eq!(Value::series(series.clone()).len(), Some(3));
1101 assert_eq!(Value::series(empty_series.clone()).len(), Some(0));
1102 assert_eq!(Value::lazy_frame(lf.clone()).len(), None);
1103
1104 assert!(Value::string("").is_empty());
1105 assert!(Value::array(vec![]).is_empty());
1106 assert!(Value::dataframe(empty_df).is_empty());
1107 assert!(Value::series(empty_series).is_empty());
1108 assert!(!Value::string("a").is_empty());
1109 assert!(!Value::array(vec![Value::int(1)]).is_empty());
1110 assert!(!Value::dataframe(df).is_empty());
1111 assert!(!Value::series(series).is_empty());
1112 assert!(!Value::lazy_frame(lf).is_empty());
1113 assert!(!Value::Null.is_empty()); }
1115
1116 #[test]
1117 fn test_json_conversion_primitives() {
1118 let json = Value::Null.to_json().unwrap();
1120 assert_eq!(json, JsonValue::Null);
1121 assert_eq!(Value::from_json(json), Value::Null);
1122
1123 let json = Value::bool(true).to_json().unwrap();
1125 assert_eq!(json, JsonValue::Bool(true));
1126 assert_eq!(Value::from_json(json), Value::bool(true));
1127
1128 let json = Value::int(42).to_json().unwrap();
1130 assert_eq!(json, JsonValue::Number(JsonNumber::from(42)));
1131 assert_eq!(Value::from_json(json), Value::int(42));
1132
1133 let json = Value::float(std::f64::consts::PI).to_json().unwrap();
1135 assert_eq!(
1136 json,
1137 JsonValue::Number(JsonNumber::from_f64(std::f64::consts::PI).unwrap())
1138 );
1139 assert_eq!(Value::from_json(json), Value::float(std::f64::consts::PI));
1140
1141 let json = Value::string("hello").to_json().unwrap();
1143 assert_eq!(json, JsonValue::String("hello".to_string()));
1144 assert_eq!(Value::from_json(json), Value::string("hello"));
1145
1146 let big = BigInt::from(12345678901234567890u64);
1148 let json = Value::bigint(big.clone()).to_json().unwrap();
1149 assert_eq!(json, JsonValue::String(big.to_string()));
1150 assert_eq!(Value::from_json(json), Value::bigint(big));
1151 }
1152
1153 #[test]
1154 fn test_json_conversion_complex() {
1155 let arr = Value::array(vec![Value::int(1), Value::string("two"), Value::bool(true)]);
1157 let json = arr.to_json().unwrap();
1158 let expected = json!([1, "two", true]);
1159 assert_eq!(json, expected);
1160 assert_eq!(Value::from_json(json), arr);
1161
1162 let obj = Value::object(HashMap::from([
1164 ("name".to_string(), Value::string("Alice")),
1165 ("age".to_string(), Value::int(30)),
1166 ("active".to_string(), Value::bool(true)),
1167 ]));
1168 let json = obj.to_json().unwrap();
1169 let expected = json!({
1170 "name": "Alice",
1171 "age": 30,
1172 "active": true
1173 });
1174 assert_eq!(json, expected);
1175 assert_eq!(Value::from_json(json), obj);
1176
1177 let nested = Value::object(HashMap::from([
1179 (
1180 "data".to_string(),
1181 Value::array(vec![Value::int(1), Value::int(2)]),
1182 ),
1183 (
1184 "meta".to_string(),
1185 Value::object(HashMap::from([("count".to_string(), Value::int(2))])),
1186 ),
1187 ]));
1188 let json = nested.to_json().unwrap();
1189 let expected = json!({
1190 "data": [1, 2],
1191 "meta": {"count": 2}
1192 });
1193 assert_eq!(json, expected);
1194 assert_eq!(Value::from_json(json), nested);
1195 }
1196
1197 #[test]
1198 fn test_json_conversion_polars() {
1199 let df = DataFrame::new(vec![
1201 Series::new("name".into(), vec!["Alice", "Bob"]).into(),
1202 Series::new("age".into(), vec![30i64, 25i64]).into(),
1203 ])
1204 .unwrap();
1205 let value = Value::dataframe(df.clone());
1206 let json = value.to_json().unwrap();
1207 let expected = json!([
1208 {"name": "Alice", "age": 30},
1209 {"name": "Bob", "age": 25}
1210 ]);
1211 assert_eq!(json, expected);
1212
1213 let lf = df.lazy();
1215 let value = Value::lazy_frame(lf);
1216 let json = value.to_json().unwrap();
1217 assert_eq!(json, expected); let series = Series::new("ages".into(), vec![30i64, 25i64]);
1221 let value = Value::series(series);
1222 let json = value.to_json().unwrap();
1223 let expected_series = json!([30, 25]);
1224 assert_eq!(json, expected_series);
1225 }
1226
1227 #[test]
1228 fn test_json_conversion_edge_cases() {
1229 let nan_val = Value::float(f64::NAN);
1231 assert!(nan_val.to_json().is_err());
1232
1233 let json = JsonValue::String("999999999999999999999999999999".to_string());
1235 let value = Value::from_json(json);
1236 match value {
1237 Value::BigInt(_) => {}
1238 _ => panic!("Expected BigInt"),
1239 }
1240
1241 let json = JsonValue::String("not_a_number".to_string());
1243 let value = Value::from_json(json);
1244 assert_eq!(value, Value::string("not_a_number"));
1245 }
1246
1247 #[test]
1248 fn test_indexing_array() {
1249 let arr = Value::array(vec![Value::int(1), Value::int(2), Value::int(3)]);
1250
1251 assert_eq!(arr.index(0).unwrap(), Value::int(1));
1252 assert_eq!(arr.index(1).unwrap(), Value::int(2));
1253 assert_eq!(arr.index(2).unwrap(), Value::int(3));
1254 assert_eq!(arr.index(-1).unwrap(), Value::int(3));
1255 assert_eq!(arr.index(-2).unwrap(), Value::int(2));
1256 assert_eq!(arr.index(-3).unwrap(), Value::int(1));
1257 assert_eq!(arr.index(10).unwrap(), Value::Null);
1258 assert_eq!(arr.index(-10).unwrap(), Value::Null);
1259 }
1260
1261 #[test]
1262 fn test_indexing_string() {
1263 let s = Value::string("hello");
1264
1265 assert_eq!(s.index(0).unwrap(), Value::string("h"));
1266 assert_eq!(s.index(1).unwrap(), Value::string("e"));
1267 assert_eq!(s.index(4).unwrap(), Value::string("o"));
1268 assert_eq!(s.index(-1).unwrap(), Value::string("o"));
1269 assert_eq!(s.index(-2).unwrap(), Value::string("l"));
1270 assert_eq!(s.index(10).unwrap(), Value::Null);
1271 assert_eq!(s.index(-10).unwrap(), Value::Null);
1272 }
1273
1274 #[test]
1275 fn test_indexing_dataframe() {
1276 let df = DataFrame::new(vec![
1277 Series::new("name".into(), vec!["Alice", "Bob"]).into(),
1278 Series::new("age".into(), vec![30i64, 25i64]).into(),
1279 ])
1280 .unwrap();
1281 let val = Value::dataframe(df);
1282
1283 let row = val.index(0).unwrap();
1284 match row {
1285 Value::Object(obj) => {
1286 assert_eq!(obj.get("name"), Some(&Value::string("Alice")));
1287 assert_eq!(obj.get("age"), Some(&Value::int(30)));
1288 }
1289 _ => panic!("Expected object"),
1290 }
1291
1292 let row1 = val.index(1).unwrap();
1293 match row1 {
1294 Value::Object(obj) => {
1295 assert_eq!(obj.get("name"), Some(&Value::string("Bob")));
1296 assert_eq!(obj.get("age"), Some(&Value::int(25)));
1297 }
1298 _ => panic!("Expected object"),
1299 }
1300
1301 let null_row = val.index(10).unwrap();
1302 assert_eq!(null_row, Value::Null);
1303 }
1304
1305 #[test]
1306 fn test_indexing_invalid() {
1307 let obj = Value::object(HashMap::new());
1308 assert!(obj.index(0).is_err());
1309
1310 let null_val = Value::Null;
1311 assert!(null_val.index(0).is_err());
1312 }
1313
1314 #[test]
1315 fn test_field_access() {
1316 let obj = Value::object(HashMap::from([
1317 ("name".to_string(), Value::string("Bob")),
1318 ("age".to_string(), Value::int(25)),
1319 (
1320 "nested".to_string(),
1321 Value::object(HashMap::from([("inner".to_string(), Value::bool(true))])),
1322 ),
1323 ]));
1324
1325 assert_eq!(obj.field("name").unwrap(), Value::string("Bob"));
1326 assert_eq!(obj.field("age").unwrap(), Value::int(25));
1327 assert_eq!(obj.field("missing").unwrap(), Value::Null);
1328
1329 assert_eq!(
1331 obj.field_path(&["nested", "inner"]).unwrap(),
1332 Value::bool(true)
1333 );
1334 assert_eq!(obj.field_path(&["nested", "missing"]).unwrap(), Value::Null);
1335 assert_eq!(obj.field_path(&["missing", "field"]).unwrap(), Value::Null);
1336 }
1337
1338 #[test]
1339 fn test_field_access_array() {
1340 let arr = Value::array(vec![
1341 Value::object(HashMap::from([(
1342 "name".to_string(),
1343 Value::string("Alice"),
1344 )])),
1345 Value::object(HashMap::from([("name".to_string(), Value::string("Bob"))])),
1346 ]);
1347
1348 let result = arr.field("name").unwrap();
1349 match result {
1350 Value::Array(names) => {
1351 assert_eq!(names.len(), 2);
1352 assert_eq!(names[0], Value::string("Alice"));
1353 assert_eq!(names[1], Value::string("Bob"));
1354 }
1355 _ => panic!("Expected array"),
1356 }
1357 }
1358
1359 #[test]
1360 fn test_field_access_dataframe() {
1361 let df = DataFrame::new(vec![
1362 Series::new("name".into(), vec!["Alice", "Bob"]).into(),
1363 Series::new("age".into(), vec![30i64, 25i64]).into(),
1364 ])
1365 .unwrap();
1366 let val = Value::dataframe(df);
1367
1368 let name_series = val.field("name").unwrap();
1369 match name_series {
1370 Value::Series(s) => {
1371 assert_eq!(s.name(), "name");
1372 }
1373 _ => panic!("Expected series"),
1374 }
1375
1376 let missing = val.field("missing").unwrap();
1377 assert_eq!(missing, Value::Null);
1378 }
1379
1380 #[test]
1381 fn test_field_access_null() {
1382 let null_val = Value::Null;
1383 assert_eq!(null_val.field("any").unwrap(), Value::Null);
1384 }
1385
1386 #[test]
1387 fn test_type_names() {
1388 assert_eq!(Value::Null.type_name(), "null");
1389 assert_eq!(Value::Bool(true).type_name(), "boolean");
1390 assert_eq!(Value::Int(42).type_name(), "integer");
1391 assert_eq!(Value::BigInt(BigInt::from(42)).type_name(), "biginteger");
1392 assert_eq!(Value::Float(std::f64::consts::PI).type_name(), "float");
1393 assert_eq!(Value::String("test".to_string()).type_name(), "string");
1394 assert_eq!(Value::Array(vec![]).type_name(), "array");
1395 assert_eq!(Value::Object(HashMap::new()).type_name(), "object");
1396 }
1397
1398 #[test]
1399 fn test_equality() {
1400 assert_eq!(Value::int(42), Value::int(42));
1402 assert_eq!(
1403 Value::float(std::f64::consts::PI),
1404 Value::float(std::f64::consts::PI)
1405 );
1406 assert_eq!(
1407 Value::bigint(BigInt::from(42)),
1408 Value::bigint(BigInt::from(42))
1409 );
1410 assert_eq!(Value::string("hello"), Value::string("hello"));
1411 assert_eq!(Value::bool(true), Value::bool(true));
1412 assert_eq!(Value::Null, Value::Null);
1413
1414 assert_eq!(Value::int(42), Value::float(42.0));
1416 assert_eq!(Value::float(42.0), Value::int(42));
1417 assert_eq!(Value::int(42), Value::bigint(BigInt::from(42)));
1418 assert_eq!(Value::bigint(BigInt::from(42)), Value::int(42));
1419
1420 let arr1 = Value::array(vec![Value::int(1), Value::int(2)]);
1422 let arr2 = Value::array(vec![Value::int(1), Value::int(2)]);
1423 assert_eq!(arr1, arr2);
1424
1425 let obj1 = Value::object(HashMap::from([("a".to_string(), Value::int(1))]));
1426 let obj2 = Value::object(HashMap::from([("a".to_string(), Value::int(1))]));
1427 assert_eq!(obj1, obj2);
1428
1429 assert_ne!(Value::int(1), Value::int(2));
1431 assert_ne!(Value::int(1), Value::float(1.1));
1432 assert_ne!(Value::string("a"), Value::string("b"));
1433 assert_ne!(Value::bool(true), Value::bool(false));
1434
1435 let df = DataFrame::new(vec![Series::new("a".into(), vec![1, 2, 3]).into()]).unwrap();
1437 assert_ne!(Value::dataframe(df.clone()), Value::dataframe(df));
1438 let series = Series::new("test".into(), vec![1, 2, 3]);
1439 assert_ne!(Value::series(series.clone()), Value::series(series));
1440
1441 assert_ne!(Value::bigint(BigInt::from(42)), Value::float(42.0));
1443 }
1444
1445 #[test]
1446 fn test_serde() {
1447 let val = Value::int(42);
1449 let json = serde_json::to_string(&val).unwrap();
1450 assert_eq!(json, "42");
1451
1452 let arr = Value::array(vec![Value::int(1), Value::string("two")]);
1454 let json = serde_json::to_string(&arr).unwrap();
1455 assert_eq!(json, "[1,\"two\"]");
1456
1457 let obj = Value::object(HashMap::from([
1459 ("a".to_string(), Value::int(1)),
1460 ("b".to_string(), Value::string("x")),
1461 ]));
1462 let json = serde_json::to_string(&obj).unwrap();
1463 assert!(json.contains("\"a\":1"));
1465 assert!(json.contains("\"b\":\"x\""));
1466
1467 let df = DataFrame::new(vec![Series::new("name".into(), vec!["Alice"]).into()]).unwrap();
1469 let val = Value::dataframe(df);
1470 let json = serde_json::to_string(&val).unwrap();
1471 assert!(json.contains("\"type\":\"DataFrame\""));
1472 assert!(json.contains("\"shape\":[1,1]"));
1473 assert!(json.contains("\"columns\":[\"name\"]"));
1474 }
1475
1476 #[test]
1477 fn test_debug() {
1478 assert!(format!("{:?}", Value::Null).contains("Null"));
1479 assert!(format!("{:?}", Value::int(42)).contains("Int(42)"));
1480 assert!(format!("{:?}", Value::string("hello")).contains("String(\"hello\")"));
1481 assert!(format!("{:?}", Value::array(vec![Value::int(1)])).contains("Array([Int(1)]"));
1482 assert!(format!("{:?}", Value::object(HashMap::new())).contains("Object({})"));
1483 assert!(format!("{:?}", Value::dataframe(DataFrame::empty())).contains("DataFrame"));
1484 assert!(
1485 format!("{:?}", Value::series(Series::new("test".into(), vec![1]))).contains("Series")
1486 );
1487 }
1488
1489 #[test]
1490 #[allow(clippy::approx_constant)]
1491 fn test_display() {
1492 assert_eq!(format!("{}", Value::Null), "null");
1493 assert_eq!(format!("{}", Value::bool(true)), "true");
1494 assert_eq!(format!("{}", Value::int(42)), "42");
1495 assert_eq!(format!("{}", Value::bigint(BigInt::from(123))), "123");
1496 assert_eq!(format!("{}", Value::float(3.14)), "3.14");
1497 assert_eq!(format!("{}", Value::string("hello")), "\"hello\"");
1498
1499 let arr = Value::array(vec![Value::int(1), Value::string("two")]);
1500 assert_eq!(format!("{}", arr), "[1, \"two\"]");
1501
1502 let obj = Value::object(HashMap::from([
1503 ("a".to_string(), Value::int(1)),
1504 ("b".to_string(), Value::string("x")),
1505 ]));
1506 let display = format!("{}", obj);
1507 assert!(display.contains("\"a\": 1"));
1508 assert!(display.contains("\"b\": \"x\""));
1509 }
1510
1511 #[test]
1512 fn test_to_dataframe() {
1513 let data = Value::array(vec![
1515 Value::object(HashMap::from([
1516 ("name".to_string(), Value::string("Alice")),
1517 ("age".to_string(), Value::int(30)),
1518 ])),
1519 Value::object(HashMap::from([
1520 ("name".to_string(), Value::string("Bob")),
1521 ("age".to_string(), Value::int(25)),
1522 ])),
1523 ]);
1524
1525 let df = data.to_dataframe().unwrap();
1526 assert_eq!(df.height(), 2);
1527 assert_eq!(df.width(), 2);
1528 assert!(df
1529 .get_column_names()
1530 .contains(&&polars::datatypes::PlSmallStr::from("name")));
1531 assert!(df
1532 .get_column_names()
1533 .contains(&&polars::datatypes::PlSmallStr::from("age")));
1534
1535 let empty = Value::array(vec![]);
1537 let df = empty.to_dataframe().unwrap();
1538 assert_eq!(df.height(), 0);
1539
1540 let invalid = Value::array(vec![Value::int(1), Value::string("not object")]);
1542 assert!(invalid.to_dataframe().is_err());
1543
1544 let data = Value::array(vec![Value::object(HashMap::from([
1546 ("name".to_string(), Value::string("Alice")),
1547 ("big".to_string(), Value::bigint(BigInt::from(123))),
1548 ]))]);
1549 assert!(data.to_dataframe().is_err());
1550
1551 let df = DataFrame::new(vec![
1553 Series::new("name".into(), vec!["Alice", "Bob"]).into(),
1554 Series::new("age".into(), vec![30i64, 25i64]).into(),
1555 ])
1556 .unwrap();
1557 let val = Value::dataframe(df.clone());
1558 let df2 = val.to_dataframe().unwrap();
1559 assert_eq!(df2.height(), 2);
1560 assert_eq!(df2.width(), 2);
1561
1562 let lf = df.lazy();
1564 let val = Value::lazy_frame(lf);
1565 let df3 = val.to_dataframe().unwrap();
1566 assert_eq!(df3.height(), 2);
1567 assert_eq!(df3.width(), 2);
1568 }
1569
1570 #[test]
1571 #[allow(clippy::approx_constant)]
1572 fn test_value_from_any_value() {
1573 use polars::datatypes::AnyValue;
1574
1575 assert_eq!(value_from_any_value(AnyValue::Null), Some(Value::Null));
1576 assert_eq!(
1577 value_from_any_value(AnyValue::Boolean(true)),
1578 Some(Value::bool(true))
1579 );
1580 assert_eq!(
1581 value_from_any_value(AnyValue::Int64(42)),
1582 Some(Value::int(42))
1583 );
1584 assert_eq!(
1585 value_from_any_value(AnyValue::Float64(3.14)),
1586 Some(Value::float(3.14))
1587 );
1588 assert_eq!(
1589 value_from_any_value(AnyValue::String("hello")),
1590 Some(Value::string("hello"))
1591 );
1592
1593 assert_eq!(value_from_any_value(AnyValue::Date(0)), None);
1595 }
1596
1597 #[test]
1598 fn test_df_row_to_value() {
1599 let df = DataFrame::new(vec![
1600 Series::new("name".into(), vec!["Alice", "Bob"]).into(),
1601 Series::new("age".into(), vec![30i64, 25i64]).into(),
1602 ])
1603 .unwrap();
1604
1605 let row = df_row_to_value(&df, 0).unwrap();
1606 match row {
1607 Value::Object(obj) => {
1608 assert_eq!(obj.get("name"), Some(&Value::string("Alice")));
1609 assert_eq!(obj.get("age"), Some(&Value::int(30)));
1610 }
1611 _ => panic!("Expected object"),
1612 }
1613
1614 let out_of_bounds = df_row_to_value(&df, 10).unwrap();
1616 match out_of_bounds {
1617 Value::Object(obj) => {
1618 assert_eq!(obj.get("name"), Some(&Value::Null));
1619 assert_eq!(obj.get("age"), Some(&Value::Null));
1620 }
1621 _ => panic!("Expected object"),
1622 }
1623 }
1624
1625 #[test]
1626 fn test_series_value_at() {
1627 let series = Series::new("test".into(), vec![Some(1i64), None, Some(3i64)]);
1628
1629 assert_eq!(series_value_at(&series, 0).unwrap(), Value::int(1));
1630 assert_eq!(series_value_at(&series, 1).unwrap(), Value::Null);
1631 assert_eq!(series_value_at(&series, 2).unwrap(), Value::int(3));
1632
1633 assert_eq!(series_value_at(&series, 10).unwrap(), Value::Null);
1635 }
1636}