Build Entity instances, not Term* instances. Fixes #674. (#778) r=grisha

This commit is contained in:
Nick Alexander 2018-07-05 16:42:02 -07:00
commit 99deb87b9f
18 changed files with 397 additions and 315 deletions

View file

@ -60,9 +60,14 @@ pub use cache::{
/// Core types defining a Mentat knowledge base.
mod types;
mod tx_report;
mod value_type_set;
mod sql_types;
pub use tx_report::{
TxReport,
};
pub use types::{
Binding,
Entid,
@ -365,7 +370,6 @@ impl HasSchema for Schema {
}
}
pub mod intern_set;
pub mod counter;
pub mod util;

38
core/src/tx_report.rs Normal file
View file

@ -0,0 +1,38 @@
// Copyright 2018 Mozilla
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#![allow(dead_code)]
use std::collections::{
BTreeMap,
};
use ::{
DateTime,
Entid,
Utc,
};
/// A transaction report summarizes an applied transaction.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
pub struct TxReport {
/// The transaction ID of the transaction.
pub tx_id: Entid,
/// The timestamp when the transaction began to be committed.
pub tx_instant: DateTime<Utc>,
/// A map from string literal tempid to resolved or allocated entid.
///
/// Every string literal tempid presented to the transactor either resolves via upsert to an
/// existing entid, or is allocated a new entid. (It is possible for multiple distinct string
/// literal tempids to all unify to a single freshly allocated entid.)
pub tempids: BTreeMap<String, Entid>,
}

View file

@ -47,6 +47,14 @@ use ::edn::{
ValueRc,
};
use ::edn::entities::{
AttributePlace,
EntidOrIdent,
EntityPlace,
ValuePlace,
TransactableValueMarker,
};
use values;
/// Represents one entid in the entid space.
@ -73,6 +81,24 @@ impl From<KnownEntid> for TypedValue {
}
}
impl<V: TransactableValueMarker> Into<EntityPlace<V>> for KnownEntid {
fn into(self) -> EntityPlace<V> {
EntityPlace::Entid(EntidOrIdent::Entid(self.0))
}
}
impl Into<AttributePlace> for KnownEntid {
fn into(self) -> AttributePlace {
AttributePlace::Entid(EntidOrIdent::Entid(self.0))
}
}
impl<V: TransactableValueMarker> Into<ValuePlace<V>> for KnownEntid {
fn into(self) -> ValuePlace<V> {
ValuePlace::Entid(EntidOrIdent::Entid(self.0))
}
}
/// The attribute of each Mentat assertion has a :db/valueType constraining the value to a
/// particular set. Mentat recognizes the following :db/valueType values.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
@ -215,6 +241,9 @@ pub enum TypedValue {
Uuid(Uuid), // It's only 128 bits, so this should be acceptable to clone.
}
/// `TypedValue` is the value type for programmatic use in transaction builders.
impl TransactableValueMarker for TypedValue {}
/// The values bound in a query specification can be:
///
/// * Vecs of structured values, for multi-valued component attributes or nested expressions.

View file

@ -1119,20 +1119,22 @@ mod tests {
use debug;
use errors;
use edn;
use mentat_core::{
HasSchema,
Keyword,
KnownEntid,
attribute,
};
use mentat_core::intern_set::{
use edn::{
InternSet,
};
use mentat_core::util::Either::*;
use edn::entities::{
OpType,
TempId,
};
use mentat_core::{
HasSchema,
Keyword,
KnownEntid,
TxReport,
attribute,
};
use mentat_core::util::Either::*;
use rusqlite;
use std::collections::{
BTreeMap,
@ -1141,7 +1143,6 @@ mod tests {
Term,
TermWithTempIds,
};
use types::TxReport;
use tx::{
transact_terms,
};

View file

@ -17,7 +17,6 @@ use std::collections::{
BTreeSet,
HashMap,
};
use std::rc::Rc;
use mentat_core::KnownEntid;
@ -27,6 +26,14 @@ use edn;
use edn::{
SpannedValue,
ValueAndSpan,
ValueRc,
};
use edn::entities;
use edn::entities::{
EntityPlace,
OpType,
TempId,
TxFunction,
};
use errors;
@ -47,13 +54,6 @@ use types::{
TypedValue,
ValueType,
};
use edn::entities;
use edn::entities::{
EntityPlace,
OpType,
TempId,
TxFunction,
};
impl TransactableValue for ValueAndSpan {
fn into_typed_value(self, schema: &Schema, value_type: ValueType) -> Result<TypedValue> {
@ -72,7 +72,7 @@ impl TransactableValue for ValueAndSpan {
bail!(DbErrorKind::InputError(errors::InputError::BadEntityPlace))
}
},
Text(v) => Ok(EntityPlace::TempId(TempId::External(v))),
Text(v) => Ok(EntityPlace::TempId(TempId::External(v).into())),
List(ls) => {
let mut it = ls.iter();
match (it.next().map(|x| &x.inner), it.next(), it.next(), it.next()) {
@ -107,7 +107,7 @@ impl TransactableValue for ValueAndSpan {
}
fn as_tempid(&self) -> Option<TempId> {
self.inner.as_text().cloned().map(TempId::External)
self.inner.as_text().cloned().map(TempId::External).map(|v| v.into())
}
}
@ -123,7 +123,7 @@ impl TransactableValue for TypedValue {
match self {
TypedValue::Ref(x) => Ok(EntityPlace::Entid(entities::EntidOrIdent::Entid(x))),
TypedValue::Keyword(x) => Ok(EntityPlace::Entid(entities::EntidOrIdent::Ident((*x).clone()))),
TypedValue::String(x) => Ok(EntityPlace::TempId(TempId::External((*x).clone()))),
TypedValue::String(x) => Ok(EntityPlace::TempId(TempId::External((*x).clone()).into())),
TypedValue::Boolean(_) |
TypedValue::Long(_) |
TypedValue::Double(_) |
@ -134,7 +134,7 @@ impl TransactableValue for TypedValue {
fn as_tempid(&self) -> Option<TempId> {
match self {
&TypedValue::String(ref s) => Some(TempId::External((**s).clone())),
&TypedValue::String(ref s) => Some(TempId::External((**s).clone()).into()),
_ => None,
}
}
@ -150,10 +150,10 @@ use self::Either::*;
pub type KnownEntidOr<T> = Either<KnownEntid, T>;
pub type TypedValueOr<T> = Either<TypedValue, T>;
pub type TempIdHandle = Rc<TempId>;
pub type TempIdHandle = ValueRc<TempId>;
pub type TempIdMap = HashMap<TempIdHandle, KnownEntid>;
pub type LookupRef = Rc<AVPair>;
pub type LookupRef = ValueRc<AVPair>;
/// Internal representation of an entid on its way to resolution. We either have the simple case (a
/// numeric entid), a lookup-ref that still needs to be resolved (an atomized [a v] pair), or a temp

View file

@ -106,7 +106,6 @@ pub use types::{
DB,
PartitionMap,
TransactableValue,
TxReport,
};
pub fn to_namespaced_keyword(s: &str) -> Result<symbols::Keyword> {

View file

@ -56,9 +56,6 @@ use std::collections::{
use std::iter::{
once,
};
use std::rc::{
Rc,
};
use db;
use db::{
@ -66,6 +63,7 @@ use db::{
PartitionMapping,
};
use edn::{
InternSet,
Keyword,
};
use entids;
@ -96,13 +94,12 @@ use mentat_core::{
DateTime,
KnownEntid,
Schema,
TxReport,
Utc,
attribute,
now,
};
use mentat_core::intern_set::InternSet;
use edn::entities as entmod;
use edn::entities::{
AttributePlace,
@ -123,7 +120,6 @@ use types::{
Entid,
PartitionMap,
TransactableValue,
TxReport,
TypedValue,
ValueType,
};
@ -304,15 +300,11 @@ impl<'conn, 'a, W> Tx<'conn, 'a, W> where W: TransactWatcher {
Ok(self.lookup_refs.intern((lr_a, lr_typed_value)))
}
fn intern_temp_id(&mut self, temp_id: TempId) -> Rc<TempId> {
self.temp_ids.intern(temp_id)
}
/// Allocate private internal tempids reserved for Mentat. Internal tempids just need to be
/// unique within one transaction; they should never escape a transaction.
fn allocate_mentat_id<W: TransactableValue>(&mut self) -> entmod::EntityPlace<W> {
self.mentat_id_count += 1;
entmod::EntityPlace::TempId(TempId::Internal(self.mentat_id_count))
entmod::EntityPlace::TempId(TempId::Internal(self.mentat_id_count).into())
}
fn entity_e_into_term_e<W: TransactableValue>(&mut self, x: entmod::EntityPlace<W>) -> Result<KnownEntidOr<LookupRefOrTempId>> {
@ -326,7 +318,7 @@ impl<'conn, 'a, W> Tx<'conn, 'a, W> where W: TransactWatcher {
},
entmod::EntityPlace::TempId(e) => {
Ok(Either::Right(LookupRefOrTempId::TempId(self.intern_temp_id(e))))
Ok(Either::Right(LookupRefOrTempId::TempId(self.temp_ids.intern(e))))
},
entmod::EntityPlace::LookupRef(ref lookup_ref) => {
@ -372,7 +364,7 @@ impl<'conn, 'a, W> Tx<'conn, 'a, W> where W: TransactWatcher {
// that the given value is in the attribute's value set, or (in
// limited cases) coerce the value into the attribute's value set.
match v.as_tempid() {
Some(tempid) => Ok(Either::Right(LookupRefOrTempId::TempId(self.intern_temp_id(tempid)))),
Some(tempid) => Ok(Either::Right(LookupRefOrTempId::TempId(self.temp_ids.intern(tempid)))),
None => {
if let TypedValue::Ref(entid) = v.into_typed_value(&self.schema, ValueType::Ref)? {
Ok(Either::Left(KnownEntid(entid)))
@ -388,7 +380,7 @@ impl<'conn, 'a, W> Tx<'conn, 'a, W> where W: TransactWatcher {
Ok(Either::Left(KnownEntid(self.entity_a_into_term_a(entid)?))),
entmod::ValuePlace::TempId(tempid) =>
Ok(Either::Right(LookupRefOrTempId::TempId(self.intern_temp_id(tempid)))),
Ok(Either::Right(LookupRefOrTempId::TempId(self.temp_ids.intern(tempid)))),
entmod::ValuePlace::LookupRef(ref lookup_ref) =>
Ok(Either::Right(LookupRefOrTempId::LookupRef(self.intern_lookup_ref(lookup_ref)?))),
@ -459,7 +451,7 @@ impl<'conn, 'a, W> Tx<'conn, 'a, W> where W: TransactWatcher {
// limited cases) coerce the value into the attribute's value set.
if attribute.value_type == ValueType::Ref {
match v.as_tempid() {
Some(tempid) => Either::Right(LookupRefOrTempId::TempId(in_process.intern_temp_id(tempid))),
Some(tempid) => Either::Right(LookupRefOrTempId::TempId(in_process.temp_ids.intern(tempid))),
None => v.into_typed_value(&self.schema, attribute.value_type).map(Either::Left)?,
}
} else {
@ -471,7 +463,7 @@ impl<'conn, 'a, W> Tx<'conn, 'a, W> where W: TransactWatcher {
Either::Left(TypedValue::Ref(in_process.entity_a_into_term_a(entid)?)),
entmod::ValuePlace::TempId(tempid) =>
Either::Right(LookupRefOrTempId::TempId(in_process.intern_temp_id(tempid))),
Either::Right(LookupRefOrTempId::TempId(in_process.temp_ids.intern(tempid))),
entmod::ValuePlace::LookupRef(ref lookup_ref) => {
if attribute.value_type != ValueType::Ref {
@ -622,7 +614,7 @@ impl<'conn, 'a, W> Tx<'conn, 'a, W> where W: TransactWatcher {
let (terms_with_temp_ids_and_lookup_refs, tempid_set, lookup_ref_set) = self.entities_into_terms_with_temp_ids_and_lookup_refs(entities)?;
// Pipeline stage 2: resolve lookup refs -> terms with tempids.
let lookup_ref_avs: Vec<&(i64, TypedValue)> = lookup_ref_set.inner.iter().map(|rc| &**rc).collect();
let lookup_ref_avs: Vec<&(i64, TypedValue)> = lookup_ref_set.iter().map(|rc| &**rc).collect();
let lookup_ref_map: AVMap = self.store.resolve_avs(&lookup_ref_avs[..])?;
let terms_with_temp_ids = self.resolve_lookup_refs(&lookup_ref_map, terms_with_temp_ids_and_lookup_refs)?;
@ -703,8 +695,8 @@ impl<'conn, 'a, W> Tx<'conn, 'a, W> where W: TransactWatcher {
}
// Verify that every tempid we interned either resolved or has been allocated.
assert_eq!(tempids.len(), tempid_set.inner.len());
for tempid in &tempid_set.inner {
assert_eq!(tempids.len(), tempid_set.len());
for tempid in tempid_set.iter() {
assert!(tempids.contains_key(&**tempid));
}

View file

@ -95,23 +95,6 @@ pub type AVMap<'a> = HashMap<&'a AVPair, Entid>;
// represents a set of entids that are correspond to attributes
pub type AttributeSet = BTreeSet<Entid>;
/// A transaction report summarizes an applied transaction.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
pub struct TxReport {
/// The transaction ID of the transaction.
pub tx_id: Entid,
/// The timestamp when the transaction began to be committed.
pub tx_instant: DateTime<Utc>,
/// A map from string literal tempid to resolved or allocated entid.
///
/// Every string literal tempid presented to the transactor either resolves via upsert to an
/// existing entid, or is allocated a new entid. (It is possible for multiple distinct string
/// literal tempids to all unify to a single freshly allocated entid.)
pub tempids: BTreeMap<String, Entid>,
}
/// The transactor is tied to `edn::ValueAndSpan` right now, but in the future we'd like to support
/// `TypedValue` directly for programmatic use. `TransactableValue` encapsulates the interface
/// value types (i.e., values in the value place) need to support to be transacted.

View file

@ -260,7 +260,7 @@ tx_function -> TxFunction
= "(" __ n:$(symbol_name) __ ")" { TxFunction { op: PlainSymbol::plain(n) } }
entity_place -> EntityPlace<ValueAndSpan>
= v:raw_text { EntityPlace::TempId(TempId::External(v)) }
= v:raw_text { EntityPlace::TempId(TempId::External(v).into()) }
/ v:entid { EntityPlace::Entid(v) }
/ v:lookup_ref { EntityPlace::LookupRef(v) }
/ v:tx_function { EntityPlace::TxFunction(v) }

View file

@ -13,11 +13,29 @@
use std::collections::BTreeMap;
use std::fmt;
use value_rc::{
ValueRc,
};
use symbols::{
Keyword,
PlainSymbol,
};
use types::{
ValueAndSpan,
};
/// `EntityPlace` and `ValuePlace` embed values, either directly (i.e., `ValuePlace::Atom`) or
/// indirectly (i.e., `EntityPlace::LookupRef`). In order to maintain the graph of `Into` and
/// `From` relations, we need to ensure that `{Value,Entity}Place` can't match as a potential value.
/// (If it does, the `impl Into<T> for T` default conflicts.) This marker trait allows to mark
/// acceptable values, thereby removing `{Entity,Value}Place` from consideration.
pub trait TransactableValueMarker {}
/// `ValueAndSpan` is the value type coming out of the entity parser.
impl TransactableValueMarker for ValueAndSpan {}
/// A tempid, either an external tempid given in a transaction (usually as an `Value::Text`),
/// or an internal tempid allocated by Mentat itself.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
@ -50,6 +68,18 @@ pub enum EntidOrIdent {
Ident(Keyword),
}
impl From<i64> for EntidOrIdent {
fn from(v: i64) -> Self {
EntidOrIdent::Entid(v)
}
}
impl From<Keyword> for EntidOrIdent {
fn from(v: Keyword) -> Self {
EntidOrIdent::Ident(v)
}
}
impl EntidOrIdent {
pub fn unreversed(&self) -> Option<EntidOrIdent> {
match self {
@ -93,7 +123,7 @@ pub enum ValuePlace<V> {
Entid(EntidOrIdent),
// We never know at parse-time whether a string is really a tempid, but we will often know when
// building entities programmatically.
TempId(TempId),
TempId(ValueRc<TempId>),
LookupRef(LookupRef<V>),
TxFunction(TxFunction),
Vector(Vec<ValuePlace<V>>),
@ -101,19 +131,103 @@ pub enum ValuePlace<V> {
MapNotation(MapNotation<V>),
}
impl<V: TransactableValueMarker> From<EntidOrIdent> for ValuePlace<V> {
fn from(v: EntidOrIdent) -> Self {
ValuePlace::Entid(v)
}
}
impl<V: TransactableValueMarker> From<TempId> for ValuePlace<V> {
fn from(v: TempId) -> Self {
ValuePlace::TempId(v.into())
}
}
impl<V: TransactableValueMarker> From<ValueRc<TempId>> for ValuePlace<V> {
fn from(v: ValueRc<TempId>) -> Self {
ValuePlace::TempId(v)
}
}
impl<V: TransactableValueMarker> From<LookupRef<V>> for ValuePlace<V> {
fn from(v: LookupRef<V>) -> Self {
ValuePlace::LookupRef(v)
}
}
impl<V: TransactableValueMarker> From<TxFunction> for ValuePlace<V> {
fn from(v: TxFunction) -> Self {
ValuePlace::TxFunction(v)
}
}
impl<V: TransactableValueMarker> From<Vec<ValuePlace<V>>> for ValuePlace<V> {
fn from(v: Vec<ValuePlace<V>>) -> Self {
ValuePlace::Vector(v)
}
}
impl<V: TransactableValueMarker> From<V> for ValuePlace<V> {
fn from(v: V) -> Self {
ValuePlace::Atom(v)
}
}
impl<V: TransactableValueMarker> From<MapNotation<V>> for ValuePlace<V> {
fn from(v: MapNotation<V>) -> Self {
ValuePlace::MapNotation(v)
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
pub enum EntityPlace<V> {
Entid(EntidOrIdent),
TempId(TempId),
TempId(ValueRc<TempId>),
LookupRef(LookupRef<V>),
TxFunction(TxFunction),
}
impl<V, E: Into<EntidOrIdent>> From<E> for EntityPlace<V> {
fn from(v: E) -> Self {
EntityPlace::Entid(v.into())
}
}
impl<V: TransactableValueMarker> From<TempId> for EntityPlace<V> {
fn from(v: TempId) -> Self {
EntityPlace::TempId(v.into())
}
}
impl<V: TransactableValueMarker> From<ValueRc<TempId>> for EntityPlace<V> {
fn from(v: ValueRc<TempId>) -> Self {
EntityPlace::TempId(v)
}
}
impl<V: TransactableValueMarker> From<LookupRef<V>> for EntityPlace<V> {
fn from(v: LookupRef<V>) -> Self {
EntityPlace::LookupRef(v)
}
}
impl<V: TransactableValueMarker> From<TxFunction> for EntityPlace<V> {
fn from(v: TxFunction) -> Self {
EntityPlace::TxFunction(v)
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
pub enum AttributePlace {
Entid(EntidOrIdent),
}
impl<A: Into<EntidOrIdent>> From<A> for AttributePlace {
fn from(v: A) -> Self {
AttributePlace::Entid(v.into())
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
pub enum OpType {
Add,

View file

@ -12,7 +12,14 @@
use std::collections::HashSet;
use std::hash::Hash;
use std::rc::Rc;
use std::ops::{
Deref,
DerefMut,
};
use ::{
ValueRc,
};
/// An `InternSet` allows to "intern" some potentially large values, maintaining a single value
/// instance owned by the `InternSet` and leaving consumers with lightweight ref-counted handles to
@ -23,7 +30,21 @@ use std::rc::Rc;
/// See https://en.wikipedia.org/wiki/String_interning for discussion.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct InternSet<T> where T: Eq + Hash {
pub inner: HashSet<Rc<T>>,
inner: HashSet<ValueRc<T>>,
}
impl<T> Deref for InternSet<T> where T: Eq + Hash {
type Target = HashSet<ValueRc<T>>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T> DerefMut for InternSet<T> where T: Eq + Hash {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<T> InternSet<T> where T: Eq + Hash {
@ -33,20 +54,15 @@ impl<T> InternSet<T> where T: Eq + Hash {
}
}
pub fn len(&self) -> usize {
self.inner.len()
}
/// Intern a value, providing a ref-counted handle to the interned value.
///
/// ```
/// use std::rc::Rc;
/// use mentat_core::intern_set::InternSet;
/// use edn::{InternSet, ValueRc};
///
/// let mut s = InternSet::new();
///
/// let one = "foo".to_string();
/// let two = Rc::new("foo".to_string());
/// let two = ValueRc::new("foo".to_string());
///
/// let out_one = s.intern(one);
/// assert_eq!(out_one, two);
@ -54,11 +70,11 @@ impl<T> InternSet<T> where T: Eq + Hash {
///
/// let out_two = s.intern(two);
/// assert_eq!(out_one, out_two);
/// assert_eq!(1, s.inner.len());
/// assert_eq!(1, s.len());
/// // assert!(&out_one.ptr_eq(&out_two)); // Nightly-only.
/// ```
pub fn intern<R: Into<Rc<T>>>(&mut self, value: R) -> Rc<T> {
let key: Rc<T> = value.into();
pub fn intern<R: Into<ValueRc<T>>>(&mut self, value: R) -> ValueRc<T> {
let key: ValueRc<T> = value.into();
if self.inner.insert(key.clone()) {
key
} else {

View file

@ -23,6 +23,10 @@ extern crate serde;
extern crate serde_derive;
pub mod entities;
pub mod intern_set;
pub use intern_set::{
InternSet,
};
// Intentionally not pub.
mod namespaceable_name;
pub mod query;

View file

@ -120,7 +120,6 @@ pub use mentat::entity_builder::{
BuildTerms,
EntityBuilder,
InProgressBuilder,
IntoThing,
};
pub mod android;
@ -339,7 +338,7 @@ pub unsafe extern "C" fn in_progress_entity_builder_from_temp_id<'m>(in_progress
pub unsafe extern "C" fn in_progress_entity_builder_from_entid<'m>(in_progress: *mut InProgress<'m, 'm>, entid: c_longlong) -> *mut EntityBuilder<InProgressBuilder> {
assert_not_null!(in_progress);
let in_progress = Box::from_raw(in_progress);
Box::into_raw(Box::new(in_progress.builder().describe(&KnownEntid(entid))))
Box::into_raw(Box::new(in_progress.builder().describe(KnownEntid(entid))))
}
/// Starts a new transaction and creates a builder using the transaction
@ -392,7 +391,7 @@ pub unsafe extern "C" fn store_entity_builder_from_entid<'a, 'c>(store: *mut Sto
assert_not_null!(store);
let store = &mut *store;
let result = store.begin_transaction().and_then(|in_progress| {
Ok(in_progress.builder().describe(&KnownEntid(entid)))
Ok(in_progress.builder().describe(KnownEntid(entid)))
});
translate_result(result, error)
}
@ -418,7 +417,7 @@ pub unsafe extern "C" fn in_progress_builder_add_string<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = c_char_to_string(value).into();
translate_void_result(builder.add_kw(KnownEntid(entid), &kw, value), error);
translate_void_result(builder.add(KnownEntid(entid), kw, value), error);
}
/// Uses `builder` to assert `value` for `kw` on entity `entid`.
@ -441,7 +440,7 @@ pub unsafe extern "C" fn in_progress_builder_add_long<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = TypedValue::Long(value);
translate_void_result(builder.add_kw(KnownEntid(entid), &kw, value), error);
translate_void_result(builder.add(KnownEntid(entid), kw, value), error);
}
/// Uses `builder` to assert `value` for `kw` on entity `entid`.
@ -465,7 +464,7 @@ pub unsafe extern "C" fn in_progress_builder_add_ref<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = TypedValue::Ref(value);
translate_void_result(builder.add_kw(KnownEntid(entid), &kw, value), error);
translate_void_result(builder.add(KnownEntid(entid), kw, value), error);
}
/// Uses `builder` to assert `value` for `kw` on entity `entid`.
@ -490,7 +489,7 @@ pub unsafe extern "C" fn in_progress_builder_add_keyword<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = kw_from_string(c_char_to_string(value)).into();
translate_void_result(builder.add_kw(KnownEntid(entid), &kw, value), error);
translate_void_result(builder.add(KnownEntid(entid), kw, value), error);
}
/// Uses `builder` to assert `value` for `kw` on entity `entid`.
@ -514,7 +513,7 @@ pub unsafe extern "C" fn in_progress_builder_add_boolean<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = value.into();
translate_void_result(builder.add_kw(KnownEntid(entid), &kw, value), error);
translate_void_result(builder.add(KnownEntid(entid), kw, value), error);
}
/// Uses `builder` to assert `value` for `kw` on entity `entid`.
@ -538,7 +537,7 @@ pub unsafe extern "C" fn in_progress_builder_add_double<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = value.into();
translate_void_result(builder.add_kw(KnownEntid(entid), &kw, value), error);
translate_void_result(builder.add(KnownEntid(entid), kw, value), error);
}
/// Uses `builder` to assert `value` for `kw` on entity `entid`.
@ -562,7 +561,7 @@ pub unsafe extern "C" fn in_progress_builder_add_timestamp<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = TypedValue::instant(value);
translate_void_result(builder.add_kw(KnownEntid(entid), &kw, value), error);
translate_void_result(builder.add(KnownEntid(entid), kw, value), error);
}
/// Uses `builder` to assert `value` for `kw` on entity `entid`.
@ -588,7 +587,7 @@ pub unsafe extern "C" fn in_progress_builder_add_uuid<'a, 'c>(
let value = &*value;
let value = Uuid::from_bytes(value).expect("valid uuid");
let value: TypedValue = value.into();
translate_void_result(builder.add_kw(KnownEntid(entid), &kw, value), error);
translate_void_result(builder.add(KnownEntid(entid), kw, value), error);
}
/// Uses `builder` to retract `value` for `kw` on entity `entid`.
@ -612,7 +611,7 @@ pub unsafe extern "C" fn in_progress_builder_retract_string<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = c_char_to_string(value).into();
translate_void_result(builder.retract_kw(KnownEntid(entid), &kw, value), error);
translate_void_result(builder.retract(KnownEntid(entid), kw, value), error);
}
/// Uses `builder` to retract `value` for `kw` on entity `entid`.
@ -636,7 +635,7 @@ pub unsafe extern "C" fn in_progress_builder_retract_long<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = TypedValue::Long(value);
translate_void_result(builder.retract_kw(KnownEntid(entid), &kw, value), error);
translate_void_result(builder.retract(KnownEntid(entid), kw, value), error);
}
/// Uses `builder` to retract `value` for `kw` on entity `entid`.
@ -660,7 +659,7 @@ pub unsafe extern "C" fn in_progress_builder_retract_ref<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = TypedValue::Ref(value);
translate_void_result(builder.retract_kw(KnownEntid(entid), &kw, value), error);
translate_void_result(builder.retract(KnownEntid(entid), kw, value), error);
}
@ -685,7 +684,7 @@ pub unsafe extern "C" fn in_progress_builder_retract_keyword<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = kw_from_string(c_char_to_string(value)).into();
translate_void_result(builder.retract_kw(KnownEntid(entid), &kw, value), error);
translate_void_result(builder.retract(KnownEntid(entid), kw, value), error);
}
/// Uses `builder` to retract `value` for `kw` on entity `entid`.
@ -709,7 +708,7 @@ pub unsafe extern "C" fn in_progress_builder_retract_boolean<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = value.into();
translate_void_result(builder.retract_kw(KnownEntid(entid), &kw, value), error);
translate_void_result(builder.retract(KnownEntid(entid), kw, value), error);
}
/// Uses `builder` to retract `value` for `kw` on entity `entid`.
@ -733,7 +732,7 @@ pub unsafe extern "C" fn in_progress_builder_retract_double<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = value.into();
translate_void_result(builder.retract_kw(KnownEntid(entid), &kw, value), error);
translate_void_result(builder.retract(KnownEntid(entid), kw, value), error);
}
/// Uses `builder` to retract `value` for `kw` on entity `entid`.
@ -757,7 +756,7 @@ pub unsafe extern "C" fn in_progress_builder_retract_timestamp<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = TypedValue::instant(value);
translate_void_result(builder.retract_kw(KnownEntid(entid), &kw, value), error);
translate_void_result(builder.retract(KnownEntid(entid), kw, value), error);
}
/// Uses `builder` to retract `value` for `kw` on entity `entid`.
@ -785,7 +784,7 @@ pub unsafe extern "C" fn in_progress_builder_retract_uuid<'a, 'c>(
let value = &*value;
let value = Uuid::from_bytes(value).expect("valid uuid");
let value: TypedValue = value.into();
translate_void_result(builder.retract_kw(KnownEntid(entid), &kw, value), error);
translate_void_result(builder.retract(KnownEntid(entid), kw, value), error);
}
/// Transacts and commits all the assertions and retractions that have been performed
@ -842,7 +841,7 @@ pub unsafe extern "C" fn entity_builder_add_string<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = c_char_to_string(value).into();
translate_void_result(builder.add_kw(&kw, value), error);
translate_void_result(builder.add(kw, value), error);
}
/// Uses `builder` to assert `value` for `kw` on entity `entid`.
@ -865,7 +864,7 @@ pub unsafe extern "C" fn entity_builder_add_long<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = TypedValue::Long(value);
translate_void_result(builder.add_kw(&kw, value), error);
translate_void_result(builder.add(kw, value), error);
}
/// Uses `builder` to assert `value` for `kw` on entity `entid`.
@ -888,7 +887,7 @@ pub unsafe extern "C" fn entity_builder_add_ref<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = TypedValue::Ref(value);
translate_void_result(builder.add_kw(&kw, value), error);
translate_void_result(builder.add(kw, value), error);
}
/// Uses `builder` to assert `value` for `kw` on entity `entid`.
@ -911,7 +910,7 @@ pub unsafe extern "C" fn entity_builder_add_keyword<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = kw_from_string(c_char_to_string(value)).into();
translate_void_result(builder.add_kw(&kw, value), error);
translate_void_result(builder.add(kw, value), error);
}
/// Uses `builder` to assert `value` for `kw` on entity `entid`.
@ -934,7 +933,7 @@ pub unsafe extern "C" fn entity_builder_add_boolean<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = value.into();
translate_void_result(builder.add_kw(&kw, value), error);
translate_void_result(builder.add(kw, value), error);
}
/// Uses `builder` to assert `value` for `kw` on entity `entid`.
@ -957,7 +956,7 @@ pub unsafe extern "C" fn entity_builder_add_double<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = value.into();
translate_void_result(builder.add_kw(&kw, value), error);
translate_void_result(builder.add(kw, value), error);
}
/// Uses `builder` to assert `value` for `kw` on entity `entid`.
@ -980,7 +979,7 @@ pub unsafe extern "C" fn entity_builder_add_timestamp<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = TypedValue::instant(value);
translate_void_result(builder.add_kw(&kw, value), error);
translate_void_result(builder.add(kw, value), error);
}
/// Uses `builder` to assert `value` for `kw` on entity `entid`.
@ -1005,7 +1004,7 @@ pub unsafe extern "C" fn entity_builder_add_uuid<'a, 'c>(
let value = &*value;
let value = Uuid::from_bytes(value).expect("valid uuid");
let value: TypedValue = value.into();
translate_void_result(builder.add_kw(&kw, value), error);
translate_void_result(builder.add(kw, value), error);
}
/// Uses `builder` to retract `value` for `kw` on entity `entid`.
@ -1028,7 +1027,7 @@ pub unsafe extern "C" fn entity_builder_retract_string<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = c_char_to_string(value).into();
translate_void_result(builder.retract_kw(&kw, value), error);
translate_void_result(builder.retract(kw, value), error);
}
/// Uses `builder` to retract `value` for `kw` on entity `entid`.
@ -1051,7 +1050,7 @@ pub unsafe extern "C" fn entity_builder_retract_long<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = TypedValue::Long(value);
translate_void_result(builder.retract_kw(&kw, value), error);
translate_void_result(builder.retract(kw, value), error);
}
/// Uses `builder` to retract `value` for `kw` on entity `entid`.
@ -1074,7 +1073,7 @@ pub unsafe extern "C" fn entity_builder_retract_ref<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = TypedValue::Ref(value);
translate_void_result(builder.retract_kw(&kw, value), error);
translate_void_result(builder.retract(kw, value), error);
}
/// Uses `builder` to retract `value` for `kw` on entity `entid`.
@ -1097,7 +1096,7 @@ pub unsafe extern "C" fn entity_builder_retract_keyword<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = kw_from_string(c_char_to_string(value)).into();
translate_void_result(builder.retract_kw(&kw, value), error);
translate_void_result(builder.retract(kw, value), error);
}
/// Uses `builder` to retract `value` for `kw` on entity `entid`.
@ -1120,7 +1119,7 @@ pub unsafe extern "C" fn entity_builder_retract_boolean<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = value.into();
translate_void_result(builder.retract_kw(&kw, value), error);
translate_void_result(builder.retract(kw, value), error);
}
/// Uses `builder` to retract `value` for `kw` on entity `entid`.
@ -1143,7 +1142,7 @@ pub unsafe extern "C" fn entity_builder_retract_double<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = value.into();
translate_void_result(builder.retract_kw(&kw, value), error);
translate_void_result(builder.retract(kw, value), error);
}
/// Uses `builder` to retract `value` for `kw` on entity `entid`.
@ -1166,7 +1165,7 @@ pub unsafe extern "C" fn entity_builder_retract_timestamp<'a, 'c>(
let builder = &mut *builder;
let kw = kw_from_string(c_char_to_string(kw));
let value: TypedValue = TypedValue::instant(value);
translate_void_result(builder.retract_kw(&kw, value), error);
translate_void_result(builder.retract(kw, value), error);
}
/// Uses `builder` to retract `value` for `kw` on entity `entid`.
@ -1192,7 +1191,7 @@ pub unsafe extern "C" fn entity_builder_retract_uuid<'a, 'c>(
let value = &*value;
let value = Uuid::from_bytes(value).expect("valid uuid");
let value: TypedValue = value.into();
translate_void_result(builder.retract_kw(&kw, value), error);
translate_void_result(builder.retract(kw, value), error);
}
/// Transacts all the assertions and retractions that have been performed

View file

@ -41,6 +41,9 @@ use rusqlite::{
};
use edn;
use edn::{
InternSet,
};
use mentat_core::{
Attribute,
@ -50,13 +53,12 @@ use mentat_core::{
Keyword,
Schema,
StructuredMap,
TxReport,
TypedValue,
ValueRc,
ValueType,
};
use mentat_core::intern_set::InternSet;
use mentat_db::cache::{
InProgressCacheTransactWatcher,
InProgressSQLiteAttributeCache,
@ -73,7 +75,6 @@ use mentat_db::{
TransactWatcher,
TxObservationService,
TxObserver,
TxReport,
};
use mentat_db::internal_types::TermWithTempIds;
@ -401,8 +402,8 @@ impl<'a, 'c> InProgress<'a, 'c> {
/// This exists so you can make your own.
pub fn transact_builder(&mut self, builder: TermBuilder) -> Result<TxReport> {
builder.build()
.and_then(|(terms, tempid_set)| {
self.transact_terms(terms, tempid_set)
.and_then(|(terms, _tempid_set)| {
self.transact_entities(terms)
})
}

View file

@ -50,34 +50,27 @@
//
// The second is to expose a declarative, programmatic builder pattern for constructing entities.
//
// We probably need both, but this file provides the latter. Unfortunately, Entity -- the input to
// the transactor -- is intimately tied to EDN and to spanned values.
// We probably need both, but this file provides the latter.
use mentat_core::{
HasSchema,
KnownEntid,
Keyword,
TypedValue,
use edn::{
InternSet,
PlainSymbol,
ValueRc,
};
use mentat_core::intern_set::InternSet;
use mentat_core::util::Either;
use mentat_db::{
TxReport,
};
use mentat_db::internal_types::{
KnownEntidOr,
TempIdHandle,
Term,
TermWithTempIds,
TypedValueOr,
};
use edn::entities::{
AttributePlace,
Entity,
EntityPlace,
LookupRef,
OpType,
TempId,
TxFunction,
ValuePlace,
};
use mentat_core::{
TxReport,
TypedValue,
};
use conn::{
@ -85,66 +78,65 @@ use conn::{
};
use errors::{
MentatError,
Result,
};
pub type Terms = (Vec<TermWithTempIds>, InternSet<TempId>);
pub type Terms = (Vec<Entity<TypedValue>>, InternSet<TempId>);
pub struct TermBuilder {
tempids: InternSet<TempId>,
terms: Vec<TermWithTempIds>,
terms: Vec<Entity<TypedValue>>,
}
pub struct EntityBuilder<T: BuildTerms + Sized> {
builder: T,
entity: KnownEntidOr<TempIdHandle>,
entity: EntityPlace<TypedValue>,
}
pub trait BuildTerms where Self: Sized {
fn named_tempid(&mut self, name: String) -> TempIdHandle;
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: IntoThing<KnownEntidOr<TempIdHandle>>;
fn add<E, V>(&mut self, e: E, a: KnownEntid, v: V) -> Result<()>
where E: IntoThing<KnownEntidOr<TempIdHandle>>,
V: IntoThing<TypedValueOr<TempIdHandle>>;
fn retract<E, V>(&mut self, e: E, a: KnownEntid, v: V) -> Result<()>
where E: IntoThing<KnownEntidOr<TempIdHandle>>,
V: IntoThing<TypedValueOr<TempIdHandle>>;
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(&mut self, name: String) -> TempIdHandle {
self.tempids.intern(TempId::External(name))
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.into());
let e = self.named_tempid(name);
self.describe(e)
}
fn describe<E>(self, entity: E) -> EntityBuilder<Self> where E: IntoThing<KnownEntidOr<TempIdHandle>> {
fn describe<E>(self, entity: E) -> EntityBuilder<Self> where E: Into<EntityPlace<TypedValue>> {
EntityBuilder {
builder: self,
entity: entity.into_thing(),
entity: entity.into(),
}
}
fn add<E, V>(&mut self, e: E, a: KnownEntid, v: V) -> Result<()>
where E: IntoThing<KnownEntidOr<TempIdHandle>>,
V: IntoThing<TypedValueOr<TempIdHandle>> {
let e = e.into_thing();
let v = v.into_thing();
self.terms.push(Term::AddOrRetract(OpType::Add, e, a.into(), v));
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, V>(&mut self, e: E, a: KnownEntid, v: V) -> Result<()>
where E: IntoThing<KnownEntidOr<TempIdHandle>>,
V: IntoThing<TypedValueOr<TempIdHandle>> {
let e = e.into_thing();
let v = v.into_thing();
self.terms.push(Term::AddOrRetract(OpType::Retract, e, a.into(), 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.terms.push(Entity::AddOrRetract { op: OpType::Retract, e: e.into(), a: a.into(), v: v.into() });
Ok(())
}
}
@ -166,23 +158,35 @@ impl TermBuilder {
}
#[allow(dead_code)]
pub fn numbered_tempid(&mut self, id: i64) -> TempIdHandle {
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, KnownEntidOr<TempIdHandle>) {
pub fn finish(self) -> (T, EntityPlace<TypedValue>) {
(self.builder, self.entity)
}
pub fn add<V>(&mut self, a: KnownEntid, v: V) -> Result<()>
where V: IntoThing<TypedValueOr<TempIdHandle>> {
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<V>(&mut self, a: KnownEntid, v: V) -> Result<()>
where V: IntoThing<TypedValueOr<TempIdHandle>> {
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)
}
}
@ -207,8 +211,8 @@ impl<'a, 'c> InProgressBuilder<'a, 'c> {
let mut in_progress = self.in_progress;
let result = self.builder
.build()
.and_then(|(terms, tempid_set)| {
in_progress.transact_terms(terms, tempid_set)
.and_then(|(terms, _tempid_set)| {
in_progress.transact_entities(terms)
});
(in_progress, result)
}
@ -226,79 +230,38 @@ impl<'a, 'c> InProgressBuilder<'a, 'c> {
}
impl<'a, 'c> BuildTerms for InProgressBuilder<'a, 'c> {
fn named_tempid(&mut self, name: String) -> TempIdHandle {
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.into());
let e = self.builder.named_tempid(name.to_string());
self.describe(e)
}
fn describe<E>(self, entity: E) -> EntityBuilder<InProgressBuilder<'a, 'c>> where E: IntoThing<KnownEntidOr<TempIdHandle>> {
fn describe<E>(self, entity: E) -> EntityBuilder<InProgressBuilder<'a, 'c>> where E: Into<EntityPlace<TypedValue>> {
EntityBuilder {
builder: self,
entity: entity.into_thing(),
entity: entity.into(),
}
}
fn add<E, V>(&mut self, e: E, a: KnownEntid, v: V) -> Result<()>
where E: IntoThing<KnownEntidOr<TempIdHandle>>,
V: IntoThing<TypedValueOr<TempIdHandle>> {
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, V>(&mut self, e: E, a: KnownEntid, v: V) -> Result<()>
where E: IntoThing<KnownEntidOr<TempIdHandle>>,
V: IntoThing<TypedValueOr<TempIdHandle>> {
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> InProgressBuilder<'a, 'c> {
pub fn add_kw<E, V>(&mut self, e: E, a: &Keyword, v: V) -> Result<()>
where E: IntoThing<KnownEntidOr<TempIdHandle>>,
V: IntoThing<TypedValueOr<TempIdHandle>> {
let (attribute, value) = self.extract_kw_value(a, v.into_thing())?;
self.add(e, attribute, value)
}
pub fn retract_kw<E, V>(&mut self, e: E, a: &Keyword, v: V) -> Result<()>
where E: IntoThing<KnownEntidOr<TempIdHandle>>,
V: IntoThing<TypedValueOr<TempIdHandle>> {
let (attribute, value) = self.extract_kw_value(a, v.into_thing())?;
self.retract(e, attribute, value)
}
fn extract_kw_value(&mut self, a: &Keyword, v: TypedValueOr<TempIdHandle>) -> Result<(KnownEntid, TypedValueOr<TempIdHandle>)> {
let attribute: KnownEntid;
if let Some((attr, aa)) = self.in_progress.attribute_for_ident(a) {
if let Either::Left(ref tv) = v {
let provided = tv.value_type();
let expected = attr.value_type;
if provided != expected {
bail!(MentatError::ValueTypeMismatch(provided, expected));
}
}
attribute = aa;
} else {
bail!(MentatError::UnknownAttribute(a.to_string()));
}
Ok((attribute, v))
}
}
impl<'a, 'c> EntityBuilder<InProgressBuilder<'a, 'c>> {
pub fn add_kw<V>(&mut self, a: &Keyword, v: V) -> Result<()>
where V: IntoThing<TypedValueOr<TempIdHandle>> {
self.builder.add_kw(self.entity.clone(), a, v)
}
pub fn retract_kw<V>(&mut self, a: &Keyword, v: V) -> Result<()>
where V: IntoThing<TypedValueOr<TempIdHandle>> {
self.builder.retract_kw(self.entity.clone(), a, v)
}
/// Build the terms from this builder and transact them against the current
/// `InProgress`. This method _always_ returns the `InProgress` -- failure doesn't
/// imply an automatic rollback.
@ -313,69 +276,6 @@ impl<'a, 'c> EntityBuilder<InProgressBuilder<'a, 'c>> {
}
}
// Can't implement Into for Rc<T>.
pub trait IntoThing<T>: Sized {
fn into_thing(self) -> T;
}
pub trait FromThing<T> {
fn from_thing(v: T) -> Self;
}
impl<T> FromThing<T> for T {
fn from_thing(v: T) -> T {
v
}
}
impl<I, F> IntoThing<I> for F where I: FromThing<F> {
fn into_thing(self) -> I {
I::from_thing(self)
}
}
impl<'a> FromThing<&'a TempIdHandle> for TypedValueOr<TempIdHandle> {
fn from_thing(v: &'a TempIdHandle) -> Self {
Either::Right(v.clone())
}
}
impl FromThing<TempIdHandle> for TypedValueOr<TempIdHandle> {
fn from_thing(v: TempIdHandle) -> Self {
Either::Right(v)
}
}
impl FromThing<TypedValue> for TypedValueOr<TempIdHandle> {
fn from_thing(v: TypedValue) -> Self {
Either::Left(v)
}
}
impl FromThing<TempIdHandle> for KnownEntidOr<TempIdHandle> {
fn from_thing(v: TempIdHandle) -> Self {
Either::Right(v)
}
}
impl<'a> FromThing<&'a KnownEntid> for KnownEntidOr<TempIdHandle> {
fn from_thing(v: &'a KnownEntid) -> Self {
Either::Left(v.clone())
}
}
impl FromThing<KnownEntid> for KnownEntidOr<TempIdHandle> {
fn from_thing(v: KnownEntid) -> Self {
Either::Left(v)
}
}
impl FromThing<KnownEntid> for TypedValueOr<TempIdHandle> {
fn from_thing(v: KnownEntid) -> Self {
Either::Left(v.into())
}
}
#[cfg(test)]
mod testing {
extern crate mentat_db;
@ -384,9 +284,11 @@ mod testing {
Conn,
Entid,
HasSchema,
KnownEntid,
MentatError,
Queryable,
TypedValue,
TxReport,
TypedValue,
};
use super::*;
@ -399,7 +301,7 @@ mod testing {
#[test]
fn test_entity_builder_bogus_entids() {
let mut builder = TermBuilder::new();
let e = builder.named_tempid("x".into());
let e = builder.named_tempid("x");
let a1 = fake_known_entid(37); // :db/doc
let a2 = fake_known_entid(999);
let v = TypedValue::typed_string("Some attribute");
@ -419,7 +321,7 @@ mod testing {
let mut in_progress = conn.begin_transaction(&mut sqlite).expect("begun successfully");
// This should fail: unrecognized entid.
match in_progress.transact_terms(terms, tempids).expect_err("expected transact to fail") {
match in_progress.transact_entities(terms).expect_err("expected transact to fail") {
MentatError::DbError(e) => {
assert_eq!(e.kind(), mentat_db::DbErrorKind::UnrecognizedEntid(999));
},
@ -451,10 +353,10 @@ mod testing {
let a_many = in_progress.get_entid(&kw!(:foo/many)).expect(":foo/many");
let mut builder = in_progress.builder();
let e_x = builder.named_tempid("x".into());
let e_x = builder.named_tempid("x");
let v_many_1 = TypedValue::typed_string("Some text");
let v_many_2 = TypedValue::typed_string("Other text");
builder.add_kw(e_x.clone(), &kw!(:foo/many), v_many_1).expect("add succeeded");
builder.add(e_x.clone(), kw!(:foo/many), v_many_1).expect("add succeeded");
builder.add(e_x.clone(), a_many, v_many_2).expect("add succeeded");
builder.commit().expect("commit succeeded");
}
@ -489,8 +391,8 @@ mod testing {
// Scoped borrow of in_progress.
{
let mut builder = TermBuilder::new();
let e_x = builder.named_tempid("x".into());
let e_y = builder.named_tempid("y".into());
let e_x = builder.named_tempid("x");
let e_y = builder.named_tempid("y");
let a_ref = in_progress.get_entid(&foo_ref).expect(":foo/ref");
let a_one = in_progress.get_entid(&foo_one).expect(":foo/one");
let a_many = in_progress.get_entid(&foo_many).expect(":foo/many");
@ -508,7 +410,7 @@ mod testing {
assert_eq!(tempids.len(), 2);
assert_eq!(terms.len(), 4);
report = in_progress.transact_terms(terms, tempids).expect("add succeeded");
report = in_progress.transact_entities(terms).expect("add succeeded");
let x = report.tempids.get("x").expect("our tempid has an ID");
let y = report.tempids.get("y").expect("our tempid has an ID");
assert_eq!(in_progress.lookup_value_for_attribute(*y, &foo_ref).expect("lookup succeeded"),

View file

@ -41,6 +41,7 @@ pub use mentat_core::{
Keyword,
Schema,
Binding,
TxReport,
TypedValue,
Uuid,
Utc,
@ -56,7 +57,6 @@ pub use mentat_db::{
DB_SCHEMA_CORE,
AttributeSet,
TxObserver,
TxReport,
new_connection,
};

View file

@ -30,12 +30,12 @@ use mentat_core::{
Entid,
Keyword,
StructuredMap,
TxReport,
TypedValue,
ValueRc,
};
use mentat_db::{
TxObserver,
TxReport,
};
use mentat_tolstoy::Syncer;
@ -607,12 +607,12 @@ mod tests {
let name = format!("todo{}", i);
let uuid = Uuid::new_v4();
let mut builder = in_progress.builder().describe_tempid(&name);
builder.add_kw(&kw!(:todo/uuid), TypedValue::Uuid(uuid)).expect("Expected added uuid");
builder.add(kw!(:todo/uuid), TypedValue::Uuid(uuid)).expect("Expected added uuid");
changeset.insert(uuid_entid.clone());
builder.add_kw(&kw!(:todo/name), TypedValue::typed_string(&name)).expect("Expected added name");
builder.add(kw!(:todo/name), TypedValue::typed_string(&name)).expect("Expected added name");
changeset.insert(name_entid.clone());
if i % 2 == 0 {
builder.add_kw(&kw!(:todo/completion_date), TypedValue::current_instant()).expect("Expected added date");
builder.add(kw!(:todo/completion_date), TypedValue::current_instant()).expect("Expected added date");
changeset.insert(date_entid.clone());
}
let (ip, r) = builder.transact();
@ -622,8 +622,8 @@ mod tests {
in_progress = ip;
}
let mut builder = in_progress.builder().describe_tempid("Label");
builder.add_kw(&kw!(:label/name), TypedValue::typed_string("Label 1")).expect("Expected added name");
builder.add_kw(&kw!(:label/color), TypedValue::typed_string("blue")).expect("Expected added color");
builder.add(kw!(:label/name), TypedValue::typed_string("Label 1")).expect("Expected added name");
builder.add(kw!(:label/color), TypedValue::typed_string("blue")).expect("Expected added color");
builder.commit().expect("expect transaction to occur");
}
@ -678,8 +678,8 @@ mod tests {
for i in 0..3 {
let name = format!("label{}", i);
let mut builder = in_progress.builder().describe_tempid(&name);
builder.add_kw(&kw!(:label/name), TypedValue::typed_string(&name)).expect("Expected added name");
builder.add_kw(&kw!(:label/color), TypedValue::typed_string("blue")).expect("Expected added color");
builder.add(kw!(:label/name), TypedValue::typed_string(&name)).expect("Expected added name");
builder.add(kw!(:label/color), TypedValue::typed_string("blue")).expect("Expected added color");
let (ip, _) = builder.transact();
in_progress = ip;
}

View file

@ -812,14 +812,14 @@ impl VocabularySource for SimpleVocabularySource {
impl<'a, 'c> VocabularyMechanics for InProgress<'a, 'c> {
/// Turn the vocabulary into datoms, transact them, and on success return the outcome.
fn install_vocabulary(&mut self, definition: &Definition) -> Result<VocabularyOutcome> {
let (terms, tempids) = definition.description(self)?;
self.transact_terms(terms, tempids)?;
let (terms, _tempids) = definition.description(self)?;
self.transact_entities(terms)?;
Ok(VocabularyOutcome::Installed)
}
fn install_attributes_for<'definition>(&mut self, definition: &'definition Definition, attributes: Vec<&'definition (Keyword, Attribute)>) -> Result<VocabularyOutcome> {
let (terms, tempids) = definition.description_for_attributes(&attributes, self, None)?;
self.transact_terms(terms, tempids)?;
let (terms, _tempids) = definition.description_for_attributes(&attributes, self, None)?;
self.transact_entities(terms)?;
Ok(VocabularyOutcome::InstalledMissingAttributes)
}
@ -834,8 +834,8 @@ impl<'a, 'c> VocabularyMechanics for InProgress<'a, 'c> {
// TODO: don't do work for attributes that are unchanged. Here we rely on the transactor
// to elide duplicate datoms.
let (terms, tempids) = definition.description_diff(self, &from_version)?;
self.transact_terms(terms, tempids)?;
let (terms, _tempids) = definition.description_diff(self, &from_version)?;
self.transact_entities(terms)?;
definition.post(self, &from_version)?;
Ok(VocabularyOutcome::Upgraded)