chdb 0.1.2

Use clickhouse as library (chdb)
Documentation
use std::ffi::CString;

use chdb_bindings_rs::query_stable;

use crate::{options::QueryOption, result::QueryResult};

#[derive(Debug)]
pub struct Query {
    query: String,
    params: Vec<QueryOption>,
}

impl Query {
    pub fn new(query: impl Into<String>) -> Self {
        Self {
            query: query.into(),
            params: Vec::new(),
        }
    }

    pub fn option(self, param: QueryOption) -> Self {
        Self {
            query: self.query,
            params: self
                .params
                .into_iter()
                .chain(std::iter::once(param))
                .collect(),
        }
    }

    pub fn exec(self) -> Option<QueryResult> {
        let mut args: Vec<String> =
            Vec::from(["clickhouse".to_string(), format!("--query={}", self.query)]);

        args.extend(
            self.params
                .iter()
                .map(|p| p.to_string())
                .collect::<Vec<_>>(),
        );

        let c_strings: Vec<CString> = args
            .iter()
            .map(|s| CString::new(s.as_str()).expect("Failed to convert &str to CString"))
            .collect();

        let raw_pointers: Vec<*const std::os::raw::c_char> =
            c_strings.iter().map(|c_string| c_string.as_ptr()).collect();

        let result = unsafe { query_stable(c_strings.len() as i32, raw_pointers.as_ptr()) };

        if result.is_null() {
            return None;
        }

        let result = unsafe { &*result };

        Some(QueryResult {
            elapsed: result.elapsed,
            rows_read: result.rows_read,
            bytes_read: result.bytes_read,
            buf: unsafe { Vec::from_raw_parts(result.buf as *mut u8, result.size, 16) },
        })
    }
}