From 9af377a19ab271e4cc054199438484b0b202bf2c Mon Sep 17 00:00:00 2001 From: Elliana May Date: Tue, 2 Jan 2024 16:55:10 +0800 Subject: [PATCH] feat: create struct & decimal types for virtual tables (#246) * build: switch to https url for submodule * enable struct code * add LogicalType#decimal * feat: more decimal methods * more struct tests * chore: satify clippy remove dud enumerate call * test more cases * correct docs --- .gitmodules | 4 +- src/vtab/logical_type.rs | 91 +++++++++++++++++++++++++++++++--------- 2 files changed, 74 insertions(+), 21 deletions(-) diff --git a/.gitmodules b/.gitmodules index 0c1b687f..4754e802 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "libduckdb-sys/duckdb-sources"] path = libduckdb-sys/duckdb-sources - url = git@github.com:duckdb/duckdb.git - update = none + url = https://github.com/duckdb/duckdb + update = none diff --git a/src/vtab/logical_type.rs b/src/vtab/logical_type.rs index 575c5220..00845260 100644 --- a/src/vtab/logical_type.rs +++ b/src/vtab/logical_type.rs @@ -1,4 +1,7 @@ -use std::{ffi::CString, fmt::Debug}; +use std::{ + ffi::{c_char, CString}, + fmt::Debug, +}; use crate::ffi::*; @@ -176,25 +179,43 @@ impl LogicalType { } } + /// Creates a decimal type from its `width` and `scale`. + pub fn decimal(width: u8, scale: u8) -> Self { + unsafe { + Self { + ptr: duckdb_create_decimal_type(width, scale), + } + } + } + + /// Retrieves the decimal width + /// Returns 0 if the LogicalType is not a decimal + pub fn decimal_width(&self) -> u8 { + unsafe { duckdb_decimal_width(self.ptr) } + } + + /// Retrieves the decimal scale + /// Returns 0 if the LogicalType is not a decimal + pub fn decimal_scale(&self) -> u8 { + unsafe { duckdb_decimal_scale(self.ptr) } + } + /// Make a `LogicalType` for `struct` - // pub fn struct_type(fields: &[(&str, LogicalType)]) -> Self { - // let keys: Vec = fields.iter().map(|f| CString::new(f.0).unwrap()).collect(); - // let values: Vec = fields.iter().map(|it| it.1.ptr).collect(); - // let name_ptrs = keys - // .iter() - // .map(|it| it.as_ptr()) - // .collect::>(); - - // unsafe { - // Self { - // ptr: duckdb_create_struct_type( - // fields.len() as idx_t, - // name_ptrs.as_slice().as_ptr().cast_mut(), - // values.as_slice().as_ptr(), - // ), - // } - // } - // } + pub fn struct_type(fields: &[(&str, LogicalType)]) -> Self { + let keys: Vec = fields.iter().map(|f| CString::new(f.0).unwrap()).collect(); + let values: Vec = fields.iter().map(|it| it.1.ptr).collect(); + let name_ptrs = keys.iter().map(|it| it.as_ptr()).collect::>(); + + unsafe { + Self { + ptr: duckdb_create_struct_type( + values.as_slice().as_ptr().cast_mut(), + name_ptrs.as_slice().as_ptr().cast_mut(), + fields.len() as idx_t, + ), + } + } + } /// Logical type ID pub fn id(&self) -> LogicalTypeId { @@ -228,3 +249,35 @@ impl LogicalType { Self::from(c_logical_type) } } + +#[cfg(test)] +mod test { + use crate::vtab::LogicalType; + + #[test] + fn test_struct() { + let fields = &[("hello", LogicalType::new(crate::vtab::LogicalTypeId::Boolean))]; + let typ = LogicalType::struct_type(fields); + + assert_eq!(typ.num_children(), 1); + assert_eq!(typ.child_name(0), "hello"); + assert_eq!(typ.child(0).id(), crate::vtab::LogicalTypeId::Boolean); + } + + #[test] + fn test_decimal() { + let typ = LogicalType::decimal(10, 2); + + assert_eq!(typ.id(), crate::vtab::LogicalTypeId::Decimal); + assert_eq!(typ.decimal_width(), 10); + assert_eq!(typ.decimal_scale(), 2); + } + + #[test] + fn test_decimal_methods() { + let typ = LogicalType::new(crate::vtab::LogicalTypeId::Varchar); + + assert_eq!(typ.decimal_width(), 0); + assert_eq!(typ.decimal_scale(), 0); + } +}