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:
parent
3bf7459315
commit
2614f498be
11 changed files with 190 additions and 106 deletions
|
@ -8,15 +8,15 @@
|
|||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
extern crate chrono;
|
||||
extern crate enum_set;
|
||||
extern crate ordered_float;
|
||||
extern crate uuid;
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate ordered_float;
|
||||
|
||||
extern crate chrono;
|
||||
extern crate edn;
|
||||
extern crate uuid;
|
||||
|
||||
pub mod values;
|
||||
|
||||
|
@ -231,6 +231,12 @@ impl TypedValue {
|
|||
pub fn current_instant() -> TypedValue {
|
||||
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 {
|
||||
|
@ -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`
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
|
||||
pub enum SQLTypeAffinity {
|
||||
|
|
|
@ -42,4 +42,10 @@ pub use types::{
|
|||
Value,
|
||||
ValueAndSpan,
|
||||
};
|
||||
pub use symbols::{Keyword, NamespacedKeyword, PlainSymbol, NamespacedSymbol};
|
||||
|
||||
pub use symbols::{
|
||||
Keyword,
|
||||
NamespacedKeyword,
|
||||
NamespacedSymbol,
|
||||
PlainSymbol,
|
||||
};
|
||||
|
|
|
@ -10,6 +10,13 @@
|
|||
|
||||
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.
|
||||
#[derive(Clone,Debug,Eq,Hash,Ord,PartialOrd,PartialEq)]
|
||||
pub struct PlainSymbol(pub String);
|
||||
|
@ -136,6 +143,8 @@ impl NamespacedKeyword {
|
|||
/// let keyword = NamespacedKeyword::new("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> {
|
||||
let n = name.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]
|
||||
fn test_ns_keyword_macro() {
|
||||
assert_eq!(ns_keyword!("test", "name").to_string(),
|
||||
|
|
|
@ -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)]
|
||||
pub struct QueryFunction(pub PlainSymbol);
|
||||
|
||||
|
@ -443,6 +449,16 @@ pub enum Element {
|
|||
// 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)]
|
||||
pub enum Limit {
|
||||
None,
|
||||
|
@ -543,6 +559,16 @@ impl FindSpec {
|
|||
pub fn requires_distinct(&self) -> bool {
|
||||
!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
|
||||
|
|
22
src/conn.rs
22
src/conn.rs
|
@ -105,6 +105,8 @@ pub struct Conn {
|
|||
}
|
||||
|
||||
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>
|
||||
where T: Into<Option<QueryInputs>>;
|
||||
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)
|
||||
}
|
||||
|
||||
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>>
|
||||
where E: Into<Entid> {
|
||||
self.0.lookup_values_for_attribute(entity, attribute)
|
||||
|
@ -156,6 +163,14 @@ impl<'a, 'c> Queryable for InProgress<'a, 'c> {
|
|||
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>>
|
||||
where E: Into<Entid> {
|
||||
lookup_values_for_attribute(&*(self.transaction), &self.schema, entity, attribute)
|
||||
|
@ -362,6 +377,13 @@ impl Conn {
|
|||
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,
|
||||
sqlite: &rusqlite::Connection,
|
||||
entity: Entid,
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#![macro_use]
|
||||
|
||||
// We have a little bit of a dilemma in Mentat.
|
||||
// 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
|
||||
|
@ -23,7 +25,7 @@
|
|||
// a: Entid::Ident(NamespacedKeyword::new("test", "a1")),
|
||||
// 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))),
|
||||
// }));
|
||||
//
|
||||
|
@ -322,30 +324,23 @@ impl FromThing<KnownEntid> for TypedValueOr<TempIdHandle> {
|
|||
mod testing {
|
||||
extern crate mentat_db;
|
||||
|
||||
use mentat_core::{
|
||||
Entid,
|
||||
HasSchema,
|
||||
NamespacedKeyword,
|
||||
TypedValue,
|
||||
};
|
||||
|
||||
use errors::{
|
||||
Error,
|
||||
ErrorKind,
|
||||
};
|
||||
|
||||
use errors::ErrorKind::{
|
||||
DbError,
|
||||
};
|
||||
|
||||
use mentat_db::TxReport;
|
||||
|
||||
// For matching inside a test.
|
||||
use mentat_db::ErrorKind::{
|
||||
UnrecognizedEntid,
|
||||
};
|
||||
|
||||
use ::{
|
||||
Conn,
|
||||
Entid,
|
||||
HasSchema,
|
||||
Queryable,
|
||||
TypedValue,
|
||||
TxReport,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
@ -378,7 +373,7 @@ mod testing {
|
|||
let mut in_progress = conn.begin_transaction(&mut sqlite).expect("begun successfully");
|
||||
|
||||
// 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);
|
||||
} else {
|
||||
panic!("Should have rejected the entid.");
|
||||
|
@ -390,9 +385,9 @@ mod testing {
|
|||
let mut sqlite = mentat_db::db::new_connection("").unwrap();
|
||||
let mut conn = Conn::connect(&mut sqlite).unwrap();
|
||||
|
||||
let foo_one = NamespacedKeyword::new("foo", "one");
|
||||
let foo_many = NamespacedKeyword::new("foo", "many");
|
||||
let foo_ref = NamespacedKeyword::new("foo", "ref");
|
||||
let foo_one = kw!(:foo/one);
|
||||
let foo_many = kw!(:foo/many);
|
||||
let foo_ref = kw!(:foo/ref);
|
||||
let report: TxReport;
|
||||
|
||||
// Give ourselves a schema to work with!
|
||||
|
|
72
src/lib.rs
72
src/lib.rs
|
@ -18,7 +18,7 @@ extern crate lazy_static;
|
|||
|
||||
extern crate rusqlite;
|
||||
|
||||
extern crate edn;
|
||||
pub extern crate edn;
|
||||
extern crate mentat_core;
|
||||
extern crate mentat_db;
|
||||
extern crate mentat_query;
|
||||
|
@ -30,7 +30,44 @@ extern crate mentat_sql;
|
|||
extern crate mentat_tx;
|
||||
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 ident;
|
||||
|
@ -43,29 +80,17 @@ pub fn get_name() -> String {
|
|||
return String::from("mentat");
|
||||
}
|
||||
|
||||
// Will ultimately not return the sqlite connection directly
|
||||
pub fn get_connection() -> Connection {
|
||||
return Connection::open_in_memory().unwrap();
|
||||
/// Open a Mentat store at the provided path.
|
||||
pub fn open(path: &str) -> errors::Result<(rusqlite::Connection, Conn)> {
|
||||
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::{
|
||||
IntoResult,
|
||||
NamespacedKeyword,
|
||||
PlainSymbol,
|
||||
QueryExecutionResult,
|
||||
QueryExplanation,
|
||||
QueryInputs,
|
||||
QueryPlanStep,
|
||||
|
@ -84,9 +109,16 @@ pub use conn::{
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use edn::symbols::Keyword;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn can_import_edn() {
|
||||
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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,12 +23,11 @@
|
|||
//! Typical use is the following:
|
||||
//!
|
||||
//! ```
|
||||
//! #[macro_use(kw)]
|
||||
//! extern crate mentat;
|
||||
//! extern crate mentat_db; // So we can use SQLite connection utilities.
|
||||
//!
|
||||
//! use mentat::{
|
||||
//! Conn,
|
||||
//! NamespacedKeyword,
|
||||
//! ValueType,
|
||||
//! };
|
||||
//!
|
||||
|
@ -41,8 +40,7 @@
|
|||
//! };
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut sqlite = mentat_db::db::new_connection("").expect("SQLite connected");
|
||||
//! let mut conn = Conn::connect(&mut sqlite).expect("connected");
|
||||
//! let (mut sqlite, mut conn) = mentat::open("").expect("connected");
|
||||
//!
|
||||
//! {
|
||||
//! // Read the list of installed vocabularies.
|
||||
|
@ -64,10 +62,10 @@
|
|||
//!
|
||||
//! // Make sure our vocabulary is installed, and install if necessary.
|
||||
//! in_progress.ensure_vocabulary(&Definition {
|
||||
//! name: NamespacedKeyword::new("example", "links"),
|
||||
//! name: kw!(:example/links),
|
||||
//! version: 1,
|
||||
//! attributes: vec![
|
||||
//! (NamespacedKeyword::new("link", "title"),
|
||||
//! (kw!(:link/title),
|
||||
//! vocabulary::AttributeBuilder::default()
|
||||
//! .value_type(ValueType::String)
|
||||
//! .multival(false)
|
||||
|
@ -85,22 +83,19 @@
|
|||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use mentat_core::{
|
||||
Attribute,
|
||||
Entid,
|
||||
HasSchema,
|
||||
KnownEntid,
|
||||
NamespacedKeyword,
|
||||
TypedValue,
|
||||
ValueType,
|
||||
};
|
||||
|
||||
pub use mentat_core::attribute;
|
||||
use mentat_core::attribute::Unique;
|
||||
use mentat_core::KnownEntid;
|
||||
|
||||
use ::{
|
||||
CORE_SCHEMA_VERSION,
|
||||
Attribute,
|
||||
Entid,
|
||||
HasSchema,
|
||||
IntoResult,
|
||||
NamespacedKeyword,
|
||||
TypedValue,
|
||||
ValueType,
|
||||
};
|
||||
|
||||
use ::conn::{
|
||||
|
@ -170,25 +165,25 @@ impl Vocabularies {
|
|||
|
||||
lazy_static! {
|
||||
static ref DB_SCHEMA_CORE: NamespacedKeyword = {
|
||||
NamespacedKeyword::new("db.schema", "core")
|
||||
kw!(:db.schema/core)
|
||||
};
|
||||
static ref DB_SCHEMA_ATTRIBUTE: NamespacedKeyword = {
|
||||
NamespacedKeyword::new("db.schema", "attribute")
|
||||
kw!(:db.schema/attribute)
|
||||
};
|
||||
static ref DB_SCHEMA_VERSION: NamespacedKeyword = {
|
||||
NamespacedKeyword::new("db.schema", "version")
|
||||
kw!(:db.schema/version)
|
||||
};
|
||||
static ref DB_IDENT: NamespacedKeyword = {
|
||||
NamespacedKeyword::new("db", "ident")
|
||||
kw!(:db/ident)
|
||||
};
|
||||
static ref DB_UNIQUE: NamespacedKeyword = {
|
||||
NamespacedKeyword::new("db", "unique")
|
||||
kw!(:db/unique)
|
||||
};
|
||||
static ref DB_UNIQUE_VALUE: NamespacedKeyword = {
|
||||
NamespacedKeyword::new("db.unique", "value")
|
||||
kw!(:db.unique/value)
|
||||
};
|
||||
static ref DB_UNIQUE_IDENTITY: NamespacedKeyword = {
|
||||
NamespacedKeyword::new("db.unique", "identity")
|
||||
kw!(:db.unique/identity)
|
||||
};
|
||||
static ref DB_IS_COMPONENT: NamespacedKeyword = {
|
||||
NamespacedKeyword::new("db", "isComponent")
|
||||
|
@ -197,19 +192,19 @@ lazy_static! {
|
|||
NamespacedKeyword::new("db", "valueType")
|
||||
};
|
||||
static ref DB_INDEX: NamespacedKeyword = {
|
||||
NamespacedKeyword::new("db", "index")
|
||||
kw!(:db/index)
|
||||
};
|
||||
static ref DB_FULLTEXT: NamespacedKeyword = {
|
||||
NamespacedKeyword::new("db", "fulltext")
|
||||
kw!(:db/fulltext)
|
||||
};
|
||||
static ref DB_CARDINALITY: NamespacedKeyword = {
|
||||
NamespacedKeyword::new("db", "cardinality")
|
||||
kw!(:db/cardinality)
|
||||
};
|
||||
static ref DB_CARDINALITY_ONE: NamespacedKeyword = {
|
||||
NamespacedKeyword::new("db.cardinality", "one")
|
||||
kw!(:db.cardinality/one)
|
||||
};
|
||||
static ref DB_CARDINALITY_MANY: NamespacedKeyword = {
|
||||
NamespacedKeyword::new("db.cardinality", "many")
|
||||
kw!(:db.cardinality/many)
|
||||
};
|
||||
|
||||
// Not yet supported.
|
||||
|
@ -574,32 +569,24 @@ impl<T> HasVocabularies for T where T: HasSchema + Queryable {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ::{
|
||||
NamespacedKeyword,
|
||||
Conn,
|
||||
new_connection,
|
||||
};
|
||||
|
||||
use super::HasVocabularies;
|
||||
|
||||
#[test]
|
||||
fn test_read_vocabularies() {
|
||||
let mut sqlite = new_connection("").expect("could open conn");
|
||||
let mut conn = Conn::connect(&mut sqlite).expect("could open store");
|
||||
let (mut sqlite, mut conn) = ::open("").expect("opened");
|
||||
let vocabularies = conn.begin_read(&mut sqlite).expect("in progress")
|
||||
.read_vocabularies().expect("OK");
|
||||
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);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_core_schema() {
|
||||
let mut c = new_connection("").expect("could open conn");
|
||||
let mut conn = Conn::connect(&mut c).expect("could open store");
|
||||
let in_progress = conn.begin_transaction(&mut c).expect("in progress");
|
||||
let (mut sqlite, mut conn) = ::open("").expect("opened");
|
||||
let in_progress = conn.begin_transaction(&mut sqlite).expect("in progress");
|
||||
let vocab = in_progress.read_vocabularies().expect("vocabulary");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ fn can_import_sqlite() {
|
|||
data: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
let conn = mentat::get_connection();
|
||||
let conn = mentat::new_connection("").expect("SQLite connected");
|
||||
|
||||
conn.execute("CREATE TABLE person (
|
||||
id INTEGER PRIMARY KEY,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
extern crate chrono;
|
||||
extern crate time;
|
||||
|
||||
#[macro_use]
|
||||
extern crate mentat;
|
||||
extern crate mentat_core;
|
||||
extern crate mentat_db;
|
||||
|
@ -482,9 +483,9 @@ fn test_lookup() {
|
|||
]"#).unwrap().tempids;
|
||||
|
||||
let entid = ids.get("b").unwrap();
|
||||
let foo_date = NamespacedKeyword::new("foo", "date");
|
||||
let foo_many = NamespacedKeyword::new("foo", "many");
|
||||
let db_ident = NamespacedKeyword::new("db", "ident");
|
||||
let foo_date = kw!(:foo/date);
|
||||
let foo_many = kw!(:foo/many);
|
||||
let db_ident = kw!(:db/ident);
|
||||
let expected = TypedValue::Instant(DateTime::<Utc>::from_str("2016-01-01T11:00:00.000Z").unwrap());
|
||||
|
||||
// Fetch a value.
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
#[macro_use]
|
||||
extern crate mentat;
|
||||
extern crate mentat_core;
|
||||
extern crate mentat_db;
|
||||
|
@ -47,16 +48,16 @@ use mentat::errors::{
|
|||
|
||||
lazy_static! {
|
||||
static ref FOO_NAME: NamespacedKeyword = {
|
||||
NamespacedKeyword::new("foo", "name")
|
||||
kw!(:foo/name)
|
||||
};
|
||||
|
||||
static ref FOO_MOMENT: NamespacedKeyword = {
|
||||
NamespacedKeyword::new("foo", "moment")
|
||||
kw!(:foo/moment)
|
||||
};
|
||||
|
||||
static ref FOO_VOCAB: vocabulary::Definition = {
|
||||
vocabulary::Definition {
|
||||
name: NamespacedKeyword::new("org.mozilla", "foo"),
|
||||
name: kw!(:org.mozilla/foo),
|
||||
version: 1,
|
||||
attributes: vec![
|
||||
(FOO_NAME.clone(),
|
||||
|
@ -129,24 +130,24 @@ fn test_add_vocab() {
|
|||
.fulltext(true)
|
||||
.build();
|
||||
let bar_only = vec![
|
||||
(NamespacedKeyword::new("foo", "bar"), bar.clone()),
|
||||
(kw!(:foo/bar), bar.clone()),
|
||||
];
|
||||
let baz_only = vec![
|
||||
(NamespacedKeyword::new("foo", "baz"), baz.clone()),
|
||||
(kw!(:foo/baz), baz.clone()),
|
||||
];
|
||||
let bar_and_baz = vec![
|
||||
(NamespacedKeyword::new("foo", "bar"), bar.clone()),
|
||||
(NamespacedKeyword::new("foo", "baz"), baz.clone()),
|
||||
(kw!(:foo/bar), bar.clone()),
|
||||
(kw!(:foo/baz), baz.clone()),
|
||||
];
|
||||
|
||||
let foo_v1_a = vocabulary::Definition {
|
||||
name: NamespacedKeyword::new("org.mozilla", "foo"),
|
||||
name: kw!(:org.mozilla/foo),
|
||||
version: 1,
|
||||
attributes: bar_only.clone(),
|
||||
};
|
||||
|
||||
let foo_v1_b = vocabulary::Definition {
|
||||
name: NamespacedKeyword::new("org.mozilla", "foo"),
|
||||
name: kw!(:org.mozilla/foo),
|
||||
version: 1,
|
||||
attributes: bar_and_baz.clone(),
|
||||
};
|
||||
|
@ -244,11 +245,11 @@ fn test_add_vocab() {
|
|||
.multival(true)
|
||||
.build();
|
||||
let bar_and_malformed_baz = vec![
|
||||
(NamespacedKeyword::new("foo", "bar"), bar),
|
||||
(NamespacedKeyword::new("foo", "baz"), malformed_baz.clone()),
|
||||
(kw!(:foo/bar), bar),
|
||||
(kw!(:foo/baz), malformed_baz.clone()),
|
||||
];
|
||||
let foo_v1_malformed = vocabulary::Definition {
|
||||
name: NamespacedKeyword::new("org.mozilla", "foo"),
|
||||
name: kw!(:org.mozilla/foo),
|
||||
version: 1,
|
||||
attributes: bar_and_malformed_baz.clone(),
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue