zyxdb 0.1.28

Rust bindings for the ZYX embedded graph database
use std::ffi::CString;
use std::path::Path;
use std::ptr;

#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;

use zyxdb_sys as sys;

use crate::error::status_to_result;
use crate::{Params, ResultSet};

pub struct Database {
    raw: *mut sys::zyx_driver_db_t,
}

impl Database {
    pub fn open(path: impl AsRef<Path>) -> crate::Result<Self> {
        let path = path_to_cstring(path.as_ref())?;
        let mut raw = ptr::null_mut();
        let mut error = ptr::null_mut();
        let status = unsafe { sys::zyx_driver_db_open(path.as_ptr(), &mut raw, &mut error) };
        status_to_result(status, error)?;
        Ok(Self { raw })
    }

    pub fn execute(&self, query: &str, params: Option<&Params>) -> crate::Result<ResultSet> {
        let query = CString::new(query)?;
        let mut raw_result = ptr::null_mut();
        let mut error = ptr::null_mut();
        let raw_params = params.map_or(ptr::null_mut(), |params| params.raw);
        let status = unsafe {
            sys::zyx_driver_db_execute(
                self.raw,
                query.as_ptr(),
                raw_params,
                &mut raw_result,
                &mut error,
            )
        };
        status_to_result(status, error)?;
        Ok(unsafe { ResultSet::from_raw(raw_result) })
    }
}

impl Drop for Database {
    fn drop(&mut self) {
        if !self.raw.is_null() {
            let mut error = ptr::null_mut();
            unsafe {
                let _ = sys::zyx_driver_db_close(self.raw, &mut error);
                if !error.is_null() {
                    sys::zyx_driver_error_free(error);
                }
            }
        }
    }
}

#[cfg(unix)]
fn path_to_cstring(path: &Path) -> crate::Result<CString> {
    std::str::from_utf8(path.as_os_str().as_bytes()).map_err(|_| {
        crate::Error::new(
            crate::ErrorCode::InvalidArgument,
            "path must be valid UTF-8",
        )
    })?;
    Ok(CString::new(path.as_os_str().as_bytes())?)
}

#[cfg(not(unix))]
fn path_to_cstring(path: &Path) -> crate::Result<CString> {
    let path = path.to_str().ok_or_else(|| {
        crate::Error::new(
            crate::ErrorCode::InvalidArgument,
            "path must be valid UTF-8",
        )
    })?;
    Ok(CString::new(path.as_bytes())?)
}