* Part 1 - Create as_edn_value function. * Do not include defaults inside output. * Pretty-printed by default. Do we want to make that a flag? * Includes simple test just to make sure it works. * Part 2 - only include ident if available. * Part 3 - Remove spacing and newlines as unnecessary. * Update function to build edn::Value directly rather than parsing from string * Update test to actually test the functionality. * Address review comments ncalexan. * Rename `as_edn_value` to `to_edn_value`. * Move `db/src/values.rs` to `core/src/values.rs` so we can reference inside `core/src/ib.rs`. * Add `lazy-static` crate to core `Cargo.toml` * Expose `values` as a public module from `core`. * Update references to values in `db/src/bootstrap.rs` & `db/src/lib.rs`. * Add new static vars for `DB_FULLTEXT`, `DB_INDEX` & `DB_IS_COMPONENT`. * Use static vars exposed in `values` inside `to_edn_value`. * Remove `db/id` as key in attribute output and use `entid` as `db/ident` if no `ident` is found for that `entid`. * Update test to match new expected output. * Add doc comment for function * Address review comments ncalexan. * Update function docstring to give clearer description of function. * Do not all entid at all to output. * Clean up code fetching ident (make it rustier). * Address review comments rnewman. * Extract out to new `to_edn_value` functions code for creating `edn::Value`\'s for `ValueType` and `Attribute`. * Use `map()` to create schema edn value rather than a loop. * Address review comments rnewman. * pass cloned instance of ident to `Attribute::get_edn_value`. * update `use` import for `edn`. * remove unnecessary call when using ident as key on `associate_ident`. * Fixed bug whereby we didn't differentiate between `db.index/value` and `db.index/identity` when generating `edn::Value` * Add extra assert at the end to ensure we get the same output when we convert the same schema to edn multiple times * Move check for type of uniqueness to `match` statement. * Also use `iter` instead of `into_iter` when iterating schema map.
This commit is contained in:
parent
b24db01744
commit
8e6f37e709
5 changed files with 135 additions and 3 deletions
|
@ -6,6 +6,7 @@ workspace = ".."
|
|||
[dependencies]
|
||||
num = "0.1.35"
|
||||
ordered-float = "0.4.0"
|
||||
lazy_static = "0.2.2"
|
||||
|
||||
[dependencies.edn]
|
||||
path = "../edn"
|
||||
|
|
131
core/src/lib.rs
131
core/src/lib.rs
|
@ -8,9 +8,14 @@
|
|||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
extern crate edn;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate ordered_float;
|
||||
|
||||
extern crate edn;
|
||||
|
||||
pub mod values;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use self::ordered_float::OrderedFloat;
|
||||
use self::edn::NamespacedKeyword;
|
||||
|
@ -37,6 +42,20 @@ pub enum ValueType {
|
|||
Keyword,
|
||||
}
|
||||
|
||||
impl ValueType {
|
||||
pub fn to_edn_value(&self) -> edn::Value {
|
||||
match self {
|
||||
&ValueType::Ref => values::DB_TYPE_REF.clone(),
|
||||
&ValueType::Boolean => values::DB_TYPE_BOOLEAN.clone(),
|
||||
&ValueType::Instant => values::DB_TYPE_INSTANT.clone(),
|
||||
&ValueType::Long => values::DB_TYPE_LONG.clone(),
|
||||
&ValueType::Double => values::DB_TYPE_DOUBLE.clone(),
|
||||
&ValueType::String => values::DB_TYPE_STRING.clone(),
|
||||
&ValueType::Keyword => values::DB_TYPE_KEYWORD.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a Mentat value in a particular value set.
|
||||
// TODO: expand to include :db.type/{instant,url,uuid}.
|
||||
// TODO: BigInt?
|
||||
|
@ -213,6 +232,37 @@ impl Attribute {
|
|||
}
|
||||
flags
|
||||
}
|
||||
|
||||
pub fn to_edn_value(&self, ident: Option<NamespacedKeyword>) -> edn::Value {
|
||||
let mut attribute_map: BTreeMap<edn::Value, edn::Value> = BTreeMap::default();
|
||||
if let Some(ident) = ident {
|
||||
attribute_map.insert(values::DB_IDENT.clone(), edn::Value::NamespacedKeyword(ident));
|
||||
}
|
||||
|
||||
attribute_map.insert(values::DB_VALUE_TYPE.clone(), self.value_type.to_edn_value());
|
||||
|
||||
attribute_map.insert(values::DB_CARDINALITY.clone(), if self.multival { values::DB_CARDINALITY_MANY.clone() } else { values::DB_CARDINALITY_ONE.clone() });
|
||||
|
||||
match self.unique {
|
||||
Some(attribute::Unique::Value) => { attribute_map.insert(values::DB_UNIQUE.clone(), values::DB_UNIQUE_VALUE.clone()); },
|
||||
Some(attribute::Unique::Identity) => { attribute_map.insert(values::DB_UNIQUE.clone(), values::DB_UNIQUE_IDENTITY.clone()); },
|
||||
None => (),
|
||||
}
|
||||
|
||||
if self.index {
|
||||
attribute_map.insert(values::DB_INDEX.clone(), edn::Value::Boolean(true));
|
||||
}
|
||||
|
||||
if self.fulltext {
|
||||
attribute_map.insert(values::DB_FULLTEXT.clone(), edn::Value::Boolean(true));
|
||||
}
|
||||
|
||||
if self.component {
|
||||
attribute_map.insert(values::DB_IS_COMPONENT.clone(), edn::Value::Boolean(true));
|
||||
}
|
||||
|
||||
edn::Value::Map(attribute_map)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Attribute {
|
||||
|
@ -291,12 +341,29 @@ impl Schema {
|
|||
pub fn identifies_attribute(&self, x: &NamespacedKeyword) -> bool {
|
||||
self.get_entid(x).map(|e| self.is_attribute(e)).unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Returns an symbolic representation of the schema suitable for applying across Mentat stores.
|
||||
pub fn to_edn_value(&self) -> edn::Value {
|
||||
edn::Value::Vector((&self.schema_map).iter()
|
||||
.map(|(entid, attribute)|
|
||||
attribute.to_edn_value(self.get_ident(*entid).cloned()))
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
fn associate_ident(schema: &mut Schema, i: NamespacedKeyword, e: Entid) {
|
||||
schema.entid_map.insert(e, i.clone());
|
||||
schema.ident_map.insert(i, e);
|
||||
}
|
||||
|
||||
fn add_attribute(schema: &mut Schema, e: Entid, a: Attribute) {
|
||||
schema.schema_map.insert(e, a);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_attribute_flags() {
|
||||
let attr1 = Attribute {
|
||||
|
@ -341,6 +408,68 @@ mod test {
|
|||
assert!(attr3.flags() & AttributeBitFlags::IndexFulltext as u8 != 0);
|
||||
assert!(attr3.flags() & AttributeBitFlags::UniqueValue as u8 != 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_as_edn_value() {
|
||||
let mut schema = Schema::default();
|
||||
|
||||
let attr1 = Attribute {
|
||||
index: true,
|
||||
value_type: ValueType::Ref,
|
||||
fulltext: false,
|
||||
unique: None,
|
||||
multival: false,
|
||||
component: false,
|
||||
};
|
||||
associate_ident(&mut schema, NamespacedKeyword::new("foo", "bar"), 97);
|
||||
add_attribute(&mut schema, 97, attr1);
|
||||
|
||||
let attr2 = Attribute {
|
||||
index: false,
|
||||
value_type: ValueType::String,
|
||||
fulltext: true,
|
||||
unique: Some(attribute::Unique::Value),
|
||||
multival: true,
|
||||
component: false,
|
||||
};
|
||||
associate_ident(&mut schema, NamespacedKeyword::new("foo", "bas"), 98);
|
||||
add_attribute(&mut schema, 98, attr2);
|
||||
|
||||
let attr3 = Attribute {
|
||||
index: false,
|
||||
value_type: ValueType::Boolean,
|
||||
fulltext: false,
|
||||
unique: Some(attribute::Unique::Identity),
|
||||
multival: false,
|
||||
component: true,
|
||||
};
|
||||
|
||||
associate_ident(&mut schema, NamespacedKeyword::new("foo", "bat"), 99);
|
||||
add_attribute(&mut schema, 99, attr3);
|
||||
|
||||
let value = schema.to_edn_value();
|
||||
|
||||
let expected_output = r#"[ { :db/ident :foo/bar
|
||||
:db/valueType :db.type/ref
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/index true },
|
||||
{ :db/ident :foo/bas
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/many
|
||||
:db/unique :db.unique/value
|
||||
:db/fulltext true },
|
||||
{ :db/ident :foo/bat
|
||||
:db/valueType :db.type/boolean
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/unique :db.unique/identity
|
||||
:db/component true }, ]"#;
|
||||
let expected_value = edn::parse::value(&expected_output).expect("to be able to parse").without_spans();
|
||||
assert_eq!(expected_value, value);
|
||||
|
||||
// let's compare the whole thing again, just to make sure we are not changing anything when we convert to edn.
|
||||
let value2 = schema.to_edn_value();
|
||||
assert_eq!(expected_value, value2);
|
||||
}
|
||||
}
|
||||
|
||||
pub mod intern_set;
|
||||
|
|
|
@ -42,8 +42,11 @@ lazy_static_namespaced_keyword_value!(DB_ALTER_ATTRIBUTE, "db.alter", "attribute
|
|||
lazy_static_namespaced_keyword_value!(DB_CARDINALITY, "db", "cardinality");
|
||||
lazy_static_namespaced_keyword_value!(DB_CARDINALITY_MANY, "db.cardinality", "many");
|
||||
lazy_static_namespaced_keyword_value!(DB_CARDINALITY_ONE, "db.cardinality", "one");
|
||||
lazy_static_namespaced_keyword_value!(DB_FULLTEXT, "db", "fulltext");
|
||||
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_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");
|
|
@ -22,10 +22,10 @@ use mentat_core::{
|
|||
IdentMap,
|
||||
Schema,
|
||||
TypedValue,
|
||||
values,
|
||||
};
|
||||
use schema::SchemaBuilding;
|
||||
use types::{Partition, PartitionMap};
|
||||
use values;
|
||||
|
||||
/// The first transaction ID applied to the knowledge base.
|
||||
///
|
||||
|
|
|
@ -39,7 +39,6 @@ mod schema;
|
|||
mod types;
|
||||
mod internal_types;
|
||||
mod upsert_resolution;
|
||||
mod values;
|
||||
mod tx;
|
||||
|
||||
pub use db::{
|
||||
|
|
Loading…
Reference in a new issue