Support :db/noHistory for attributes. (#622) r=nalexander

At this point we never discard history, but this completes the API support for doing so.
This commit is contained in:
Richard Newman 2018-04-03 14:23:46 -07:00 committed by GitHub
parent 9cc5cbf288
commit 6c54e1d370
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 56 additions and 7 deletions

View file

@ -700,6 +700,9 @@ pub struct Attribute {
/// They are used to compose entities from component sub-entities: they are fetched recursively
/// by pull expressions, and they are automatically recursively deleted where appropriate.
pub component: bool,
/// `true` if this attribute doesn't require history to be kept, i.e., it is `:db/noHistory true`.
pub no_history: bool,
}
impl Attribute {
@ -750,6 +753,10 @@ impl Attribute {
attribute_map.insert(values::DB_IS_COMPONENT.clone(), edn::Value::Boolean(true));
}
if self.no_history {
attribute_map.insert(values::DB_NO_HISTORY.clone(), edn::Value::Boolean(true));
}
edn::Value::Map(attribute_map)
}
}
@ -764,6 +771,7 @@ impl Default for Attribute {
multival: false,
unique: None,
component: false,
no_history: false,
}
}
}
@ -894,6 +902,7 @@ mod test {
unique: None,
multival: false,
component: false,
no_history: false,
};
assert!(attr1.flags() & AttributeBitFlags::IndexAVET as u8 != 0);
@ -908,6 +917,7 @@ mod test {
unique: Some(attribute::Unique::Value),
multival: false,
component: false,
no_history: false,
};
assert!(attr2.flags() & AttributeBitFlags::IndexAVET as u8 == 0);
@ -922,6 +932,7 @@ mod test {
unique: Some(attribute::Unique::Identity),
multival: false,
component: false,
no_history: false,
};
assert!(attr3.flags() & AttributeBitFlags::IndexAVET as u8 == 0);
@ -954,6 +965,7 @@ mod test {
unique: None,
multival: false,
component: false,
no_history: true,
};
associate_ident(&mut schema, NamespacedKeyword::new("foo", "bar"), 97);
add_attribute(&mut schema, 97, attr1);
@ -965,6 +977,7 @@ mod test {
unique: Some(attribute::Unique::Value),
multival: true,
component: false,
no_history: false,
};
associate_ident(&mut schema, NamespacedKeyword::new("foo", "bas"), 98);
add_attribute(&mut schema, 98, attr2);
@ -976,6 +989,7 @@ mod test {
unique: Some(attribute::Unique::Identity),
multival: false,
component: true,
no_history: false,
};
associate_ident(&mut schema, NamespacedKeyword::new("foo", "bat"), 99);
@ -986,7 +1000,8 @@ mod test {
let expected_output = r#"[ { :db/ident :foo/bar
:db/valueType :db.type/ref
:db/cardinality :db.cardinality/one
:db/index true },
:db/index true
:db/noHistory true },
{ :db/ident :foo/bas
:db/valueType :db.type/string
:db/cardinality :db.cardinality/many

View file

@ -47,6 +47,7 @@ lazy_static_namespaced_keyword_value!(DB_IDENT, "db", "ident");
lazy_static_namespaced_keyword_value!(DB_INDEX, "db", "index");
lazy_static_namespaced_keyword_value!(DB_INSTALL_ATTRIBUTE, "db.install", "attribute");
lazy_static_namespaced_keyword_value!(DB_IS_COMPONENT, "db", "component");
lazy_static_namespaced_keyword_value!(DB_NO_HISTORY, "db", "noHistory");
lazy_static_namespaced_keyword_value!(DB_PART_DB, "db.part", "db");
lazy_static_namespaced_keyword_value!(DB_RETRACT, "db", "retract");
lazy_static_namespaced_keyword_value!(DB_TYPE_BOOLEAN, "db.type", "boolean");

View file

@ -171,6 +171,13 @@ pub fn update_attribute_map_from_entid_triples<U>(attribute_map: &mut AttributeM
}
},
entids::DB_NO_HISTORY => {
match *value {
TypedValue::Boolean(x) => { builder.no_history(x); },
_ => bail!(ErrorKind::BadSchemaAssertion(format!("Expected [... :db/noHistory true|false] but got [... :db/noHistory {:?}]", value)))
}
},
_ => {
bail!(ErrorKind::BadSchemaAssertion(format!("Do not recognize attribute {} for entid {}", attr, entid)))
}

View file

@ -79,6 +79,7 @@ pub struct AttributeBuilder {
index: Option<bool>,
fulltext: Option<bool>,
component: Option<bool>,
no_history: Option<bool>,
}
impl AttributeBuilder {
@ -127,6 +128,11 @@ impl AttributeBuilder {
self
}
pub fn no_history<'a>(&'a mut self, no_history: bool) -> &'a mut Self {
self.no_history = Some(no_history);
self
}
pub fn validate_install_attribute(&self) -> Result<()> {
if self.value_type.is_none() {
bail!(ErrorKind::BadSchemaAssertion("Schema attribute for new attribute does not set :db/valueType".into()));
@ -164,6 +170,9 @@ impl AttributeBuilder {
if let Some(component) = self.component {
attribute.component = component;
}
if let Some(no_history) = self.no_history {
attribute.no_history = no_history;
}
attribute
}
@ -194,6 +203,12 @@ impl AttributeBuilder {
mutations.push(AttributeAlteration::IsComponent);
}
}
if let Some(no_history) = self.no_history {
if no_history != attribute.no_history {
attribute.no_history = no_history;
mutations.push(AttributeAlteration::NoHistory);
}
}
mutations
}
@ -326,6 +341,7 @@ mod test {
unique: None,
multival: false,
component: false,
no_history: false,
});
// attribute is unique by value and an index
add_attribute(&mut schema, NamespacedKeyword::new("foo", "baz"), 98, Attribute {
@ -335,6 +351,7 @@ mod test {
unique: Some(attribute::Unique::Value),
multival: false,
component: false,
no_history: false,
});
// attribue is unique by identity and an index
add_attribute(&mut schema, NamespacedKeyword::new("foo", "bat"), 99, Attribute {
@ -344,6 +361,7 @@ mod test {
unique: Some(attribute::Unique::Identity),
multival: false,
component: false,
no_history: false,
});
// attribute is a components and a `Ref`
add_attribute(&mut schema, NamespacedKeyword::new("foo", "bak"), 100, Attribute {
@ -353,6 +371,7 @@ mod test {
unique: None,
multival: false,
component: true,
no_history: false,
});
// fulltext attribute is a string and an index
add_attribute(&mut schema, NamespacedKeyword::new("foo", "bap"), 101, Attribute {
@ -362,6 +381,7 @@ mod test {
unique: None,
multival: false,
component: false,
no_history: false,
});
assert!(validate_attribute_map(&schema.entid_map, &schema.attribute_map).is_ok());
@ -379,6 +399,7 @@ mod test {
unique: Some(attribute::Unique::Value),
multival: false,
component: false,
no_history: false,
});
let err = validate_attribute_map(&schema.entid_map, &schema.attribute_map).err();
@ -401,6 +422,7 @@ mod test {
unique: Some(attribute::Unique::Identity),
multival: false,
component: false,
no_history: false,
});
let err = validate_attribute_map(&schema.entid_map, &schema.attribute_map).err();
@ -423,6 +445,7 @@ mod test {
unique: None,
multival: false,
component: true,
no_history: false,
});
let err = validate_attribute_map(&schema.entid_map, &schema.attribute_map).err();
@ -445,6 +468,7 @@ mod test {
unique: None,
multival: false,
component: false,
no_history: false,
});
let err = validate_attribute_map(&schema.entid_map, &schema.attribute_map).err();
@ -466,6 +490,7 @@ mod test {
unique: None,
multival: false,
component: false,
no_history: false,
});
let err = validate_attribute_map(&schema.entid_map, &schema.attribute_map).err();

View file

@ -207,10 +207,9 @@ lazy_static! {
kw!(:db.cardinality/many)
};
// Not yet supported.
// static ref DB_NO_HISTORY: NamespacedKeyword = {
// NamespacedKeyword::new("db", "noHistory")
// };
static ref DB_NO_HISTORY: NamespacedKeyword = {
NamespacedKeyword::new("db", "noHistory")
};
}
trait HasCoreSchema {
@ -260,8 +259,7 @@ impl Definition {
let a_value_type = via.core_attribute(&DB_VALUE_TYPE)?;
let a_unique = via.core_attribute(&DB_UNIQUE)?;
// Not yet supported.
// let a_no_history = via.core_attribute(&DB_NO_HISTORY)?;
let a_no_history = via.core_attribute(&DB_NO_HISTORY)?;
let v_cardinality_many = via.core_entid(&DB_CARDINALITY_MANY)?;
let v_cardinality_one = via.core_entid(&DB_CARDINALITY_ONE)?;
@ -310,6 +308,9 @@ impl Definition {
if attr.component {
builder.add(tempid.clone(), a_is_component, TypedValue::Boolean(true))?;
}
if attr.no_history {
builder.add(tempid.clone(), a_no_history, TypedValue::Boolean(true))?;
}
if let Some(u) = attr.unique {
let uu = match u {