use crate::store::Store;
use crate::AsyncStore;
use oxilite_core::{AsyncBackend, SyncBackend};
use oxilite_datalog::{
compile, explain as explain_program, prepare, version_of, version_refs, DatalogError,
DatalogJob, DatalogResult, MaterializeJob, MaterializeStats, Options,
};
use std::borrow::Cow;
fn check_version(options: &Options) -> Result<(), DatalogError> {
if options.include_inferred {
return Err(DatalogError::Unsupported(
"inferences describe the current state only; they cannot be combined with @version"
.into(),
));
}
Ok(())
}
fn check_materialize(program: &str, options: &Options) -> Result<(), DatalogError> {
if version_of(program, options)?.is_some() {
return Err(DatalogError::Unsupported(
"materialization derives from the current state; drop @version / as_of".into(),
));
}
Ok(())
}
impl<B: SyncBackend + Send + Sync + 'static> Store<B> {
pub fn datalog(&self, program: &str) -> Result<DatalogResult, DatalogError> {
self.datalog_with(program, &Options::default())
}
pub fn datalog_with(
&self,
program: &str,
options: &Options,
) -> Result<DatalogResult, DatalogError> {
let options = self.datalog_version(program, options)?;
let job: DatalogJob = prepare(program, self.caps(), &options)?;
Ok(self.run(job)?)
}
fn datalog_version<'o>(
&self,
program: &str,
options: &'o Options,
) -> Result<Cow<'o, Options>, DatalogError> {
let (whole, atoms) = version_refs(program, options)?;
let mut o = options.clone();
o.history = Some(self.stats().version);
if let Some(v) = whole {
check_version(options)?;
o.as_of_tick = Some(self.resolve_version(&v)?);
}
for r in atoms {
let t = self.resolve_version(&r)?;
o.versions.insert(r, t);
}
Ok(Cow::Owned(o))
}
pub fn explain_datalog(&self, program: &str) -> Result<String, DatalogError> {
explain_program(program, self.caps(), &Options::default())
}
pub fn datalog_sql(&self, program: &str) -> Result<String, DatalogError> {
Ok(compile(program, self.caps(), &Options::default())?.sql)
}
pub fn datalog_materialize(&self, program: &str) -> Result<MaterializeStats, DatalogError> {
self.datalog_materialize_with(program, &Options::default())
}
pub fn datalog_materialize_with(
&self,
program: &str,
options: &Options,
) -> Result<MaterializeStats, DatalogError> {
check_materialize(program, options)?;
let mut options = options.clone();
options.history = Some(self.stats().version);
let job = MaterializeJob::new(program, self.caps(), &options)?;
Ok(self.run(job)?)
}
}
impl<B: AsyncBackend> AsyncStore<B> {
pub async fn datalog(&self, program: &str) -> Result<DatalogResult, DatalogError> {
self.datalog_with(program, &Options::default()).await
}
pub async fn datalog_with(
&self,
program: &str,
options: &Options,
) -> Result<DatalogResult, DatalogError> {
let (whole, atoms) = version_refs(program, options)?;
let mut o = options.clone();
o.history = Some(self.stats.borrow().version);
if let Some(v) = whole {
check_version(options)?;
o.as_of_tick = Some(self.resolve_version(&v).await?);
}
for r in atoms {
let t = self.resolve_version(&r).await?;
o.versions.insert(r, t);
}
let options: Cow<'_, Options> = Cow::Owned(o);
let job: DatalogJob = prepare(program, self.caps(), &options)?;
Ok(oxilite_core::run_async(&self.backend, job).await?)
}
pub async fn explain_datalog(&self, program: &str) -> Result<String, DatalogError> {
explain_program(program, self.caps(), &Options::default())
}
pub async fn datalog_materialize(
&self,
program: &str,
) -> Result<MaterializeStats, DatalogError> {
check_materialize(program, &Options::default())?;
let job = MaterializeJob::new(program, self.caps(), &Options::default())?;
Ok(oxilite_core::run_async(&self.backend, job).await?)
}
}