use {
crate::{
database_call,
rdfox_api::{
CCursor,
CCursor_advance,
CCursor_getAnswerVariableName,
CCursor_getArity,
CCursor_open,
},
Cursor,
Transaction,
},
rdf_store_rs::{
consts::LOG_TARGET_DATABASE,
RDFStoreError::{self},
},
std::{ptr, sync::Arc},
};
#[derive(Debug)]
pub struct OpenedCursor<'a> {
pub tx: Arc<Transaction>,
pub cursor: &'a Cursor,
pub arity: usize,
}
impl<'a> OpenedCursor<'a> {
pub(crate) fn new(
cursor: &'a mut Cursor,
tx: Arc<Transaction>,
) -> Result<(Self, usize), RDFStoreError> {
let c_cursor = cursor.inner;
let multiplicity = Self::open(cursor.inner)?;
let arity = Self::arity(c_cursor)?;
let opened_cursor = OpenedCursor { tx, cursor, arity };
Ok((opened_cursor, multiplicity))
}
fn open(c_cursor: *mut CCursor) -> Result<usize, RDFStoreError> {
let skip_to_offset = 0_usize;
let mut multiplicity = 0_usize;
database_call!(
"opening a cursor",
CCursor_open(c_cursor, skip_to_offset, &mut multiplicity)
)?;
tracing::debug!(
target: LOG_TARGET_DATABASE,
"CCursor_open ok multiplicity={multiplicity}"
);
Ok(multiplicity)
}
fn arity(c_cursor: *mut CCursor) -> Result<usize, RDFStoreError> {
let mut arity = 0_usize;
database_call!(
"getting the arity",
CCursor_getArity(c_cursor, &mut arity)
)?;
Ok(arity)
}
pub fn advance(&mut self) -> Result<usize, RDFStoreError> {
let mut multiplicity = 0_usize;
database_call!(
"advancing the cursor",
CCursor_advance(self.cursor.inner, &mut multiplicity)
)?;
tracing::trace!(
target: LOG_TARGET_DATABASE,
"cursor {:?} advanced, multiplicity={multiplicity}",
self.cursor.inner
);
Ok(multiplicity)
}
pub fn update_and_commit<T, U>(&mut self, f: T) -> Result<U, RDFStoreError>
where T: FnOnce(&mut OpenedCursor) -> Result<U, RDFStoreError> {
Transaction::begin_read_write(&self.cursor.connection)?.update_and_commit(|_tx| f(self))
}
pub fn execute_and_rollback<T, U>(&mut self, f: T) -> Result<U, RDFStoreError>
where T: FnOnce(&mut OpenedCursor) -> Result<U, RDFStoreError> {
Transaction::begin_read_only(&self.cursor.connection)?.execute_and_rollback(|_tx| f(self))
}
pub fn get_answer_variable_name(&self, index: usize) -> Result<String, RDFStoreError> {
let mut c_buf: *const std::os::raw::c_char = ptr::null();
database_call!(
"getting a variable name",
CCursor_getAnswerVariableName(self.cursor.inner, index, &mut c_buf)
)?;
let c_name = unsafe { std::ffi::CStr::from_ptr(c_buf) };
Ok(c_name.to_str().unwrap().to_owned())
}
}