@@ -217,6 +217,23 @@ impl LogicalType {
217
217
}
218
218
}
219
219
220
+ /// Make a `LogicalType` for `union`
221
+ pub fn union_type ( fields : & [ ( & str , LogicalType ) ] ) -> Self {
222
+ let keys: Vec < CString > = fields. iter ( ) . map ( |f| CString :: new ( f. 0 ) . unwrap ( ) ) . collect ( ) ;
223
+ let values: Vec < duckdb_logical_type > = fields. iter ( ) . map ( |it| it. 1 . ptr ) . collect ( ) ;
224
+ let name_ptrs = keys. iter ( ) . map ( |it| it. as_ptr ( ) ) . collect :: < Vec < * const c_char > > ( ) ;
225
+
226
+ unsafe {
227
+ Self {
228
+ ptr : duckdb_create_union_type (
229
+ values. as_slice ( ) . as_ptr ( ) . cast_mut ( ) ,
230
+ name_ptrs. as_slice ( ) . as_ptr ( ) . cast_mut ( ) ,
231
+ fields. len ( ) as idx_t ,
232
+ ) ,
233
+ }
234
+ }
235
+ }
236
+
220
237
/// Logical type ID
221
238
pub fn id ( & self ) -> LogicalTypeId {
222
239
let duckdb_type_id = unsafe { duckdb_get_type_id ( self . ptr ) } ;
@@ -227,16 +244,22 @@ impl LogicalType {
227
244
pub fn num_children ( & self ) -> usize {
228
245
match self . id ( ) {
229
246
LogicalTypeId :: Struct => unsafe { duckdb_struct_type_child_count ( self . ptr ) as usize } ,
247
+ LogicalTypeId :: Union => unsafe { duckdb_union_type_member_count ( self . ptr ) as usize } ,
230
248
LogicalTypeId :: List => 1 ,
231
249
_ => 0 ,
232
250
}
233
251
}
234
252
235
253
/// Logical type child name by idx
254
+ ///
255
+ /// Panics if the logical type is not a struct or union
236
256
pub fn child_name ( & self , idx : usize ) -> String {
237
- assert_eq ! ( self . id( ) , LogicalTypeId :: Struct ) ;
238
257
unsafe {
239
- let child_name_ptr = duckdb_struct_type_child_name ( self . ptr , idx as u64 ) ;
258
+ let child_name_ptr = match self . id ( ) {
259
+ LogicalTypeId :: Struct => duckdb_struct_type_child_name ( self . ptr , idx as u64 ) ,
260
+ LogicalTypeId :: Union => duckdb_union_type_member_name ( self . ptr , idx as u64 ) ,
261
+ _ => panic ! ( "not a struct or union" ) ,
262
+ } ;
240
263
let c_str = CString :: from_raw ( child_name_ptr) ;
241
264
let name = c_str. to_str ( ) . unwrap ( ) ;
242
265
name. to_string ( )
@@ -245,14 +268,20 @@ impl LogicalType {
245
268
246
269
/// Logical type child by idx
247
270
pub fn child ( & self , idx : usize ) -> Self {
248
- let c_logical_type = unsafe { duckdb_struct_type_child_type ( self . ptr , idx as u64 ) } ;
271
+ let c_logical_type = unsafe {
272
+ match self . id ( ) {
273
+ LogicalTypeId :: Struct => duckdb_struct_type_child_type ( self . ptr , idx as u64 ) ,
274
+ LogicalTypeId :: Union => duckdb_union_type_member_type ( self . ptr , idx as u64 ) ,
275
+ _ => panic ! ( "not a struct or union" ) ,
276
+ }
277
+ } ;
249
278
Self :: from ( c_logical_type)
250
279
}
251
280
}
252
281
253
282
#[ cfg( test) ]
254
283
mod test {
255
- use crate :: vtab :: LogicalType ;
284
+ use super :: { LogicalType , LogicalTypeId } ;
256
285
257
286
#[ test]
258
287
fn test_struct ( ) {
@@ -280,4 +309,21 @@ mod test {
280
309
assert_eq ! ( typ. decimal_width( ) , 0 ) ;
281
310
assert_eq ! ( typ. decimal_scale( ) , 0 ) ;
282
311
}
312
+
313
+ #[ test]
314
+ fn test_union_type ( ) {
315
+ let fields = & [
316
+ ( "hello" , LogicalType :: new ( LogicalTypeId :: Boolean ) ) ,
317
+ ( "world" , LogicalType :: new ( LogicalTypeId :: Integer ) ) ,
318
+ ] ;
319
+ let typ = LogicalType :: union_type ( fields) ;
320
+
321
+ assert_eq ! ( typ. num_children( ) , 2 ) ;
322
+
323
+ assert_eq ! ( typ. child_name( 0 ) , "hello" ) ;
324
+ assert_eq ! ( typ. child( 0 ) . id( ) , LogicalTypeId :: Boolean ) ;
325
+
326
+ assert_eq ! ( typ. child_name( 1 ) , "world" ) ;
327
+ assert_eq ! ( typ. child( 1 ) . id( ) , LogicalTypeId :: Integer ) ;
328
+ }
283
329
}
0 commit comments