Store Idents as NamespacedKeywords, rather than Strings. Fixes #291. (#300)

r=ncalexander
This commit is contained in:
Jordan Santell 2017-02-17 13:55:36 -08:00 committed by GitHub
parent ec2bbb8e83
commit a59f9583ac
9 changed files with 145 additions and 99 deletions

View file

@ -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<String, Entid>;
/// Map `NamespacedKeyword` idents (`:db/ident`) to positive integer entids (`1`).
pub type IdentMap = BTreeMap<NamespacedKeyword, Entid>;
/// Map positive integer entids (`1`) to `String` idents (`:db/ident`).
pub type EntidMap = BTreeMap<Entid, String>;
/// Map positive integer entids (`1`) to `NamespacedKeyword` idents (`:db/ident`).
pub type EntidMap = BTreeMap<Entid, NamespacedKeyword>;
/// Map attribute entids to `Attribute` instances.
pub type SchemaMap = BTreeMap<Entid, Attribute>;
@ -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<Entid> {
pub fn get_entid(&self, x: &NamespacedKeyword) -> Option<Entid> {
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)
}
}

View file

@ -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<Value> {
fn idents_to_assertions(idents: &[(symbols::NamespacedKeyword, i64)]) -> Vec<Value> {
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<Vec<(String, String, TypedValue)>> {
fn symbolic_schema_to_triples(ident_map: &IdentMap, symbolic_schema: &Value) -> Result<Vec<(symbols::NamespacedKeyword, symbols::NamespacedKeyword, TypedValue)>> {
// 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<Vec<Value>>
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()
}

View file

@ -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<IdentMap> {
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<PartitionMap> {
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<PartitionMap> {
/// Read the schema materialized view from the given SQL store.
pub fn read_schema(conn: &rusqlite::Connection, ident_map: &IdentMap) -> Result<Schema> {
let mut stmt: rusqlite::Statement = conn.prepare("SELECT ident, attr, value, value_type_tag FROM schema")?;
let r: Result<Vec<(String, String, TypedValue)>> = stmt.query_and_then(&[], |row| {
let r: Result<Vec<(symbols::NamespacedKeyword, symbols::NamespacedKeyword, TypedValue)>> = 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())),
}

View file

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

View file

@ -18,6 +18,7 @@ extern crate time;
extern crate tabwriter;
#[macro_use]
extern crate edn;
extern crate mentat_core;
extern crate mentat_tx;

View file

@ -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<Entid>;
fn require_ident(&self, entid: Entid) -> Result<&symbols::NamespacedKeyword>;
fn require_entid(&self, ident: &symbols::NamespacedKeyword) -> Result<Entid>;
fn require_attribute_for_entid(&self, entid: Entid) -> Result<&Attribute>;
fn from_ident_map_and_schema_map(ident_map: IdentMap, schema_map: SchemaMap) -> Result<Schema>;
fn from_ident_map_and_triples<U>(ident_map: IdentMap, assertions: U) -> Result<Schema>
where U: IntoIterator<Item=(String, String, TypedValue)>;
where U: IntoIterator<Item=(symbols::NamespacedKeyword, symbols::NamespacedKeyword, TypedValue)>;
}
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<Entid> {
self.get_entid(&ident).ok_or(ErrorKind::UnrecognizedIdent(ident.clone()).into())
fn require_entid(&self, ident: &symbols::NamespacedKeyword) -> Result<Entid> {
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<U>(ident_map: IdentMap, assertions: U) -> Result<Schema>
where U: IntoIterator<Item=(String, String, TypedValue)>{
where U: IntoIterator<Item=(symbols::NamespacedKeyword, symbols::NamespacedKeyword, TypedValue)>{
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.

View file

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

View file

@ -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());
}

View file

@ -262,7 +262,7 @@ impl ConjoiningClauses {
}
fn entid_for_ident<'s, 'a>(&self, schema: &'s Schema, ident: &'a NamespacedKeyword) -> Option<Entid> {
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<DatomsTable> {
@ -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()