@@ -442,27 +442,26 @@ pub fn from_rows(
442
442
infer_schema ( pairs, infer_schema_length)
443
443
}
444
444
} ;
445
- let len = rows. len ( ) ;
446
- let it: Vec < Row > = ( 0 ..len)
445
+ let it: Vec < Row > = ( 0 ..rows. len ( ) )
447
446
. into_iter ( )
448
447
. map ( |idx| {
449
448
let obj = rows
450
449
. get :: < Object > ( idx as u32 )
451
450
. unwrap_or ( None )
452
451
. unwrap_or_else ( || env. create_object ( ) . unwrap ( ) ) ;
452
+
453
453
Row ( schema
454
454
. iter_fields ( )
455
455
. map ( |fld| {
456
- let dtype = fld. dtype ( ) . clone ( ) ;
457
- let key = fld. name ( ) ;
458
- if let Ok ( unknown) = obj. get ( key) {
459
- let av = match unknown {
460
- Some ( unknown) => unsafe {
461
- coerce_js_anyvalue ( unknown, dtype) . unwrap_or ( AnyValue :: Null )
462
- } ,
463
- None => AnyValue :: Null ,
464
- } ;
465
- av
456
+ let dtype: & DataType = fld. dtype ( ) ;
457
+ let key: & PlSmallStr = fld. name ( ) ;
458
+ if let Ok ( unknown) = obj. get :: < & polars:: prelude:: PlSmallStr , JsUnknown > ( key) {
459
+ match unknown {
460
+ Some ( unknown) => {
461
+ coerce_js_anyvalue ( unknown, dtype. clone ( ) ) . unwrap_or ( AnyValue :: Null )
462
+ }
463
+ _ => AnyValue :: Null ,
464
+ }
466
465
} else {
467
466
AnyValue :: Null
468
467
}
@@ -1620,61 +1619,79 @@ fn obj_to_pairs(rows: &Array, len: usize) -> impl '_ + Iterator<Item = Vec<(Stri
1620
1619
let len = std:: cmp:: min ( len, rows. len ( ) as usize ) ;
1621
1620
( 0 ..len) . map ( move |idx| {
1622
1621
let obj = rows. get :: < Object > ( idx as u32 ) . unwrap ( ) . unwrap ( ) ;
1623
-
1624
1622
let keys = Object :: keys ( & obj) . unwrap ( ) ;
1625
1623
keys. iter ( )
1626
1624
. map ( |key| {
1627
1625
let value = obj. get :: < _ , napi:: JsUnknown > ( & key) . unwrap_or ( None ) ;
1628
- let dtype = match value {
1629
- Some ( val) => {
1630
- let ty = val. get_type ( ) . unwrap ( ) ;
1631
- match ty {
1632
- ValueType :: Boolean => DataType :: Boolean ,
1633
- ValueType :: Number => DataType :: Float64 ,
1634
- ValueType :: String => DataType :: String ,
1635
- ValueType :: Object => {
1636
- if val. is_array ( ) . unwrap ( ) {
1637
- let arr: napi:: JsObject = unsafe { val. cast ( ) } ;
1638
- let len = arr. get_array_length ( ) . unwrap ( ) ;
1639
-
1640
- if len == 0 {
1641
- DataType :: List ( DataType :: Null . into ( ) )
1642
- } else {
1643
- // dont compare too many items, as it could be expensive
1644
- let max_take = std:: cmp:: min ( len as usize , 10 ) ;
1645
- let mut dtypes: Vec < DataType > =
1646
- Vec :: with_capacity ( len as usize ) ;
1647
-
1648
- for idx in 0 ..max_take {
1649
- let item: napi:: JsUnknown =
1650
- arr. get_element ( idx as u32 ) . unwrap ( ) ;
1651
- let ty = item. get_type ( ) . unwrap ( ) ;
1652
- let dt: Wrap < DataType > = ty. into ( ) ;
1653
- dtypes. push ( dt. 0 )
1654
- }
1655
- let dtype = coerce_data_type ( & dtypes) ;
1656
-
1657
- DataType :: List ( dtype. into ( ) )
1658
- }
1659
- } else if val. is_date ( ) . unwrap ( ) {
1660
- DataType :: Datetime ( TimeUnit :: Milliseconds , None )
1661
- } else {
1662
- DataType :: Struct ( vec ! [ ] )
1663
- }
1664
- }
1665
- ValueType :: BigInt => DataType :: UInt64 ,
1666
- _ => DataType :: Null ,
1667
- }
1668
- }
1669
- None => DataType :: Null ,
1670
- } ;
1671
- ( key. to_owned ( ) , dtype)
1626
+ ( key. to_owned ( ) , obj_to_type ( value) )
1672
1627
} )
1673
1628
. collect ( )
1674
1629
} )
1675
1630
}
1676
1631
1677
- unsafe fn coerce_js_anyvalue < ' a > ( val : JsUnknown , dtype : DataType ) -> JsResult < AnyValue < ' a > > {
1632
+ fn obj_to_type ( value : Option < JsUnknown > ) -> DataType {
1633
+ match value {
1634
+ Some ( val) => {
1635
+ let ty = val. get_type ( ) . unwrap ( ) ;
1636
+ match ty {
1637
+ ValueType :: Boolean => DataType :: Boolean ,
1638
+ ValueType :: Number => DataType :: Float64 ,
1639
+ ValueType :: BigInt => DataType :: UInt64 ,
1640
+ ValueType :: String => DataType :: String ,
1641
+ ValueType :: Object => {
1642
+ if val. is_array ( ) . unwrap ( ) {
1643
+ let arr: napi:: JsObject = unsafe { val. cast ( ) } ;
1644
+ let len = arr. get_array_length ( ) . unwrap ( ) ;
1645
+ if len == 0 {
1646
+ DataType :: List ( DataType :: Null . into ( ) )
1647
+ } else {
1648
+ // dont compare too many items, as it could be expensive
1649
+ let max_take = std:: cmp:: min ( len as usize , 10 ) ;
1650
+ let mut dtypes: Vec < DataType > = Vec :: with_capacity ( len as usize ) ;
1651
+
1652
+ for idx in 0 ..max_take {
1653
+ let item: napi:: JsUnknown = arr. get_element ( idx as u32 ) . unwrap ( ) ;
1654
+ let ty = item. get_type ( ) . unwrap ( ) ;
1655
+ let dt: Wrap < DataType > = ty. into ( ) ;
1656
+ dtypes. push ( dt. 0 )
1657
+ }
1658
+ let dtype = coerce_data_type ( & dtypes) ;
1659
+
1660
+ DataType :: List ( dtype. into ( ) )
1661
+ }
1662
+ } else if val. is_date ( ) . unwrap ( ) {
1663
+ DataType :: Datetime ( TimeUnit :: Milliseconds , None )
1664
+ } else {
1665
+ let inner_val: napi:: JsObject = unsafe { val. cast ( ) } ;
1666
+ let inner_keys = Object :: keys ( & inner_val) . unwrap ( ) ;
1667
+ let mut fldvec: Vec < Field > = Vec :: with_capacity ( inner_keys. len ( ) as usize ) ;
1668
+
1669
+ inner_keys. iter ( ) . for_each ( |key| {
1670
+ let inner_val = inner_val. get :: < _ , napi:: JsUnknown > ( & key) . unwrap ( ) ;
1671
+ let dtype = match inner_val. as_ref ( ) . unwrap ( ) . get_type ( ) . unwrap ( ) {
1672
+ ValueType :: Boolean => DataType :: Boolean ,
1673
+ ValueType :: Number => DataType :: Float64 ,
1674
+ ValueType :: BigInt => DataType :: UInt64 ,
1675
+ ValueType :: String => DataType :: String ,
1676
+ // determine struct type using a recursive func
1677
+ ValueType :: Object => obj_to_type ( inner_val) ,
1678
+ _ => DataType :: Null ,
1679
+ } ;
1680
+
1681
+ let fld = Field :: new ( key. into ( ) , dtype) ;
1682
+ fldvec. push ( fld) ;
1683
+ } ) ;
1684
+ DataType :: Struct ( fldvec)
1685
+ }
1686
+ }
1687
+ _ => DataType :: Null ,
1688
+ }
1689
+ }
1690
+ None => DataType :: Null ,
1691
+ }
1692
+ }
1693
+
1694
+ fn coerce_js_anyvalue < ' a > ( val : JsUnknown , dtype : DataType ) -> JsResult < AnyValue < ' a > > {
1678
1695
use DataType :: * ;
1679
1696
let vtype = val. get_type ( ) . unwrap ( ) ;
1680
1697
match ( vtype, dtype) {
@@ -1749,17 +1766,59 @@ unsafe fn coerce_js_anyvalue<'a>(val: JsUnknown, dtype: DataType) -> JsResult<An
1749
1766
}
1750
1767
( ValueType :: Object , DataType :: Datetime ( _, _) ) => {
1751
1768
if val. is_date ( ) ? {
1752
- let d: napi:: JsDate = val. cast ( ) ;
1769
+ let d: napi:: JsDate = unsafe { val. cast ( ) } ;
1753
1770
let d = d. value_of ( ) ?;
1754
1771
Ok ( AnyValue :: Datetime ( d as i64 , TimeUnit :: Milliseconds , None ) )
1755
1772
} else {
1756
1773
Ok ( AnyValue :: Null )
1757
1774
}
1758
1775
}
1759
1776
( ValueType :: Object , DataType :: List ( _) ) => {
1760
- let s = val. to_series ( ) ;
1777
+ let s = unsafe { val. to_series ( ) } ;
1761
1778
Ok ( AnyValue :: List ( s) )
1762
1779
}
1780
+ ( ValueType :: Object , DataType :: Struct ( fields) ) => {
1781
+ let number_of_fields: i8 = fields. len ( ) . try_into ( ) . map_err ( |e| {
1782
+ napi:: Error :: from_reason ( format ! (
1783
+ "the number of `fields` cannot be larger than i8::MAX {e:?}"
1784
+ ) )
1785
+ } ) ?;
1786
+
1787
+ let inner_val: napi:: JsObject = unsafe { val. cast ( ) } ;
1788
+ let mut val_vec: Vec < polars:: prelude:: AnyValue < ' _ > > =
1789
+ Vec :: with_capacity ( number_of_fields as usize ) ;
1790
+ fields. iter ( ) . for_each ( |fld| {
1791
+ let single_val = inner_val
1792
+ . get :: < _ , napi:: JsUnknown > ( & fld. name )
1793
+ . unwrap ( )
1794
+ . unwrap ( ) ;
1795
+ let vv = match & fld. dtype {
1796
+ DataType :: Boolean => {
1797
+ AnyValue :: Boolean ( single_val. coerce_to_bool ( ) . unwrap ( ) . get_value ( ) . unwrap ( ) )
1798
+ }
1799
+ DataType :: String => AnyValue :: from_js ( single_val) . expect ( "Expecting string" ) ,
1800
+ DataType :: Int16 => AnyValue :: Int16 (
1801
+ single_val. coerce_to_number ( ) . unwrap ( ) . get_int32 ( ) . unwrap ( ) as i16 ,
1802
+ ) ,
1803
+ DataType :: Int32 => {
1804
+ AnyValue :: Int32 ( single_val. coerce_to_number ( ) . unwrap ( ) . get_int32 ( ) . unwrap ( ) )
1805
+ }
1806
+ DataType :: Int64 => {
1807
+ AnyValue :: Int64 ( single_val. coerce_to_number ( ) . unwrap ( ) . get_int64 ( ) . unwrap ( ) )
1808
+ }
1809
+ DataType :: Float64 => AnyValue :: Float64 (
1810
+ single_val. coerce_to_number ( ) . unwrap ( ) . get_double ( ) . unwrap ( ) ,
1811
+ ) ,
1812
+ DataType :: Struct ( _) => {
1813
+ coerce_js_anyvalue ( single_val, fld. dtype . clone ( ) ) . unwrap ( )
1814
+ }
1815
+ _ => AnyValue :: Null ,
1816
+ } ;
1817
+ val_vec. push ( vv) ;
1818
+ } ) ;
1819
+
1820
+ Ok ( AnyValue :: StructOwned ( Box :: new ( ( val_vec, fields) ) ) )
1821
+ }
1763
1822
_ => Ok ( AnyValue :: Null ) ,
1764
1823
}
1765
1824
}
0 commit comments