From a59f9583acbb192223e90128078ad3239d9e2ff7 Mon Sep 17 00:00:00 2001 From: Jordan Santell Date: Fri, 17 Feb 2017 13:55:36 -0800 Subject: [PATCH] Store Idents as NamespacedKeywords, rather than Strings. Fixes #291. (#300) r=ncalexander --- core/src/lib.rs | 18 +++--- db/src/bootstrap.rs | 127 +++++++++++++++++++------------------ db/src/db.rs | 40 ++++++++++-- db/src/debug.rs | 2 +- db/src/lib.rs | 1 + db/src/schema.rs | 21 +++--- db/src/tx.rs | 4 +- edn/src/symbols.rs | 15 +++++ query-algebrizer/src/cc.rs | 16 ++--- 9 files changed, 145 insertions(+), 99 deletions(-) diff --git a/core/src/lib.rs b/core/src/lib.rs index ba072337..4872c351 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -177,12 +177,11 @@ impl Default for Attribute { } } -/// Map `String` idents (`:db/ident`) to positive integer entids (`1`). -/// TODO: these should all be parsed into NamespacedKeywords on entry. #291. -pub type IdentMap = BTreeMap; +/// Map `NamespacedKeyword` idents (`:db/ident`) to positive integer entids (`1`). +pub type IdentMap = BTreeMap; -/// Map positive integer entids (`1`) to `String` idents (`:db/ident`). -pub type EntidMap = BTreeMap; +/// Map positive integer entids (`1`) to `NamespacedKeyword` idents (`:db/ident`). +pub type EntidMap = BTreeMap; /// Map attribute entids to `Attribute` instances. pub type SchemaMap = BTreeMap; @@ -214,11 +213,11 @@ pub struct Schema { } impl Schema { - pub fn get_ident(&self, x: Entid) -> Option<&String> { + pub fn get_ident(&self, x: Entid) -> Option<&NamespacedKeyword> { self.entid_map.get(&x) } - pub fn get_entid(&self, x: &String) -> Option { + pub fn get_entid(&self, x: &NamespacedKeyword) -> Option { self.ident_map.get(x).map(|x| *x) } @@ -227,8 +226,7 @@ impl Schema { } pub fn attribute_for_ident(&self, ident: &NamespacedKeyword) -> Option<&Attribute> { - let s = ident.to_string(); // TODO: don't do this. #291. - self.get_entid(&s) + self.get_entid(&ident) .and_then(|x| self.attribute_for_entid(x)) } @@ -238,7 +236,7 @@ impl Schema { } /// Return true if the provided ident identifies an attribute in this schema. - pub fn identifies_attribute(&self, x: &String) -> bool { + pub fn identifies_attribute(&self, x: &NamespacedKeyword) -> bool { self.get_entid(x).map(|e| self.is_attribute(e)).unwrap_or(false) } } diff --git a/db/src/bootstrap.rs b/db/src/bootstrap.rs index d6a23a64..934bcdd0 100644 --- a/db/src/bootstrap.rs +++ b/db/src/bootstrap.rs @@ -14,6 +14,7 @@ use ::{to_namespaced_keyword}; use edn; use errors::{ErrorKind, Result}; use edn::types::Value; +use edn::symbols; use entids; use db::TypedSQLValue; use mentat_tx::entities::Entity; @@ -33,63 +34,63 @@ use values; pub const TX0: i64 = 0x10000000; lazy_static! { - static ref V1_IDENTS: Vec<(&'static str, i64)> = { - vec![(":db/ident", entids::DB_IDENT), - (":db.part/db", entids::DB_PART_DB), - (":db/txInstant", entids::DB_TX_INSTANT), - (":db.install/partition", entids::DB_INSTALL_PARTITION), - (":db.install/valueType", entids::DB_INSTALL_VALUETYPE), - (":db.install/attribute", entids::DB_INSTALL_ATTRIBUTE), - (":db/valueType", entids::DB_VALUE_TYPE), - (":db/cardinality", entids::DB_CARDINALITY), - (":db/unique", entids::DB_UNIQUE), - (":db/isComponent", entids::DB_IS_COMPONENT), - (":db/index", entids::DB_INDEX), - (":db/fulltext", entids::DB_FULLTEXT), - (":db/noHistory", entids::DB_NO_HISTORY), - (":db/add", entids::DB_ADD), - (":db/retract", entids::DB_RETRACT), - (":db.part/user", entids::DB_PART_USER), - (":db.part/tx", entids::DB_PART_TX), - (":db/excise", entids::DB_EXCISE), - (":db.excise/attrs", entids::DB_EXCISE_ATTRS), - (":db.excise/beforeT", entids::DB_EXCISE_BEFORE_T), - (":db.excise/before", entids::DB_EXCISE_BEFORE), - (":db.alter/attribute", entids::DB_ALTER_ATTRIBUTE), - (":db.type/ref", entids::DB_TYPE_REF), - (":db.type/keyword", entids::DB_TYPE_KEYWORD), - (":db.type/long", entids::DB_TYPE_LONG), - (":db.type/double", entids::DB_TYPE_DOUBLE), - (":db.type/string", entids::DB_TYPE_STRING), - (":db.type/boolean", entids::DB_TYPE_BOOLEAN), - (":db.type/instant", entids::DB_TYPE_INSTANT), - (":db.type/bytes", entids::DB_TYPE_BYTES), - (":db.cardinality/one", entids::DB_CARDINALITY_ONE), - (":db.cardinality/many", entids::DB_CARDINALITY_MANY), - (":db.unique/value", entids::DB_UNIQUE_VALUE), - (":db.unique/identity", entids::DB_UNIQUE_IDENTITY), - (":db/doc", entids::DB_DOC), + static ref V1_IDENTS: Vec<(symbols::NamespacedKeyword, i64)> = { + vec![(ns_keyword!("db", "ident"), entids::DB_IDENT), + (ns_keyword!("db.part", "db"), entids::DB_PART_DB), + (ns_keyword!("db", "txInstant"), entids::DB_TX_INSTANT), + (ns_keyword!("db.install", "partition"), entids::DB_INSTALL_PARTITION), + (ns_keyword!("db.install", "valueType"), entids::DB_INSTALL_VALUETYPE), + (ns_keyword!("db.install", "attribute"), entids::DB_INSTALL_ATTRIBUTE), + (ns_keyword!("db", "valueType"), entids::DB_VALUE_TYPE), + (ns_keyword!("db", "cardinality"), entids::DB_CARDINALITY), + (ns_keyword!("db", "unique"), entids::DB_UNIQUE), + (ns_keyword!("db", "isComponent"), entids::DB_IS_COMPONENT), + (ns_keyword!("db", "index"), entids::DB_INDEX), + (ns_keyword!("db", "fulltext"), entids::DB_FULLTEXT), + (ns_keyword!("db", "noHistory"), entids::DB_NO_HISTORY), + (ns_keyword!("db", "add"), entids::DB_ADD), + (ns_keyword!("db", "retract"), entids::DB_RETRACT), + (ns_keyword!("db.part", "user"), entids::DB_PART_USER), + (ns_keyword!("db.part", "tx"), entids::DB_PART_TX), + (ns_keyword!("db", "excise"), entids::DB_EXCISE), + (ns_keyword!("db.excise", "attrs"), entids::DB_EXCISE_ATTRS), + (ns_keyword!("db.excise", "beforeT"), entids::DB_EXCISE_BEFORE_T), + (ns_keyword!("db.excise", "before"), entids::DB_EXCISE_BEFORE), + (ns_keyword!("db.alter", "attribute"), entids::DB_ALTER_ATTRIBUTE), + (ns_keyword!("db.type", "ref"), entids::DB_TYPE_REF), + (ns_keyword!("db.type", "keyword"), entids::DB_TYPE_KEYWORD), + (ns_keyword!("db.type", "long"), entids::DB_TYPE_LONG), + (ns_keyword!("db.type", "double"), entids::DB_TYPE_DOUBLE), + (ns_keyword!("db.type", "string"), entids::DB_TYPE_STRING), + (ns_keyword!("db.type", "boolean"), entids::DB_TYPE_BOOLEAN), + (ns_keyword!("db.type", "instant"), entids::DB_TYPE_INSTANT), + (ns_keyword!("db.type", "bytes"), entids::DB_TYPE_BYTES), + (ns_keyword!("db.cardinality", "one"), entids::DB_CARDINALITY_ONE), + (ns_keyword!("db.cardinality", "many"), entids::DB_CARDINALITY_MANY), + (ns_keyword!("db.unique", "value"), entids::DB_UNIQUE_VALUE), + (ns_keyword!("db.unique", "identity"), entids::DB_UNIQUE_IDENTITY), + (ns_keyword!("db", "doc"), entids::DB_DOC), ] }; - static ref V2_IDENTS: Vec<(&'static str, i64)> = { + static ref V2_IDENTS: Vec<(symbols::NamespacedKeyword, i64)> = { [(*V1_IDENTS).clone(), - vec![(":db.schema/version", entids::DB_SCHEMA_VERSION), - (":db.schema/attribute", entids::DB_SCHEMA_ATTRIBUTE), + vec![(ns_keyword!("db.schema", "version"), entids::DB_SCHEMA_VERSION), + (ns_keyword!("db.schema", "attribute"), entids::DB_SCHEMA_ATTRIBUTE), ]].concat() }; - static ref V1_PARTS: Vec<(&'static str, i64, i64)> = { - vec![(":db.part/db", 0, (1 + V1_IDENTS.len()) as i64), - (":db.part/user", 0x10000, 0x10000), - (":db.part/tx", TX0, TX0), + static ref V1_PARTS: Vec<(symbols::NamespacedKeyword, i64, i64)> = { + vec![(ns_keyword!("db.part", "db"), 0, (1 + V1_IDENTS.len()) as i64), + (ns_keyword!("db.part", "user"), 0x10000, 0x10000), + (ns_keyword!("db.part", "tx"), TX0, TX0), ] }; - static ref V2_PARTS: Vec<(&'static str, i64, i64)> = { - vec![(":db.part/db", 0, (1 + V2_IDENTS.len()) as i64), - (":db.part/user", 0x10000, 0x10000), - (":db.part/tx", TX0, TX0), + static ref V2_PARTS: Vec<(symbols::NamespacedKeyword, i64, i64)> = { + vec![(ns_keyword!("db.part", "db"), 0, (1 + V2_IDENTS.len()) as i64), + (ns_keyword!("db.part", "user"), 0x10000, 0x10000), + (ns_keyword!("db.part", "tx"), TX0, TX0), ] }; @@ -156,36 +157,37 @@ lazy_static! { } /// Convert (ident, entid) pairs into [:db/add IDENT :db/ident IDENT] `Value` instances. -fn idents_to_assertions(idents: &[(&str, i64)]) -> Vec { +fn idents_to_assertions(idents: &[(symbols::NamespacedKeyword, i64)]) -> Vec { idents .into_iter() - .map(|&(ident, _)| { - let value = Value::NamespacedKeyword(to_namespaced_keyword(&ident).unwrap()); + .map(|&(ref ident, _)| { + let value = Value::NamespacedKeyword(ident.clone()); Value::Vector(vec![values::DB_ADD.clone(), value.clone(), values::DB_IDENT.clone(), value.clone()]) }) .collect() } -/// Convert {:ident {:key :value ...} ...} to vec![(String(:ident), String(:key), TypedValue(:value)), ...]. +/// Convert {:ident {:key :value ...} ...} to +/// vec![(symbols::NamespacedKeyword(:ident), symbols::NamespacedKeyword(:key), TypedValue(:value)), ...]. /// /// Such triples are closer to what the transactor will produce when processing /// :db.install/attribute assertions. -fn symbolic_schema_to_triples(ident_map: &IdentMap, symbolic_schema: &Value) -> Result> { +fn symbolic_schema_to_triples(ident_map: &IdentMap, symbolic_schema: &Value) -> Result> { // Failure here is a coding error, not a runtime error. - let mut triples: Vec<(String, String, TypedValue)> = vec![]; + let mut triples: Vec<(symbols::NamespacedKeyword, symbols::NamespacedKeyword, TypedValue)> = vec![]; // TODO: Consider `flat_map` and `map` rather than loop. match *symbolic_schema { Value::Map(ref m) => { for (ident, mp) in m { let ident = match ident { - &Value::NamespacedKeyword(ref ident) => ident.to_string(), + &Value::NamespacedKeyword(ref ident) => ident, _ => bail!(ErrorKind::BadBootstrapDefinition(format!("Expected namespaced keyword for ident but got '{:?}'", ident))) }; match *mp { Value::Map(ref mpp) => { for (attr, value) in mpp { let attr = match attr { - &Value::NamespacedKeyword(ref attr) => attr.to_string(), + &Value::NamespacedKeyword(ref attr) => attr, _ => bail!(ErrorKind::BadBootstrapDefinition(format!("Expected namespaced keyword for attr but got '{:?}'", attr))) }; @@ -198,14 +200,17 @@ fn symbolic_schema_to_triples(ident_map: &IdentMap, symbolic_schema: &Value) -> // bootstrap symbolic schema, or by representing the initial bootstrap // schema directly as Rust data. let typed_value = match TypedValue::from_edn_value(value) { - Some(TypedValue::Keyword(ref s)) => TypedValue::Ref(*ident_map.get(s).ok_or(ErrorKind::UnrecognizedIdent(s.clone()))?), + Some(TypedValue::Keyword(ref s)) => { + to_namespaced_keyword(s) + .and_then(|ident| ident_map.get(&ident)) + .map(|entid| TypedValue::Ref(*entid)) + .ok_or(ErrorKind::UnrecognizedIdent(s.clone()))? + }, Some(v) => v, _ => bail!(ErrorKind::BadBootstrapDefinition(format!("Expected Mentat typed value for value but got '{:?}'", value))) }; - triples.push((ident.clone(), - attr.clone(), - typed_value)); + triples.push((ident.clone(), attr.clone(), typed_value)); } }, _ => bail!(ErrorKind::BadBootstrapDefinition("Expected {:db/ident {:db/attr value ...} ...}".into())) @@ -249,13 +254,13 @@ fn symbolic_schema_to_assertions(symbolic_schema: &Value) -> Result> pub fn bootstrap_partition_map() -> PartitionMap { V2_PARTS[..].iter() - .map(|&(part, start, index)| (part.to_string(), Partition::new(start, index))) + .map(|&(ref part, start, index)| (part.to_string(), Partition::new(start, index))) .collect() } pub fn bootstrap_ident_map() -> IdentMap { V2_IDENTS[..].iter() - .map(|&(ident, entid)| (ident.to_string(), entid)) + .map(|&(ref ident, entid)| (ident.clone(), entid)) .collect() } diff --git a/db/src/db.rs b/db/src/db.rs index 1067e629..054f4860 100644 --- a/db/src/db.rs +++ b/db/src/db.rs @@ -25,6 +25,7 @@ use rusqlite::types::{ToSql, ToSqlOutput}; use ::{now, repeat_values, to_namespaced_keyword}; use bootstrap; use edn::types::Value; +use edn::symbols; use mentat_core::{ Attribute, AttributeBitFlags, @@ -387,7 +388,13 @@ impl TypedSQLValue for TypedValue { &TypedValue::Long(x) => (Value::Integer(x), ValueType::Long), &TypedValue::Double(x) => (Value::Float(x), ValueType::Double), &TypedValue::String(ref x) => (Value::Text(x.clone()), ValueType::String), - &TypedValue::Keyword(ref x) => (Value::NamespacedKeyword(to_namespaced_keyword(&x).unwrap()), ValueType::Keyword), + &TypedValue::Keyword(ref x) => { + match to_namespaced_keyword(&x) { + Some(x) => (Value::NamespacedKeyword(x), ValueType::Keyword), + // TODO Use custom ErrorKind https://github.com/brson/error-chain/issues/117 + None => panic!(ErrorKind::NotYetImplemented(format!("InvalidNamespacedKeyword: {}", x))), + } + }, } } } @@ -395,13 +402,16 @@ impl TypedSQLValue for TypedValue { /// Read the ident map materialized view from the given SQL store. pub fn read_ident_map(conn: &rusqlite::Connection) -> Result { let mut stmt: rusqlite::Statement = conn.prepare("SELECT ident, entid FROM idents")?; - let m = stmt.query_and_then(&[], |row| -> Result<(String, Entid)> { - Ok((row.get(0), row.get(1))) + let m = stmt.query_and_then(&[], |row| -> Result<(symbols::NamespacedKeyword, Entid)> { + let ident: String = row.get(0); + to_namespaced_keyword(&ident) + .map(|i| (i, row.get(1))) + // TODO Use custom ErrorKind https://github.com/brson/error-chain/issues/117 + .ok_or(ErrorKind::NotYetImplemented(format!("InvalidNamespacedKeyword: {}", ident.clone())).into()) })?.collect(); m } - /// Read the partition map materialized view from the given SQL store. pub fn read_partition_map(conn: &rusqlite::Connection) -> Result { let mut stmt: rusqlite::Statement = conn.prepare("SELECT part, start, idx FROM parts")?; @@ -414,7 +424,7 @@ pub fn read_partition_map(conn: &rusqlite::Connection) -> Result { /// Read the schema materialized view from the given SQL store. pub fn read_schema(conn: &rusqlite::Connection, ident_map: &IdentMap) -> Result { let mut stmt: rusqlite::Statement = conn.prepare("SELECT ident, attr, value, value_type_tag FROM schema")?; - let r: Result> = stmt.query_and_then(&[], |row| { + let r: Result> = stmt.query_and_then(&[], |row| { // Each row looks like :db/index|:db/valueType|28|0. Observe that 28|0 represents a // :db.type/ref to entid 28, which needs to be converted to a TypedValue. // TODO: don't use textual ident and attr; just use entids directly. @@ -424,7 +434,17 @@ pub fn read_schema(conn: &rusqlite::Connection, ident_map: &IdentMap) -> Result< let value_type_tag: i32 = row.get_checked(3)?; let typed_value = TypedValue::from_sql_value_pair(v, value_type_tag)?; - Ok((symbolic_ident, symbolic_attr, typed_value)) + let ident = to_namespaced_keyword(&symbolic_ident); + let attr = to_namespaced_keyword(&symbolic_attr); + match (ident, attr, typed_value) { + (Some(ident), Some(attr), typed_value) => Ok((ident, attr, typed_value)), + (None, _, _) => + // TODO Use custom ErrorKind https://github.com/brson/error-chain/issues/117 + Err(ErrorKind::NotYetImplemented(format!("InvalidNamespacedKeyword: {}", &symbolic_ident)).into()), + (_, None, _) => + // TODO Use custom ErrorKind https://github.com/brson/error-chain/issues/117 + Err(ErrorKind::NotYetImplemented(format!("InvalidNamespacedKeyword: {}", &symbolic_attr)).into()), + } })?.collect(); r.and_then(|triples| Schema::from_ident_map_and_triples(ident_map.clone(), triples)) @@ -467,7 +487,13 @@ impl DB { (&ValueType::Keyword, tv @ TypedValue::Keyword(_)) => Ok(tv), // Ref coerces a little: we interpret some things depending on the schema as a Ref. (&ValueType::Ref, TypedValue::Long(x)) => Ok(TypedValue::Ref(x)), - (&ValueType::Ref, TypedValue::Keyword(ref x)) => self.schema.require_entid(&x.to_string()).map(|entid| TypedValue::Ref(entid)), + (&ValueType::Ref, TypedValue::Keyword(ref x)) => { + match to_namespaced_keyword(x) { + Some(x) => self.schema.require_entid(&x).map(|entid| TypedValue::Ref(entid)), + // TODO Use custom ErrorKind https://github.com/brson/error-chain/issues/117 + None => bail!(ErrorKind::NotYetImplemented(format!("InvalidNamespacedKeyword: {}", x))), + } + } // Otherwise, we have a type mismatch. (value_type, _) => bail!(ErrorKind::BadEDNValuePair(value.clone(), value_type.clone())), } diff --git a/db/src/debug.rs b/db/src/debug.rs index 65fb8bf2..10d6b203 100644 --- a/db/src/debug.rs +++ b/db/src/debug.rs @@ -107,7 +107,7 @@ impl Transactions { /// Convert a numeric entid to an ident `Entid` if possible, otherwise a numeric `Entid`. fn to_entid(db: &DB, entid: i64) -> Entid { - db.schema.get_ident(entid).and_then(|ident| to_namespaced_keyword(&ident)).map_or(Entid::Entid(entid), Entid::Ident) + db.schema.get_ident(entid).map_or(Entid::Entid(entid), |ident| Entid::Ident(ident.clone())) } /// Return the set of datoms in the store, ordered by (e, a, v, tx), but not including any datoms of diff --git a/db/src/lib.rs b/db/src/lib.rs index fd8dca7a..b53b3615 100644 --- a/db/src/lib.rs +++ b/db/src/lib.rs @@ -18,6 +18,7 @@ extern crate time; extern crate tabwriter; +#[macro_use] extern crate edn; extern crate mentat_core; extern crate mentat_tx; diff --git a/db/src/schema.rs b/db/src/schema.rs index 7e7aa9c0..c7e5077e 100644 --- a/db/src/schema.rs +++ b/db/src/schema.rs @@ -12,6 +12,7 @@ use entids; use errors::*; +use edn::symbols; use mentat_core::{ Attribute, Entid, @@ -50,21 +51,21 @@ fn validate_schema_map(entid_map: &EntidMap, schema_map: &SchemaMap) -> Result<( } pub trait SchemaBuilding { - fn require_ident(&self, entid: Entid) -> Result<&String>; - fn require_entid(&self, ident: &String) -> Result; + fn require_ident(&self, entid: Entid) -> Result<&symbols::NamespacedKeyword>; + fn require_entid(&self, ident: &symbols::NamespacedKeyword) -> Result; fn require_attribute_for_entid(&self, entid: Entid) -> Result<&Attribute>; fn from_ident_map_and_schema_map(ident_map: IdentMap, schema_map: SchemaMap) -> Result; fn from_ident_map_and_triples(ident_map: IdentMap, assertions: U) -> Result - where U: IntoIterator; + where U: IntoIterator; } impl SchemaBuilding for Schema { - fn require_ident(&self, entid: Entid) -> Result<&String> { + fn require_ident(&self, entid: Entid) -> Result<&symbols::NamespacedKeyword> { self.get_ident(entid).ok_or(ErrorKind::UnrecognizedEntid(entid).into()) } - fn require_entid(&self, ident: &String) -> Result { - self.get_entid(&ident).ok_or(ErrorKind::UnrecognizedIdent(ident.clone()).into()) + fn require_entid(&self, ident: &symbols::NamespacedKeyword) -> Result { + self.get_entid(&ident).ok_or(ErrorKind::UnrecognizedIdent(ident.to_string()).into()) } fn require_attribute_for_entid(&self, entid: Entid) -> Result<&Attribute> { @@ -84,13 +85,13 @@ impl SchemaBuilding for Schema { }) } - /// Turn vec![(String(:ident), String(:key), TypedValue(:value)), ...] into a Mentat `Schema`. + /// Turn vec![(NamespacedKeyword(:ident), NamespacedKeyword(:key), TypedValue(:value)), ...] into a Mentat `Schema`. fn from_ident_map_and_triples(ident_map: IdentMap, assertions: U) -> Result - where U: IntoIterator{ + where U: IntoIterator{ let mut schema_map = SchemaMap::new(); for (ref symbolic_ident, ref symbolic_attr, ref value) in assertions.into_iter() { - let ident: i64 = *ident_map.get(symbolic_ident).ok_or(ErrorKind::UnrecognizedIdent(symbolic_ident.clone()))?; - let attr: i64 = *ident_map.get(symbolic_attr).ok_or(ErrorKind::UnrecognizedIdent(symbolic_attr.clone()))?; + let ident: i64 = *ident_map.get(symbolic_ident).ok_or(ErrorKind::UnrecognizedIdent(symbolic_ident.to_string()))?; + let attr: i64 = *ident_map.get(symbolic_attr).ok_or(ErrorKind::UnrecognizedIdent(symbolic_attr.to_string()))?; let attributes = schema_map.entry(ident).or_insert(Attribute::default()); // TODO: improve error messages throughout. diff --git a/db/src/tx.rs b/db/src/tx.rs index 14933ce5..92f45b41 100644 --- a/db/src/tx.rs +++ b/db/src/tx.rs @@ -144,7 +144,7 @@ impl<'conn> Tx<'conn> { Entity::AddOrRetract { op, e, a, v } => { let a: i64 = match a { entmod::Entid::Entid(ref a) => *a, - entmod::Entid::Ident(ref a) => self.db.schema.require_entid(&a.to_string())?, + entmod::Entid::Ident(ref a) => self.db.schema.require_entid(&a)?, }; let attribute: &Attribute = self.db.schema.require_attribute_for_entid(a)?; @@ -153,7 +153,7 @@ impl<'conn> Tx<'conn> { entmod::EntidOrLookupRefOrTempId::Entid(e) => { let e: i64 = match e { entmod::Entid::Entid(ref e) => *e, - entmod::Entid::Ident(ref e) => self.db.schema.require_entid(&e.to_string())?, + entmod::Entid::Ident(ref e) => self.db.schema.require_entid(&e)?, }; std::result::Result::Ok(e) }, diff --git a/edn/src/symbols.rs b/edn/src/symbols.rs index cc665464..866328c0 100644 --- a/edn/src/symbols.rs +++ b/edn/src/symbols.rs @@ -277,3 +277,18 @@ impl Display for NamespacedKeyword { write!(f, ":{}/{}", self.namespace, self.name) } } + +#[macro_export] +macro_rules! ns_keyword { + ($ns: expr, $name: expr) => {{ + $crate::NamespacedKeyword::new($ns, $name) + }} +} + +#[test] +fn test_ns_keyword_macro() { + assert_eq!(ns_keyword!("test", "name").to_string(), + NamespacedKeyword::new("test", "name").to_string()); + assert_eq!(ns_keyword!("ns", "_name").to_string(), + NamespacedKeyword::new("ns", "_name").to_string()); +} diff --git a/query-algebrizer/src/cc.rs b/query-algebrizer/src/cc.rs index 9eae490a..49ca56c6 100644 --- a/query-algebrizer/src/cc.rs +++ b/query-algebrizer/src/cc.rs @@ -262,7 +262,7 @@ impl ConjoiningClauses { } fn entid_for_ident<'s, 'a>(&self, schema: &'s Schema, ident: &'a NamespacedKeyword) -> Option { - schema.get_entid(&ident.to_string()) // TODO: #291. + schema.get_entid(&ident) } fn table_for_attribute_and_value<'s, 'a>(&self, attribute: &'s Attribute, value: &'a PatternValuePlace) -> Option { @@ -602,9 +602,9 @@ impl ConjoiningClauses { mod testing { use super::*; - fn associate_ident(schema: &mut Schema, i: &str, e: Entid) { - schema.entid_map.insert(e, i.to_string()); - schema.ident_map.insert(i.to_string(), e); + fn associate_ident(schema: &mut Schema, i: NamespacedKeyword, e: Entid) { + schema.entid_map.insert(e, i.clone()); + schema.ident_map.insert(i.clone(), e); } fn add_attribute(schema: &mut Schema, e: Entid, a: Attribute) { @@ -632,7 +632,7 @@ mod testing { let mut cc = ConjoiningClauses::default(); let mut schema = Schema::default(); - associate_ident(&mut schema, ":foo/bar", 99); + associate_ident(&mut schema, NamespacedKeyword::new("foo", "bar"), 99); cc.apply_pattern(&schema, &Pattern { source: None, @@ -650,7 +650,7 @@ mod testing { let mut cc = ConjoiningClauses::default(); let mut schema = Schema::default(); - associate_ident(&mut schema, ":foo/bar", 99); + associate_ident(&mut schema, NamespacedKeyword::new("foo", "bar"), 99); add_attribute(&mut schema, 99, Attribute { value_type: ValueType::Boolean, ..Default::default() @@ -733,8 +733,8 @@ mod testing { let mut cc = ConjoiningClauses::default(); let mut schema = Schema::default(); - associate_ident(&mut schema, ":foo/bar", 99); - associate_ident(&mut schema, ":foo/roz", 98); + associate_ident(&mut schema, NamespacedKeyword::new("foo", "bar"), 99); + associate_ident(&mut schema, NamespacedKeyword::new("foo", "roz"), 98); add_attribute(&mut schema, 99, Attribute { value_type: ValueType::Boolean, ..Default::default()