#![macro_use]
use edn::entities::{
AttributePlace, Entity, EntityPlace, LookupRef, OpType, TempId, TxFunction, ValuePlace,
};
use edn::{InternSet, PlainSymbol, ValueRc};
use core_traits::TypedValue;
use mentat_core::TxReport;
use crate::InProgress;
use public_traits::errors::Result;
pub type Terms = (Vec<Entity<TypedValue>>, InternSet<TempId>);
#[derive(Debug)]
pub struct TermBuilder {
tempids: InternSet<TempId>,
terms: Vec<Entity<TypedValue>>,
}
pub struct EntityBuilder<T: BuildTerms + Sized> {
builder: T,
entity: EntityPlace<TypedValue>,
}
pub trait BuildTerms
where
Self: Sized,
{
fn named_tempid<I>(&mut self, name: I) -> ValueRc<TempId>
where
I: Into<String>;
fn describe_tempid(self, name: &str) -> EntityBuilder<Self>;
fn describe<E>(self, entity: E) -> EntityBuilder<Self>
where
E: Into<EntityPlace<TypedValue>>;
fn add<E, A, V>(&mut self, e: E, a: A, v: V) -> Result<()>
where
E: Into<EntityPlace<TypedValue>>,
A: Into<AttributePlace>,
V: Into<ValuePlace<TypedValue>>;
fn retract<E, A, V>(&mut self, e: E, a: A, v: V) -> Result<()>
where
E: Into<EntityPlace<TypedValue>>,
A: Into<AttributePlace>,
V: Into<ValuePlace<TypedValue>>;
}
impl BuildTerms for TermBuilder {
fn named_tempid<I>(&mut self, name: I) -> ValueRc<TempId>
where
I: Into<String>,
{
self.tempids.intern(TempId::External(name.into()))
}
fn describe_tempid(mut self, name: &str) -> EntityBuilder<Self> {
let e = self.named_tempid(name);
self.describe(e)
}
fn describe<E>(self, entity: E) -> EntityBuilder<Self>
where
E: Into<EntityPlace<TypedValue>>,
{
EntityBuilder {
builder: self,
entity: entity.into(),
}
}
fn add<E, A, V>(&mut self, e: E, a: A, v: V) -> Result<()>
where
E: Into<EntityPlace<TypedValue>>,
A: Into<AttributePlace>,
V: Into<ValuePlace<TypedValue>>,
{
self.terms.push(Entity::AddOrRetract {
op: OpType::Add,
e: e.into(),
a: a.into(),
v: v.into(),
});
Ok(())
}
fn retract<E, A, V>(&mut self, e: E, a: A, v: V) -> Result<()>
where
E: Into<EntityPlace<TypedValue>>,
A: Into<AttributePlace>,
V: Into<ValuePlace<TypedValue>>,
{
self.terms.push(Entity::AddOrRetract {
op: OpType::Retract,
e: e.into(),
a: a.into(),
v: v.into(),
});
Ok(())
}
}
impl Default for TermBuilder {
fn default() -> Self {
TermBuilder::new()
}
}
impl TermBuilder {
pub fn build(self) -> Result<Terms> {
Ok((self.terms, self.tempids))
}
pub fn new() -> TermBuilder {
TermBuilder {
tempids: InternSet::new(),
terms: vec![],
}
}
pub fn is_empty(&self) -> bool {
self.terms.is_empty()
}
#[allow(dead_code)]
pub fn numbered_tempid(&mut self, id: i64) -> ValueRc<TempId> {
self.tempids.intern(TempId::Internal(id))
}
pub fn lookup_ref<A, V>(a: A, v: V) -> LookupRef<TypedValue>
where
A: Into<AttributePlace>,
V: Into<TypedValue>,
{
LookupRef {
a: a.into(),
v: v.into(),
}
}
pub fn tx_function(op: &str) -> TxFunction {
TxFunction {
op: PlainSymbol::plain(op),
}
}
}
impl<T> EntityBuilder<T>
where
T: BuildTerms,
{
pub fn finish(self) -> (T, EntityPlace<TypedValue>) {
(self.builder, self.entity)
}
pub fn add<A, V>(&mut self, a: A, v: V) -> Result<()>
where
A: Into<AttributePlace>,
V: Into<ValuePlace<TypedValue>>,
{
self.builder.add(self.entity.clone(), a, v)
}
pub fn retract<A, V>(&mut self, a: A, v: V) -> Result<()>
where
A: Into<AttributePlace>,
V: Into<ValuePlace<TypedValue>>,
{
self.builder.retract(self.entity.clone(), a, v)
}
}
pub struct InProgressBuilder<'a, 'c> {
in_progress: InProgress<'a, 'c>,
builder: TermBuilder,
}
impl<'a, 'c> InProgressBuilder<'a, 'c> {
pub fn new(in_progress: InProgress<'a, 'c>) -> Self {
InProgressBuilder {
in_progress,
builder: TermBuilder::new(),
}
}
pub fn transact(self) -> (InProgress<'a, 'c>, Result<TxReport>) {
let mut in_progress = self.in_progress;
let result = self
.builder
.build()
.and_then(|(terms, _tempid_set)| in_progress.transact_entities(terms));
(in_progress, result)
}
pub fn commit(self) -> Result<TxReport> {
let mut in_progress = self.in_progress;
in_progress
.transact_builder(self.builder)
.and_then(|report| {
in_progress.commit()?;
Ok(report)
})
}
}
impl<'a, 'c> BuildTerms for InProgressBuilder<'a, 'c> {
fn named_tempid<I>(&mut self, name: I) -> ValueRc<TempId>
where
I: Into<String>,
{
self.builder.named_tempid(name)
}
fn describe_tempid(mut self, name: &str) -> EntityBuilder<InProgressBuilder<'a, 'c>> {
let e = self.builder.named_tempid(name.to_string());
self.describe(e)
}
fn describe<E>(self, entity: E) -> EntityBuilder<InProgressBuilder<'a, 'c>>
where
E: Into<EntityPlace<TypedValue>>,
{
EntityBuilder {
builder: self,
entity: entity.into(),
}
}
fn add<E, A, V>(&mut self, e: E, a: A, v: V) -> Result<()>
where
E: Into<EntityPlace<TypedValue>>,
A: Into<AttributePlace>,
V: Into<ValuePlace<TypedValue>>,
{
self.builder.add(e, a, v)
}
fn retract<E, A, V>(&mut self, e: E, a: A, v: V) -> Result<()>
where
E: Into<EntityPlace<TypedValue>>,
A: Into<AttributePlace>,
V: Into<ValuePlace<TypedValue>>,
{
self.builder.retract(e, a, v)
}
}
impl<'a, 'c> EntityBuilder<InProgressBuilder<'a, 'c>> {
pub fn transact(self) -> (InProgress<'a, 'c>, Result<TxReport>) {
self.finish().0.transact()
}
pub fn commit(self) -> Result<TxReport> {
self.finish().0.commit()
}
}