Skip to content

Commit 34a6448

Browse files
authored
feat: create union type for virtual tables (#269)
* add ability to create union type * rework to use proper union functions * check for panic * swap for if * tweak import * remove workaround * remove deref * Remove duplicate use
1 parent 62089b6 commit 34a6448

File tree

1 file changed

+50
-4
lines changed

1 file changed

+50
-4
lines changed

src/vtab/logical_type.rs

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,23 @@ impl LogicalType {
217217
}
218218
}
219219

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+
220237
/// Logical type ID
221238
pub fn id(&self) -> LogicalTypeId {
222239
let duckdb_type_id = unsafe { duckdb_get_type_id(self.ptr) };
@@ -227,16 +244,22 @@ impl LogicalType {
227244
pub fn num_children(&self) -> usize {
228245
match self.id() {
229246
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 },
230248
LogicalTypeId::List => 1,
231249
_ => 0,
232250
}
233251
}
234252

235253
/// Logical type child name by idx
254+
///
255+
/// Panics if the logical type is not a struct or union
236256
pub fn child_name(&self, idx: usize) -> String {
237-
assert_eq!(self.id(), LogicalTypeId::Struct);
238257
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+
};
240263
let c_str = CString::from_raw(child_name_ptr);
241264
let name = c_str.to_str().unwrap();
242265
name.to_string()
@@ -245,14 +268,20 @@ impl LogicalType {
245268

246269
/// Logical type child by idx
247270
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+
};
249278
Self::from(c_logical_type)
250279
}
251280
}
252281

253282
#[cfg(test)]
254283
mod test {
255-
use crate::vtab::LogicalType;
284+
use super::{LogicalType, LogicalTypeId};
256285

257286
#[test]
258287
fn test_struct() {
@@ -280,4 +309,21 @@ mod test {
280309
assert_eq!(typ.decimal_width(), 0);
281310
assert_eq!(typ.decimal_scale(), 0);
282311
}
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+
}
283329
}

0 commit comments

Comments
 (0)