use libduckdb_sys::{
duckdb_destroy_expression, duckdb_expression, duckdb_expression_fold,
duckdb_expression_is_foldable, duckdb_expression_return_type, duckdb_value,
};
use crate::client_context::ClientContext;
use crate::error_data::ErrorData;
use crate::types::LogicalType;
use crate::value::Value;
pub struct Expression {
raw: duckdb_expression,
}
impl Expression {
#[inline]
#[must_use]
pub const unsafe fn from_raw(raw: duckdb_expression) -> Self {
Self { raw }
}
#[inline]
#[must_use]
pub const fn as_raw(&self) -> duckdb_expression {
self.raw
}
#[inline]
#[must_use]
pub const fn is_null(&self) -> bool {
self.raw.is_null()
}
#[must_use]
pub fn return_type(&self) -> Option<LogicalType> {
if self.raw.is_null() {
return None;
}
let raw = unsafe { duckdb_expression_return_type(self.raw) };
if raw.is_null() {
return None;
}
Some(unsafe { LogicalType::from_raw(raw) })
}
#[must_use]
pub fn is_foldable(&self) -> bool {
if self.raw.is_null() {
return false;
}
unsafe { duckdb_expression_is_foldable(self.raw) }
}
pub fn fold(&self, context: &ClientContext) -> Result<Value, ErrorData> {
let mut out_value: duckdb_value = std::ptr::null_mut();
let err_raw =
unsafe { duckdb_expression_fold(context.as_raw(), self.raw, &raw mut out_value) };
let err = unsafe { ErrorData::from_raw(err_raw) };
if err.has_error() {
if !out_value.is_null() {
drop(unsafe { Value::from_raw(out_value) });
}
return Err(err);
}
Ok(unsafe { Value::from_raw(out_value) })
}
}
impl Drop for Expression {
fn drop(&mut self) {
if !self.raw.is_null() {
unsafe { duckdb_destroy_expression(&raw mut self.raw) };
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn null_expression_is_null() {
let expr = unsafe { Expression::from_raw(std::ptr::null_mut()) };
assert!(expr.is_null());
assert!(!expr.is_foldable());
assert!(expr.return_type().is_none());
}
#[test]
fn size_of_expression_is_one_pointer() {
assert_eq!(
std::mem::size_of::<Expression>(),
std::mem::size_of::<usize>()
);
}
}