Ergonomics improvements, including a kw macro. (#537) r=emily

* Add TypedValue::instant(micros).
* Add From<f64> for TypedValue.
* Add lookup_values_for_attribute to Conn.
* Add q_explain to Queryable.
* Expose an iterator over FindSpec's columns.
* Export edn from mentat crate. Export QueryExecutionResult.
* Implement Display for Variable and Element.
* Introduce a `kw` macro.

    This allows you to write:

    ```rust
    kw!(:foo/bar)
    ```

    instead of

    ```rust
    NamespacedKeyword::new("foo", "bar")
    ```

    … and it's more efficient, too.

Add `mentat::open`, eliminate use of `mentat_db` in some places.
This commit is contained in:
Richard Newman 2018-02-01 09:17:07 -08:00
parent 3bf7459315
commit 2614f498be
11 changed files with 190 additions and 106 deletions

View file

@ -8,15 +8,15 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
extern crate chrono;
extern crate enum_set; extern crate enum_set;
extern crate ordered_float;
extern crate uuid;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
extern crate ordered_float;
extern crate chrono;
extern crate edn; extern crate edn;
extern crate uuid;
pub mod values; pub mod values;
@ -231,6 +231,12 @@ impl TypedValue {
pub fn current_instant() -> TypedValue { pub fn current_instant() -> TypedValue {
Utc::now().into() Utc::now().into()
} }
/// Construct a new `TypedValue::Instant` instance from the provided
/// microsecond timestamp.
pub fn instant(micros: i64) -> TypedValue {
DateTime::<Utc>::from_micros(micros).into()
}
} }
trait MicrosecondPrecision { trait MicrosecondPrecision {
@ -301,6 +307,12 @@ impl From<i32> for TypedValue {
} }
} }
impl From<f64> for TypedValue {
fn from(value: f64) -> TypedValue {
TypedValue::Double(OrderedFloat(value))
}
}
/// Type safe representation of the possible return values from SQLite's `typeof` /// Type safe representation of the possible return values from SQLite's `typeof`
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)] #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
pub enum SQLTypeAffinity { pub enum SQLTypeAffinity {

View file

@ -42,4 +42,10 @@ pub use types::{
Value, Value,
ValueAndSpan, ValueAndSpan,
}; };
pub use symbols::{Keyword, NamespacedKeyword, PlainSymbol, NamespacedSymbol};
pub use symbols::{
Keyword,
NamespacedKeyword,
NamespacedSymbol,
PlainSymbol,
};

View file

@ -10,6 +10,13 @@
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
#[macro_export]
macro_rules! ns_keyword {
($ns: expr, $name: expr) => {{
$crate::NamespacedKeyword::new($ns, $name)
}}
}
/// A simplification of Clojure's Symbol. /// A simplification of Clojure's Symbol.
#[derive(Clone,Debug,Eq,Hash,Ord,PartialOrd,PartialEq)] #[derive(Clone,Debug,Eq,Hash,Ord,PartialOrd,PartialEq)]
pub struct PlainSymbol(pub String); pub struct PlainSymbol(pub String);
@ -136,6 +143,8 @@ impl NamespacedKeyword {
/// let keyword = NamespacedKeyword::new("foo", "bar"); /// let keyword = NamespacedKeyword::new("foo", "bar");
/// assert_eq!(keyword.to_string(), ":foo/bar"); /// assert_eq!(keyword.to_string(), ":foo/bar");
/// ``` /// ```
///
/// See also the `kw!` macro in the main `mentat` crate.
pub fn new<T>(namespace: T, name: T) -> Self where T: Into<String> { pub fn new<T>(namespace: T, name: T) -> Self where T: Into<String> {
let n = name.into(); let n = name.into();
let ns = namespace.into(); let ns = namespace.into();
@ -302,13 +311,6 @@ impl Display for NamespacedKeyword {
} }
} }
#[macro_export]
macro_rules! ns_keyword {
($ns: expr, $name: expr) => {{
$crate::NamespacedKeyword::new($ns, $name)
}}
}
#[test] #[test]
fn test_ns_keyword_macro() { fn test_ns_keyword_macro() {
assert_eq!(ns_keyword!("test", "name").to_string(), assert_eq!(ns_keyword!("test", "name").to_string(),

View file

@ -127,6 +127,12 @@ impl fmt::Debug for Variable {
} }
} }
impl std::fmt::Display for Variable {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct QueryFunction(pub PlainSymbol); pub struct QueryFunction(pub PlainSymbol);
@ -443,6 +449,16 @@ pub enum Element {
// Pull(Pull), // TODO // Pull(Pull), // TODO
} }
impl std::fmt::Display for Element {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
&Element::Variable(ref var) => {
write!(f, "{}", var)
},
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum Limit { pub enum Limit {
None, None,
@ -543,6 +559,16 @@ impl FindSpec {
pub fn requires_distinct(&self) -> bool { pub fn requires_distinct(&self) -> bool {
!self.is_unit_limited() !self.is_unit_limited()
} }
pub fn columns<'s>(&'s self) -> Box<Iterator<Item=&Element> + 's> {
use FindSpec::*;
match self {
&FindScalar(ref e) => Box::new(std::iter::once(e)),
&FindColl(ref e) => Box::new(std::iter::once(e)),
&FindTuple(ref v) => Box::new(v.iter()),
&FindRel(ref v) => Box::new(v.iter()),
}
}
} }
// Datomic accepts variable or placeholder. DataScript accepts recursive bindings. Mentat sticks // Datomic accepts variable or placeholder. DataScript accepts recursive bindings. Mentat sticks

View file

@ -105,6 +105,8 @@ pub struct Conn {
} }
pub trait Queryable { pub trait Queryable {
fn q_explain<T>(&self, query: &str, inputs: T) -> Result<QueryExplanation>
where T: Into<Option<QueryInputs>>;
fn q_once<T>(&self, query: &str, inputs: T) -> Result<QueryResults> fn q_once<T>(&self, query: &str, inputs: T) -> Result<QueryResults>
where T: Into<Option<QueryInputs>>; where T: Into<Option<QueryInputs>>;
fn lookup_values_for_attribute<E>(&self, entity: E, attribute: &edn::NamespacedKeyword) -> Result<Vec<TypedValue>> fn lookup_values_for_attribute<E>(&self, entity: E, attribute: &edn::NamespacedKeyword) -> Result<Vec<TypedValue>>
@ -135,6 +137,11 @@ impl<'a, 'c> Queryable for InProgressRead<'a, 'c> {
self.0.q_once(query, inputs) self.0.q_once(query, inputs)
} }
fn q_explain<T>(&self, query: &str, inputs: T) -> Result<QueryExplanation>
where T: Into<Option<QueryInputs>> {
self.0.q_explain(query, inputs)
}
fn lookup_values_for_attribute<E>(&self, entity: E, attribute: &edn::NamespacedKeyword) -> Result<Vec<TypedValue>> fn lookup_values_for_attribute<E>(&self, entity: E, attribute: &edn::NamespacedKeyword) -> Result<Vec<TypedValue>>
where E: Into<Entid> { where E: Into<Entid> {
self.0.lookup_values_for_attribute(entity, attribute) self.0.lookup_values_for_attribute(entity, attribute)
@ -156,6 +163,14 @@ impl<'a, 'c> Queryable for InProgress<'a, 'c> {
inputs) inputs)
} }
fn q_explain<T>(&self, query: &str, inputs: T) -> Result<QueryExplanation>
where T: Into<Option<QueryInputs>> {
q_explain(&*(self.transaction),
&self.schema,
query,
inputs)
}
fn lookup_values_for_attribute<E>(&self, entity: E, attribute: &edn::NamespacedKeyword) -> Result<Vec<TypedValue>> fn lookup_values_for_attribute<E>(&self, entity: E, attribute: &edn::NamespacedKeyword) -> Result<Vec<TypedValue>>
where E: Into<Entid> { where E: Into<Entid> {
lookup_values_for_attribute(&*(self.transaction), &self.schema, entity, attribute) lookup_values_for_attribute(&*(self.transaction), &self.schema, entity, attribute)
@ -362,6 +377,13 @@ impl Conn {
q_explain(sqlite, &*self.current_schema(), query, inputs) q_explain(sqlite, &*self.current_schema(), query, inputs)
} }
pub fn lookup_values_for_attribute(&self,
sqlite: &rusqlite::Connection,
entity: Entid,
attribute: &edn::NamespacedKeyword) -> Result<Vec<TypedValue>> {
lookup_values_for_attribute(sqlite, &*self.current_schema(), entity, attribute)
}
pub fn lookup_value_for_attribute(&self, pub fn lookup_value_for_attribute(&self,
sqlite: &rusqlite::Connection, sqlite: &rusqlite::Connection,
entity: Entid, entity: Entid,

View file

@ -8,6 +8,8 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#![macro_use]
// We have a little bit of a dilemma in Mentat. // We have a little bit of a dilemma in Mentat.
// The public data format for transacting is, fundamentally, a big string: EDN. // The public data format for transacting is, fundamentally, a big string: EDN.
// The internal data format for transacting is required to encode the complexities of // The internal data format for transacting is required to encode the complexities of
@ -23,7 +25,7 @@
// a: Entid::Ident(NamespacedKeyword::new("test", "a1")), // a: Entid::Ident(NamespacedKeyword::new("test", "a1")),
// v: Value::Text("v1".into()), // v: Value::Text("v1".into()),
// }), // }),
// a: Entid::Ident(NamespacedKeyword::new("test", "a")), // a: Entid::Ident(kw!(:test/a)),
// v: AtomOrLookupRefOrVectorOrMapNotation::Atom(ValueAndSpan::new(SpannedValue::Text("v".into()), Span(44, 47))), // v: AtomOrLookupRefOrVectorOrMapNotation::Atom(ValueAndSpan::new(SpannedValue::Text("v".into()), Span(44, 47))),
// })); // }));
// //
@ -322,30 +324,23 @@ impl FromThing<KnownEntid> for TypedValueOr<TempIdHandle> {
mod testing { mod testing {
extern crate mentat_db; extern crate mentat_db;
use mentat_core::{
Entid,
HasSchema,
NamespacedKeyword,
TypedValue,
};
use errors::{ use errors::{
Error, Error,
ErrorKind,
}; };
use errors::ErrorKind::{ // For matching inside a test.
DbError,
};
use mentat_db::TxReport;
use mentat_db::ErrorKind::{ use mentat_db::ErrorKind::{
UnrecognizedEntid, UnrecognizedEntid,
}; };
use ::{ use ::{
Conn, Conn,
Entid,
HasSchema,
Queryable, Queryable,
TypedValue,
TxReport,
}; };
use super::*; use super::*;
@ -378,7 +373,7 @@ mod testing {
let mut in_progress = conn.begin_transaction(&mut sqlite).expect("begun successfully"); let mut in_progress = conn.begin_transaction(&mut sqlite).expect("begun successfully");
// This should fail: unrecognized entid. // This should fail: unrecognized entid.
if let Err(Error(DbError(UnrecognizedEntid(e)), _)) = in_progress.transact_terms(terms, tempids) { if let Err(Error(ErrorKind::DbError(UnrecognizedEntid(e)), _)) = in_progress.transact_terms(terms, tempids) {
assert_eq!(e, 999); assert_eq!(e, 999);
} else { } else {
panic!("Should have rejected the entid."); panic!("Should have rejected the entid.");
@ -390,9 +385,9 @@ mod testing {
let mut sqlite = mentat_db::db::new_connection("").unwrap(); let mut sqlite = mentat_db::db::new_connection("").unwrap();
let mut conn = Conn::connect(&mut sqlite).unwrap(); let mut conn = Conn::connect(&mut sqlite).unwrap();
let foo_one = NamespacedKeyword::new("foo", "one"); let foo_one = kw!(:foo/one);
let foo_many = NamespacedKeyword::new("foo", "many"); let foo_many = kw!(:foo/many);
let foo_ref = NamespacedKeyword::new("foo", "ref"); let foo_ref = kw!(:foo/ref);
let report: TxReport; let report: TxReport;
// Give ourselves a schema to work with! // Give ourselves a schema to work with!

View file

@ -18,7 +18,7 @@ extern crate lazy_static;
extern crate rusqlite; extern crate rusqlite;
extern crate edn; pub extern crate edn;
extern crate mentat_core; extern crate mentat_core;
extern crate mentat_db; extern crate mentat_db;
extern crate mentat_query; extern crate mentat_query;
@ -30,7 +30,44 @@ extern crate mentat_sql;
extern crate mentat_tx; extern crate mentat_tx;
extern crate mentat_tx_parser; extern crate mentat_tx_parser;
use rusqlite::Connection; pub use mentat_core::{
Attribute,
Entid,
HasSchema,
NamespacedKeyword,
TypedValue,
Uuid,
ValueType,
};
pub use mentat_db::{
CORE_SCHEMA_VERSION,
DB_SCHEMA_CORE,
TxReport,
new_connection,
};
/// Produce the appropriate `NamespacedKeyword` for the provided namespace and name.
/// This lives here because we can't re-export macros:
/// https://github.com/rust-lang/rust/issues/29638.
#[macro_export]
macro_rules! kw {
( : $ns:ident / $n:ident ) => {
// We don't need to go through `new` -- `ident` is strict enough.
$crate::NamespacedKeyword {
namespace: stringify!($ns).into(),
name: stringify!($n).into(),
}
};
( : $ns:ident$(. $nss:ident)+ / $n:ident ) => {
// We don't need to go through `new` -- `ident` is strict enough.
$crate::NamespacedKeyword {
namespace: concat!(stringify!($ns) $(, ".", stringify!($nss))+).into(),
name: stringify!($n).into(),
}
};
}
pub mod errors; pub mod errors;
pub mod ident; pub mod ident;
@ -43,29 +80,17 @@ pub fn get_name() -> String {
return String::from("mentat"); return String::from("mentat");
} }
// Will ultimately not return the sqlite connection directly /// Open a Mentat store at the provided path.
pub fn get_connection() -> Connection { pub fn open(path: &str) -> errors::Result<(rusqlite::Connection, Conn)> {
return Connection::open_in_memory().unwrap(); let mut connection = new_connection(path)?;
let conn = Conn::connect(&mut connection)?;
Ok((connection, conn))
} }
pub use mentat_core::{
Attribute,
Entid,
TypedValue,
Uuid,
ValueType,
};
pub use mentat_db::{
CORE_SCHEMA_VERSION,
DB_SCHEMA_CORE,
new_connection,
};
pub use query::{ pub use query::{
IntoResult, IntoResult,
NamespacedKeyword,
PlainSymbol, PlainSymbol,
QueryExecutionResult,
QueryExplanation, QueryExplanation,
QueryInputs, QueryInputs,
QueryPlanStep, QueryPlanStep,
@ -84,9 +109,16 @@ pub use conn::{
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use edn::symbols::Keyword; use edn::symbols::Keyword;
use super::*;
#[test] #[test]
fn can_import_edn() { fn can_import_edn() {
assert_eq!("foo", Keyword::new("foo").0); assert_eq!("foo", Keyword::new("foo").0);
} }
#[test]
fn test_kw() {
assert_eq!(kw!(:foo/bar), NamespacedKeyword::new("foo", "bar"));
assert_eq!(kw!(:org.mozilla.foo/bar_baz), NamespacedKeyword::new("org.mozilla.foo", "bar_baz"));
}
} }

View file

@ -23,12 +23,11 @@
//! Typical use is the following: //! Typical use is the following:
//! //!
//! ``` //! ```
//! #[macro_use(kw)]
//! extern crate mentat; //! extern crate mentat;
//! extern crate mentat_db; // So we can use SQLite connection utilities.
//! //!
//! use mentat::{ //! use mentat::{
//! Conn, //! Conn,
//! NamespacedKeyword,
//! ValueType, //! ValueType,
//! }; //! };
//! //!
@ -41,8 +40,7 @@
//! }; //! };
//! //!
//! fn main() { //! fn main() {
//! let mut sqlite = mentat_db::db::new_connection("").expect("SQLite connected"); //! let (mut sqlite, mut conn) = mentat::open("").expect("connected");
//! let mut conn = Conn::connect(&mut sqlite).expect("connected");
//! //!
//! { //! {
//! // Read the list of installed vocabularies. //! // Read the list of installed vocabularies.
@ -64,10 +62,10 @@
//! //!
//! // Make sure our vocabulary is installed, and install if necessary. //! // Make sure our vocabulary is installed, and install if necessary.
//! in_progress.ensure_vocabulary(&Definition { //! in_progress.ensure_vocabulary(&Definition {
//! name: NamespacedKeyword::new("example", "links"), //! name: kw!(:example/links),
//! version: 1, //! version: 1,
//! attributes: vec![ //! attributes: vec![
//! (NamespacedKeyword::new("link", "title"), //! (kw!(:link/title),
//! vocabulary::AttributeBuilder::default() //! vocabulary::AttributeBuilder::default()
//! .value_type(ValueType::String) //! .value_type(ValueType::String)
//! .multival(false) //! .multival(false)
@ -85,22 +83,19 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use mentat_core::{
Attribute,
Entid,
HasSchema,
KnownEntid,
NamespacedKeyword,
TypedValue,
ValueType,
};
pub use mentat_core::attribute; pub use mentat_core::attribute;
use mentat_core::attribute::Unique; use mentat_core::attribute::Unique;
use mentat_core::KnownEntid;
use ::{ use ::{
CORE_SCHEMA_VERSION, CORE_SCHEMA_VERSION,
Attribute,
Entid,
HasSchema,
IntoResult, IntoResult,
NamespacedKeyword,
TypedValue,
ValueType,
}; };
use ::conn::{ use ::conn::{
@ -170,25 +165,25 @@ impl Vocabularies {
lazy_static! { lazy_static! {
static ref DB_SCHEMA_CORE: NamespacedKeyword = { static ref DB_SCHEMA_CORE: NamespacedKeyword = {
NamespacedKeyword::new("db.schema", "core") kw!(:db.schema/core)
}; };
static ref DB_SCHEMA_ATTRIBUTE: NamespacedKeyword = { static ref DB_SCHEMA_ATTRIBUTE: NamespacedKeyword = {
NamespacedKeyword::new("db.schema", "attribute") kw!(:db.schema/attribute)
}; };
static ref DB_SCHEMA_VERSION: NamespacedKeyword = { static ref DB_SCHEMA_VERSION: NamespacedKeyword = {
NamespacedKeyword::new("db.schema", "version") kw!(:db.schema/version)
}; };
static ref DB_IDENT: NamespacedKeyword = { static ref DB_IDENT: NamespacedKeyword = {
NamespacedKeyword::new("db", "ident") kw!(:db/ident)
}; };
static ref DB_UNIQUE: NamespacedKeyword = { static ref DB_UNIQUE: NamespacedKeyword = {
NamespacedKeyword::new("db", "unique") kw!(:db/unique)
}; };
static ref DB_UNIQUE_VALUE: NamespacedKeyword = { static ref DB_UNIQUE_VALUE: NamespacedKeyword = {
NamespacedKeyword::new("db.unique", "value") kw!(:db.unique/value)
}; };
static ref DB_UNIQUE_IDENTITY: NamespacedKeyword = { static ref DB_UNIQUE_IDENTITY: NamespacedKeyword = {
NamespacedKeyword::new("db.unique", "identity") kw!(:db.unique/identity)
}; };
static ref DB_IS_COMPONENT: NamespacedKeyword = { static ref DB_IS_COMPONENT: NamespacedKeyword = {
NamespacedKeyword::new("db", "isComponent") NamespacedKeyword::new("db", "isComponent")
@ -197,19 +192,19 @@ lazy_static! {
NamespacedKeyword::new("db", "valueType") NamespacedKeyword::new("db", "valueType")
}; };
static ref DB_INDEX: NamespacedKeyword = { static ref DB_INDEX: NamespacedKeyword = {
NamespacedKeyword::new("db", "index") kw!(:db/index)
}; };
static ref DB_FULLTEXT: NamespacedKeyword = { static ref DB_FULLTEXT: NamespacedKeyword = {
NamespacedKeyword::new("db", "fulltext") kw!(:db/fulltext)
}; };
static ref DB_CARDINALITY: NamespacedKeyword = { static ref DB_CARDINALITY: NamespacedKeyword = {
NamespacedKeyword::new("db", "cardinality") kw!(:db/cardinality)
}; };
static ref DB_CARDINALITY_ONE: NamespacedKeyword = { static ref DB_CARDINALITY_ONE: NamespacedKeyword = {
NamespacedKeyword::new("db.cardinality", "one") kw!(:db.cardinality/one)
}; };
static ref DB_CARDINALITY_MANY: NamespacedKeyword = { static ref DB_CARDINALITY_MANY: NamespacedKeyword = {
NamespacedKeyword::new("db.cardinality", "many") kw!(:db.cardinality/many)
}; };
// Not yet supported. // Not yet supported.
@ -574,32 +569,24 @@ impl<T> HasVocabularies for T where T: HasSchema + Queryable {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use ::{
NamespacedKeyword,
Conn,
new_connection,
};
use super::HasVocabularies; use super::HasVocabularies;
#[test] #[test]
fn test_read_vocabularies() { fn test_read_vocabularies() {
let mut sqlite = new_connection("").expect("could open conn"); let (mut sqlite, mut conn) = ::open("").expect("opened");
let mut conn = Conn::connect(&mut sqlite).expect("could open store");
let vocabularies = conn.begin_read(&mut sqlite).expect("in progress") let vocabularies = conn.begin_read(&mut sqlite).expect("in progress")
.read_vocabularies().expect("OK"); .read_vocabularies().expect("OK");
assert_eq!(vocabularies.len(), 1); assert_eq!(vocabularies.len(), 1);
let core = vocabularies.get(&NamespacedKeyword::new("db.schema", "core")).expect("exists"); let core = vocabularies.get(&kw!(:db.schema/core)).expect("exists");
assert_eq!(core.version, 1); assert_eq!(core.version, 1);
} }
#[test] #[test]
fn test_core_schema() { fn test_core_schema() {
let mut c = new_connection("").expect("could open conn"); let (mut sqlite, mut conn) = ::open("").expect("opened");
let mut conn = Conn::connect(&mut c).expect("could open store"); let in_progress = conn.begin_transaction(&mut sqlite).expect("in progress");
let in_progress = conn.begin_transaction(&mut c).expect("in progress");
let vocab = in_progress.read_vocabularies().expect("vocabulary"); let vocab = in_progress.read_vocabularies().expect("vocabulary");
assert_eq!(1, vocab.len()); assert_eq!(1, vocab.len());
assert_eq!(1, vocab.get(&NamespacedKeyword::new("db.schema", "core")).expect("core vocab").version); assert_eq!(1, vocab.get(&kw!(:db.schema/core)).expect("core vocab").version);
} }
} }

View file

@ -20,7 +20,7 @@ fn can_import_sqlite() {
data: Option<Vec<u8>>, data: Option<Vec<u8>>,
} }
let conn = mentat::get_connection(); let conn = mentat::new_connection("").expect("SQLite connected");
conn.execute("CREATE TABLE person ( conn.execute("CREATE TABLE person (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,

View file

@ -11,6 +11,7 @@
extern crate chrono; extern crate chrono;
extern crate time; extern crate time;
#[macro_use]
extern crate mentat; extern crate mentat;
extern crate mentat_core; extern crate mentat_core;
extern crate mentat_db; extern crate mentat_db;
@ -482,9 +483,9 @@ fn test_lookup() {
]"#).unwrap().tempids; ]"#).unwrap().tempids;
let entid = ids.get("b").unwrap(); let entid = ids.get("b").unwrap();
let foo_date = NamespacedKeyword::new("foo", "date"); let foo_date = kw!(:foo/date);
let foo_many = NamespacedKeyword::new("foo", "many"); let foo_many = kw!(:foo/many);
let db_ident = NamespacedKeyword::new("db", "ident"); let db_ident = kw!(:db/ident);
let expected = TypedValue::Instant(DateTime::<Utc>::from_str("2016-01-01T11:00:00.000Z").unwrap()); let expected = TypedValue::Instant(DateTime::<Utc>::from_str("2016-01-01T11:00:00.000Z").unwrap());
// Fetch a value. // Fetch a value.

View file

@ -11,6 +11,7 @@
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
#[macro_use]
extern crate mentat; extern crate mentat;
extern crate mentat_core; extern crate mentat_core;
extern crate mentat_db; extern crate mentat_db;
@ -47,16 +48,16 @@ use mentat::errors::{
lazy_static! { lazy_static! {
static ref FOO_NAME: NamespacedKeyword = { static ref FOO_NAME: NamespacedKeyword = {
NamespacedKeyword::new("foo", "name") kw!(:foo/name)
}; };
static ref FOO_MOMENT: NamespacedKeyword = { static ref FOO_MOMENT: NamespacedKeyword = {
NamespacedKeyword::new("foo", "moment") kw!(:foo/moment)
}; };
static ref FOO_VOCAB: vocabulary::Definition = { static ref FOO_VOCAB: vocabulary::Definition = {
vocabulary::Definition { vocabulary::Definition {
name: NamespacedKeyword::new("org.mozilla", "foo"), name: kw!(:org.mozilla/foo),
version: 1, version: 1,
attributes: vec![ attributes: vec![
(FOO_NAME.clone(), (FOO_NAME.clone(),
@ -129,24 +130,24 @@ fn test_add_vocab() {
.fulltext(true) .fulltext(true)
.build(); .build();
let bar_only = vec![ let bar_only = vec![
(NamespacedKeyword::new("foo", "bar"), bar.clone()), (kw!(:foo/bar), bar.clone()),
]; ];
let baz_only = vec![ let baz_only = vec![
(NamespacedKeyword::new("foo", "baz"), baz.clone()), (kw!(:foo/baz), baz.clone()),
]; ];
let bar_and_baz = vec![ let bar_and_baz = vec![
(NamespacedKeyword::new("foo", "bar"), bar.clone()), (kw!(:foo/bar), bar.clone()),
(NamespacedKeyword::new("foo", "baz"), baz.clone()), (kw!(:foo/baz), baz.clone()),
]; ];
let foo_v1_a = vocabulary::Definition { let foo_v1_a = vocabulary::Definition {
name: NamespacedKeyword::new("org.mozilla", "foo"), name: kw!(:org.mozilla/foo),
version: 1, version: 1,
attributes: bar_only.clone(), attributes: bar_only.clone(),
}; };
let foo_v1_b = vocabulary::Definition { let foo_v1_b = vocabulary::Definition {
name: NamespacedKeyword::new("org.mozilla", "foo"), name: kw!(:org.mozilla/foo),
version: 1, version: 1,
attributes: bar_and_baz.clone(), attributes: bar_and_baz.clone(),
}; };
@ -244,11 +245,11 @@ fn test_add_vocab() {
.multival(true) .multival(true)
.build(); .build();
let bar_and_malformed_baz = vec![ let bar_and_malformed_baz = vec![
(NamespacedKeyword::new("foo", "bar"), bar), (kw!(:foo/bar), bar),
(NamespacedKeyword::new("foo", "baz"), malformed_baz.clone()), (kw!(:foo/baz), malformed_baz.clone()),
]; ];
let foo_v1_malformed = vocabulary::Definition { let foo_v1_malformed = vocabulary::Definition {
name: NamespacedKeyword::new("org.mozilla", "foo"), name: kw!(:org.mozilla/foo),
version: 1, version: 1,
attributes: bar_and_malformed_baz.clone(), attributes: bar_and_malformed_baz.clone(),
}; };