Part 5: Make existing TermBuilder actually build Entity instances.

There are a few tricky details to call out here.  The first is the
`TransactableValueMarker` trait.  This is strictly a marker (like
`Sized`, for example) to give some control over what types can be used
as value types in `Entity` instances.  This expression is needed due
to the network of `Into` and `From` relations between the parts of
valid `Entity` instances.  This allows to drop the `IntoThing`
work-around trait and use the established patterns.  (Observe that
`KnownEntid` makes this a little harder, due to the cross-crate
consistency restrictions.)

The second is that we can get rid `{add,retract}_kw`, since the
network of relations expresses the coercions directly.

The third is that this commit doesn't change the name `TermBuilder`,
even though it is now building `Entity` instances.  This is because
there's _already_ an `EntityBuilder` which fixes the `EntityPlace`.
It's not clear whether the existing entity building interface should
be removed or whether both should be renamed.  That can be follow-up.
This commit is contained in:
Nick Alexander 2018-07-03 12:45:02 -07:00
parent 76507623ac
commit 1cb1847aa6
7 changed files with 246 additions and 218 deletions

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

@ -22,6 +22,20 @@ use symbols::{
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)]
@ -54,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 {
@ -105,6 +131,54 @@ 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),
@ -113,11 +187,47 @@ pub enum EntityPlace<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

@ -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

@ -402,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,73 +50,65 @@
//
// 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 edn::{
InternSet,
ValueRc,
};
use edn::entities::{
AttributePlace,
Entity,
EntityPlace,
OpType,
TempId,
ValuePlace,
};
use mentat_core::{
HasSchema,
KnownEntid,
Keyword,
TypedValue,
};
use mentat_core::util::Either;
use mentat_db::{
TxReport,
};
use mentat_db::internal_types::{
KnownEntidOr,
TempIdHandle,
Term,
TermWithTempIds,
TypedValueOr,
};
use conn::{
InProgress,
};
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(&mut self, name: String) -> ValueRc<TempId>;
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 {
fn named_tempid(&mut self, name: String) -> ValueRc<TempId> {
self.tempids.intern(TempId::External(name))
}
@ -125,28 +117,26 @@ impl BuildTerms for TermBuilder {
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(())
}
}
@ -168,23 +158,25 @@ 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))
}
}
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)
}
}
@ -209,8 +201,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)
}
@ -228,7 +220,7 @@ 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(&mut self, name: String) -> ValueRc<TempId> {
self.builder.named_tempid(name)
}
@ -237,70 +229,29 @@ impl<'a, 'c> BuildTerms for InProgressBuilder<'a, 'c> {
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.
@ -315,69 +266,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;
@ -386,6 +274,8 @@ mod testing {
Conn,
Entid,
HasSchema,
KnownEntid,
MentatError,
Queryable,
TypedValue,
TxReport,
@ -421,7 +311,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));
},
@ -456,7 +346,7 @@ mod testing {
let e_x = builder.named_tempid("x".into());
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");
}
@ -510,7 +400,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

@ -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)