Convert src/ to failure.
This commit is contained in:
parent
836fdb3a35
commit
4e01929334
11 changed files with 131 additions and 197 deletions
|
@ -28,7 +28,8 @@ rustc_version = "0.2"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
error-chain = { git = "https://github.com/rnewman/error-chain", branch = "rnewman/sync" }
|
failure = "0.1.1"
|
||||||
|
failure_derive = "0.1.1"
|
||||||
lazy_static = "0.2"
|
lazy_static = "0.2"
|
||||||
time = "0.1"
|
time = "0.1"
|
||||||
uuid = { version = "0.5", features = ["v4", "serde"] }
|
uuid = { version = "0.5", features = ["v4", "serde"] }
|
||||||
|
|
50
src/conn.rs
50
src/conn.rs
|
@ -93,7 +93,10 @@ use entity_builder::{
|
||||||
TermBuilder,
|
TermBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
use errors::*;
|
use errors::{
|
||||||
|
Result,
|
||||||
|
MentatError,
|
||||||
|
};
|
||||||
|
|
||||||
use query::{
|
use query::{
|
||||||
Known,
|
Known,
|
||||||
|
@ -474,7 +477,7 @@ impl<'a, 'c> InProgress<'a, 'c> {
|
||||||
// Retrying is tracked by https://github.com/mozilla/mentat/issues/357.
|
// Retrying is tracked by https://github.com/mozilla/mentat/issues/357.
|
||||||
// This should not occur -- an attempt to take a competing IMMEDIATE transaction
|
// This should not occur -- an attempt to take a competing IMMEDIATE transaction
|
||||||
// will fail with `SQLITE_BUSY`, causing this function to abort.
|
// will fail with `SQLITE_BUSY`, causing this function to abort.
|
||||||
bail!("Lost the transact() race!");
|
bail!(MentatError::UnexpectedLostTransactRace);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit the SQLite transaction while we hold the mutex.
|
// Commit the SQLite transaction while we hold the mutex.
|
||||||
|
@ -506,7 +509,7 @@ impl<'a, 'c> InProgress<'a, 'c> {
|
||||||
cache_action: CacheAction) -> Result<()> {
|
cache_action: CacheAction) -> Result<()> {
|
||||||
let attribute_entid: Entid = self.schema
|
let attribute_entid: Entid = self.schema
|
||||||
.attribute_for_ident(&attribute)
|
.attribute_for_ident(&attribute)
|
||||||
.ok_or_else(|| ErrorKind::UnknownAttribute(attribute.to_string()))?.1.into();
|
.ok_or_else(|| MentatError::UnknownAttribute(attribute.to_string()))?.1.into();
|
||||||
|
|
||||||
match cache_action {
|
match cache_action {
|
||||||
CacheAction::Register => {
|
CacheAction::Register => {
|
||||||
|
@ -579,17 +582,16 @@ impl Conn {
|
||||||
/// Prepare the provided SQLite handle for use as a Mentat store. Creates tables but
|
/// Prepare the provided SQLite handle for use as a Mentat store. Creates tables but
|
||||||
/// _does not_ write the bootstrap schema. This constructor should only be used by
|
/// _does not_ write the bootstrap schema. This constructor should only be used by
|
||||||
/// consumers that expect to populate raw transaction data themselves.
|
/// consumers that expect to populate raw transaction data themselves.
|
||||||
|
|
||||||
pub(crate) fn empty(sqlite: &mut rusqlite::Connection) -> Result<Conn> {
|
pub(crate) fn empty(sqlite: &mut rusqlite::Connection) -> Result<Conn> {
|
||||||
let (tx, db) = db::create_empty_current_version(sqlite)
|
let (tx, db) = db::create_empty_current_version(sqlite)?;
|
||||||
.chain_err(|| "Unable to initialize Mentat store")?;
|
|
||||||
tx.commit()?;
|
tx.commit()?;
|
||||||
Ok(Conn::new(db.partition_map, db.schema))
|
Ok(Conn::new(db.partition_map, db.schema))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn connect(sqlite: &mut rusqlite::Connection) -> Result<Conn> {
|
pub fn connect(sqlite: &mut rusqlite::Connection) -> Result<Conn> {
|
||||||
let db = db::ensure_current_version(sqlite)
|
let db = db::ensure_current_version(sqlite)?;
|
||||||
.chain_err(|| "Unable to initialize Mentat store")?;
|
|
||||||
Ok(Conn::new(db.partition_map, db.schema))
|
Ok(Conn::new(db.partition_map, db.schema))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -801,7 +803,7 @@ impl Conn {
|
||||||
{
|
{
|
||||||
attribute_entid = metadata.schema
|
attribute_entid = metadata.schema
|
||||||
.attribute_for_ident(&attribute)
|
.attribute_for_ident(&attribute)
|
||||||
.ok_or_else(|| ErrorKind::UnknownAttribute(attribute.to_string()))?.1.into();
|
.ok_or_else(|| MentatError::UnknownAttribute(attribute.to_string()))?.1.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
let cache = &mut metadata.attribute_cache;
|
let cache = &mut metadata.attribute_cache;
|
||||||
|
@ -869,11 +871,11 @@ mod tests {
|
||||||
.partition_map[":db.part/user"].index;
|
.partition_map[":db.part/user"].index;
|
||||||
let t = format!("[[:db/add {} :db.schema/attribute \"tempid\"]]", next + 1);
|
let t = format!("[[:db/add {} :db.schema/attribute \"tempid\"]]", next + 1);
|
||||||
|
|
||||||
match conn.transact(&mut sqlite, t.as_str()).unwrap_err() {
|
match conn.transact(&mut sqlite, t.as_str()).expect_err("expected transact error").downcast() {
|
||||||
Error(ErrorKind::DbError(::mentat_db::errors::ErrorKind::UnrecognizedEntid(e)), _) => {
|
Ok(::mentat_db::DbError::UnrecognizedEntid(e)) => {
|
||||||
assert_eq!(e, next + 1);
|
assert_eq!(e, next + 1);
|
||||||
},
|
},
|
||||||
x => panic!("expected transact error, got {:?}", x),
|
x => panic!("expected db error, got {:?}", x),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transact two more tempids.
|
// Transact two more tempids.
|
||||||
|
@ -896,12 +898,12 @@ mod tests {
|
||||||
// we should reject this, because the first ID was provided by the user!
|
// we should reject this, because the first ID was provided by the user!
|
||||||
let t = format!("[[:db/add {} :db.schema/attribute \"tempid\"]]", next);
|
let t = format!("[[:db/add {} :db.schema/attribute \"tempid\"]]", next);
|
||||||
|
|
||||||
match conn.transact(&mut sqlite, t.as_str()).unwrap_err() {
|
match conn.transact(&mut sqlite, t.as_str()).expect_err("expected transact error").downcast() {
|
||||||
Error(ErrorKind::DbError(::mentat_db::errors::ErrorKind::UnrecognizedEntid(e)), _) => {
|
Ok(::mentat_db::DbError::UnrecognizedEntid(e)) => {
|
||||||
// All this, despite this being the ID we were about to allocate!
|
// All this, despite this being the ID we were about to allocate!
|
||||||
assert_eq!(e, next);
|
assert_eq!(e, next);
|
||||||
},
|
},
|
||||||
x => panic!("expected transact error, got {:?}", x),
|
x => panic!("expected db error, got {:?}", x),
|
||||||
}
|
}
|
||||||
|
|
||||||
// And if we subsequently transact in a way that allocates one ID, we _will_ use that one.
|
// And if we subsequently transact in a way that allocates one ID, we _will_ use that one.
|
||||||
|
@ -1057,9 +1059,9 @@ mod tests {
|
||||||
|
|
||||||
// Bad EDN: missing closing ']'.
|
// Bad EDN: missing closing ']'.
|
||||||
let report = conn.transact(&mut sqlite, "[[:db/add \"t\" :db/ident :a/keyword]");
|
let report = conn.transact(&mut sqlite, "[[:db/add \"t\" :db/ident :a/keyword]");
|
||||||
match report.unwrap_err() {
|
match report.expect_err("expected transact to fail for bad edn").downcast() {
|
||||||
Error(ErrorKind::EdnParseError(_), _) => { },
|
Ok(edn::ParseError { .. }) => { },
|
||||||
x => panic!("expected EDN parse error, got {:?}", x),
|
Err(x) => panic!("expected EDN parse error, got {:?}", x),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Good EDN.
|
// Good EDN.
|
||||||
|
@ -1068,9 +1070,9 @@ mod tests {
|
||||||
|
|
||||||
// Bad transaction data: missing leading :db/add.
|
// Bad transaction data: missing leading :db/add.
|
||||||
let report = conn.transact(&mut sqlite, "[[\"t\" :db/ident :b/keyword]]");
|
let report = conn.transact(&mut sqlite, "[[\"t\" :db/ident :b/keyword]]");
|
||||||
match report.unwrap_err() {
|
match report.expect_err("expected transact error").downcast() {
|
||||||
Error(ErrorKind::EdnParseError(_), _) => { },
|
Ok(edn::ParseError { .. }) => { },
|
||||||
x => panic!("expected EDN parse error, got {:?}", x),
|
Err(x) => panic!("expected EDN parse error, got {:?}", x),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Good transaction data.
|
// Good transaction data.
|
||||||
|
@ -1080,8 +1082,8 @@ mod tests {
|
||||||
// Bad transaction based on state of store: conflicting upsert.
|
// Bad transaction based on state of store: conflicting upsert.
|
||||||
let report = conn.transact(&mut sqlite, "[[:db/add \"u\" :db/ident :a/keyword]
|
let report = conn.transact(&mut sqlite, "[[:db/add \"u\" :db/ident :a/keyword]
|
||||||
[:db/add \"u\" :db/ident :b/keyword]]");
|
[:db/add \"u\" :db/ident :b/keyword]]");
|
||||||
match report.unwrap_err() {
|
match report.expect_err("expected transact error").downcast() {
|
||||||
Error(ErrorKind::DbError(::mentat_db::errors::ErrorKind::SchemaConstraintViolation(_)), _) => { },
|
Ok(::mentat_db::DbError::SchemaConstraintViolation(_)) => { },
|
||||||
x => panic!("expected schema constraint violation, got {:?}", x),
|
x => panic!("expected schema constraint violation, got {:?}", x),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1099,8 +1101,8 @@ mod tests {
|
||||||
let kw = kw!(:foo/bat);
|
let kw = kw!(:foo/bat);
|
||||||
let schema = conn.current_schema();
|
let schema = conn.current_schema();
|
||||||
let res = conn.cache(&mut sqlite, &schema, &kw, CacheDirection::Forward, CacheAction::Register);
|
let res = conn.cache(&mut sqlite, &schema, &kw, CacheDirection::Forward, CacheAction::Register);
|
||||||
match res.unwrap_err() {
|
match res.expect_err("expected cache to fail").downcast() {
|
||||||
Error(ErrorKind::UnknownAttribute(msg), _) => assert_eq!(msg, ":foo/bat"),
|
Ok(MentatError::UnknownAttribute(msg)) => assert_eq!(msg, ":foo/bat"),
|
||||||
x => panic!("expected UnknownAttribute error, got {:?}", x),
|
x => panic!("expected UnknownAttribute error, got {:?}", x),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ use conn::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use errors::{
|
use errors::{
|
||||||
ErrorKind,
|
MentatError,
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -277,12 +277,12 @@ impl<'a, 'c> InProgressBuilder<'a, 'c> {
|
||||||
let provided = tv.value_type();
|
let provided = tv.value_type();
|
||||||
let expected = attr.value_type;
|
let expected = attr.value_type;
|
||||||
if provided != expected {
|
if provided != expected {
|
||||||
bail!(ErrorKind::ValueTypeMismatch(provided, expected));
|
bail!(MentatError::ValueTypeMismatch(provided, expected));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
attribute = aa;
|
attribute = aa;
|
||||||
} else {
|
} else {
|
||||||
bail!(ErrorKind::UnknownAttribute(a.to_string()));
|
bail!(MentatError::UnknownAttribute(a.to_string()));
|
||||||
}
|
}
|
||||||
Ok((attribute, v))
|
Ok((attribute, v))
|
||||||
}
|
}
|
||||||
|
@ -380,11 +380,6 @@ impl FromThing<KnownEntid> for TypedValueOr<TempIdHandle> {
|
||||||
mod testing {
|
mod testing {
|
||||||
extern crate mentat_db;
|
extern crate mentat_db;
|
||||||
|
|
||||||
use errors::{
|
|
||||||
Error,
|
|
||||||
ErrorKind,
|
|
||||||
};
|
|
||||||
|
|
||||||
// For matching inside a test.
|
// For matching inside a test.
|
||||||
use mentat_db::ErrorKind::{
|
use mentat_db::ErrorKind::{
|
||||||
UnrecognizedEntid,
|
UnrecognizedEntid,
|
||||||
|
@ -429,7 +424,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(ErrorKind::DbError(UnrecognizedEntid(e)), _)) = in_progress.transact_terms(terms, tempids) {
|
if let Err(Error(MentatError::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.");
|
||||||
|
|
137
src/errors.rs
137
src/errors.rs
|
@ -10,102 +10,63 @@
|
||||||
|
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use rusqlite;
|
use std; // To refer to std::result::Result.
|
||||||
|
|
||||||
use uuid;
|
|
||||||
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
use edn;
|
use failure::Error;
|
||||||
|
|
||||||
use mentat_core::{
|
use mentat_core::{
|
||||||
Attribute,
|
Attribute,
|
||||||
ValueType,
|
ValueType,
|
||||||
};
|
};
|
||||||
use mentat_db;
|
|
||||||
use mentat_query;
|
use mentat_query;
|
||||||
use mentat_query_algebrizer;
|
|
||||||
use mentat_query_projector;
|
|
||||||
use mentat_query_pull;
|
|
||||||
use mentat_query_translator;
|
|
||||||
use mentat_sql;
|
|
||||||
use mentat_tolstoy;
|
|
||||||
|
|
||||||
error_chain! {
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
types {
|
|
||||||
Error, ErrorKind, ResultExt, Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreign_links {
|
#[macro_export]
|
||||||
EdnParseError(edn::ParseError);
|
macro_rules! bail {
|
||||||
Rusqlite(rusqlite::Error);
|
($e:expr) => (
|
||||||
UuidParseError(uuid::ParseError);
|
return Err($e.into());
|
||||||
IoError(::std::io::Error);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
links {
|
#[derive(Debug, Fail)]
|
||||||
DbError(mentat_db::Error, mentat_db::ErrorKind);
|
pub enum MentatError {
|
||||||
QueryError(mentat_query_algebrizer::Error, mentat_query_algebrizer::ErrorKind); // Let's not leak the term 'algebrizer'.
|
#[fail(display = "path {} already exists", _0)]
|
||||||
ProjectorError(mentat_query_projector::errors::Error, mentat_query_projector::errors::ErrorKind);
|
PathAlreadyExists(String),
|
||||||
PullError(mentat_query_pull::errors::Error, mentat_query_pull::errors::ErrorKind);
|
|
||||||
TranslatorError(mentat_query_translator::Error, mentat_query_translator::ErrorKind);
|
#[fail(display = "variables {:?} unbound at query execution time", _0)]
|
||||||
SqlError(mentat_sql::Error, mentat_sql::ErrorKind);
|
UnboundVariables(BTreeSet<String>),
|
||||||
SyncError(mentat_tolstoy::Error, mentat_tolstoy::ErrorKind);
|
|
||||||
}
|
#[fail(display = "invalid argument name: '{}'", _0)]
|
||||||
|
InvalidArgumentName(String),
|
||||||
errors {
|
|
||||||
PathAlreadyExists(path: String) {
|
#[fail(display = "unknown attribute: '{}'", _0)]
|
||||||
description("path already exists")
|
UnknownAttribute(String),
|
||||||
display("path {} already exists", path)
|
|
||||||
}
|
#[fail(display = "invalid vocabulary version")]
|
||||||
|
InvalidVocabularyVersion,
|
||||||
UnboundVariables(names: BTreeSet<String>) {
|
|
||||||
description("unbound variables at query execution time")
|
#[fail(display = "vocabulary {}/{} already has attribute {}, and the requested definition differs", _0, _1, _2)]
|
||||||
display("variables {:?} unbound at query execution time", names)
|
ConflictingAttributeDefinitions(String, ::vocabulary::Version, String, Attribute, Attribute),
|
||||||
}
|
|
||||||
|
#[fail(display = "existing vocabulary {} too new: wanted {}, got {}", _0, _1, _2)]
|
||||||
InvalidArgumentName(name: String) {
|
ExistingVocabularyTooNew(String, ::vocabulary::Version, ::vocabulary::Version),
|
||||||
description("invalid argument name")
|
|
||||||
display("invalid argument name: '{}'", name)
|
#[fail(display = "core schema: wanted {}, got {:?}", _0, _1)]
|
||||||
}
|
UnexpectedCoreSchema(::vocabulary::Version, Option<::vocabulary::Version>),
|
||||||
|
|
||||||
UnknownAttribute(name: String) {
|
#[fail(display = "Lost the transact() race!")]
|
||||||
description("unknown attribute")
|
UnexpectedLostTransactRace,
|
||||||
display("unknown attribute: '{}'", name)
|
|
||||||
}
|
#[fail(display = "missing core attribute {}", _0)]
|
||||||
|
MissingCoreVocabulary(mentat_query::Keyword),
|
||||||
InvalidVocabularyVersion {
|
|
||||||
description("invalid vocabulary version")
|
#[fail(display = "schema changed since query was prepared")]
|
||||||
display("invalid vocabulary version")
|
PreparedQuerySchemaMismatch,
|
||||||
}
|
|
||||||
|
#[fail(display = "provided value of type {} doesn't match attribute value type {}", _0, _1)]
|
||||||
ConflictingAttributeDefinitions(vocabulary: String, version: ::vocabulary::Version, attribute: String, current: Attribute, requested: Attribute) {
|
ValueTypeMismatch(ValueType, ValueType),
|
||||||
description("conflicting attribute definitions")
|
|
||||||
display("vocabulary {}/{} already has attribute {}, and the requested definition differs", vocabulary, version, attribute)
|
|
||||||
}
|
|
||||||
|
|
||||||
ExistingVocabularyTooNew(name: String, existing: ::vocabulary::Version, ours: ::vocabulary::Version) {
|
|
||||||
description("existing vocabulary too new")
|
|
||||||
display("existing vocabulary too new: wanted {}, got {}", ours, existing)
|
|
||||||
}
|
|
||||||
|
|
||||||
UnexpectedCoreSchema(version: Option<::vocabulary::Version>) {
|
|
||||||
description("unexpected core schema version")
|
|
||||||
display("core schema: wanted {}, got {:?}", mentat_db::CORE_SCHEMA_VERSION, version)
|
|
||||||
}
|
|
||||||
|
|
||||||
MissingCoreVocabulary(kw: mentat_query::Keyword) {
|
|
||||||
description("missing core vocabulary")
|
|
||||||
display("missing core attribute {}", kw)
|
|
||||||
}
|
|
||||||
|
|
||||||
PreparedQuerySchemaMismatch {
|
|
||||||
description("schema changed since query was prepared")
|
|
||||||
display("schema changed since query was prepared")
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueTypeMismatch(provided: ValueType, expected: ValueType) {
|
|
||||||
description("provided value doesn't match value type")
|
|
||||||
display("provided value of type {} doesn't match attribute value type {}", provided, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
#![recursion_limit="128"]
|
#![recursion_limit="128"]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate error_chain;
|
extern crate failure_derive;
|
||||||
|
extern crate failure;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
@ -101,9 +102,10 @@ macro_rules! kw {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
pub mod errors;
|
||||||
pub mod conn;
|
pub mod conn;
|
||||||
pub mod entity_builder;
|
pub mod entity_builder;
|
||||||
pub mod errors;
|
|
||||||
pub mod ident;
|
pub mod ident;
|
||||||
pub mod query;
|
pub mod query;
|
||||||
pub mod query_builder;
|
pub mod query_builder;
|
||||||
|
|
|
@ -74,7 +74,7 @@ pub use mentat_query_projector::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use errors::{
|
use errors::{
|
||||||
ErrorKind,
|
MentatError,
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ fn algebrize_query<T>
|
||||||
// If they aren't, the user has made an error -- perhaps writing the wrong variable in `:in`, or
|
// If they aren't, the user has made an error -- perhaps writing the wrong variable in `:in`, or
|
||||||
// not binding in the `QueryInput`.
|
// not binding in the `QueryInput`.
|
||||||
if !unbound.is_empty() {
|
if !unbound.is_empty() {
|
||||||
bail!(ErrorKind::UnboundVariables(unbound.into_iter().map(|v| v.to_string()).collect()));
|
bail!(MentatError::UnboundVariables(unbound.into_iter().map(|v| v.to_string()).collect()));
|
||||||
}
|
}
|
||||||
Ok(algebrized)
|
Ok(algebrized)
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ fn fetch_values<'sqlite>
|
||||||
|
|
||||||
fn lookup_attribute(schema: &Schema, attribute: &Keyword) -> Result<KnownEntid> {
|
fn lookup_attribute(schema: &Schema, attribute: &Keyword) -> Result<KnownEntid> {
|
||||||
schema.get_entid(attribute)
|
schema.get_entid(attribute)
|
||||||
.ok_or_else(|| ErrorKind::UnknownAttribute(attribute.name().into()).into())
|
.ok_or_else(|| MentatError::UnknownAttribute(attribute.name().into()).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a single value for the provided entity and attribute.
|
/// Return a single value for the provided entity and attribute.
|
||||||
|
@ -398,7 +398,7 @@ pub fn q_prepare<'sqlite, 'schema, 'cache, 'query, T>
|
||||||
if !unbound.is_empty() {
|
if !unbound.is_empty() {
|
||||||
// TODO: Allow binding variables at execution time, not just
|
// TODO: Allow binding variables at execution time, not just
|
||||||
// preparation time.
|
// preparation time.
|
||||||
bail!(ErrorKind::UnboundVariables(unbound.into_iter().map(|v| v.to_string()).collect()));
|
bail!(MentatError::UnboundVariables(unbound.into_iter().map(|v| v.to_string()).collect()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if algebrized.is_known_empty() {
|
if algebrized.is_known_empty() {
|
||||||
|
|
|
@ -34,7 +34,7 @@ use ::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use errors::{
|
use errors::{
|
||||||
ErrorKind,
|
MentatError,
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ impl<'a> QueryBuilder<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind_ref_from_kw(&mut self, var: &str, value: Keyword) -> Result<&mut Self> {
|
pub fn bind_ref_from_kw(&mut self, var: &str, value: Keyword) -> Result<&mut Self> {
|
||||||
let entid = self.store.conn().current_schema().get_entid(&value).ok_or(ErrorKind::UnknownAttribute(value.to_string()))?;
|
let entid = self.store.conn().current_schema().get_entid(&value).ok_or(MentatError::UnknownAttribute(value.to_string()))?;
|
||||||
self.values.insert(Variable::from_valid_name(var), TypedValue::Ref(entid.into()));
|
self.values.insert(Variable::from_valid_name(var), TypedValue::Ref(entid.into()));
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ impl Store {
|
||||||
pub fn open_empty(path: &str) -> Result<Store> {
|
pub fn open_empty(path: &str) -> Result<Store> {
|
||||||
if !path.is_empty() {
|
if !path.is_empty() {
|
||||||
if Path::new(path).exists() {
|
if Path::new(path).exists() {
|
||||||
bail!(ErrorKind::PathAlreadyExists(path.to_string()));
|
bail!(MentatError::PathAlreadyExists(path.to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ impl Store {
|
||||||
pub fn open_empty_with_key(path: &str, encryption_key: &str) -> Result<Store> {
|
pub fn open_empty_with_key(path: &str, encryption_key: &str) -> Result<Store> {
|
||||||
if !path.is_empty() {
|
if !path.is_empty() {
|
||||||
if Path::new(path).exists() {
|
if Path::new(path).exists() {
|
||||||
bail!(ErrorKind::PathAlreadyExists(path.to_string()));
|
bail!(MentatError::PathAlreadyExists(path.to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,7 @@ use ::conn::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use ::errors::{
|
use ::errors::{
|
||||||
ErrorKind,
|
MentatError,
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -375,17 +375,17 @@ trait HasCoreSchema {
|
||||||
impl<T> HasCoreSchema for T where T: HasSchema {
|
impl<T> HasCoreSchema for T where T: HasSchema {
|
||||||
fn core_type(&self, t: ValueType) -> Result<KnownEntid> {
|
fn core_type(&self, t: ValueType) -> Result<KnownEntid> {
|
||||||
self.entid_for_type(t)
|
self.entid_for_type(t)
|
||||||
.ok_or_else(|| ErrorKind::MissingCoreVocabulary(DB_SCHEMA_VERSION.clone()).into())
|
.ok_or_else(|| MentatError::MissingCoreVocabulary(DB_SCHEMA_VERSION.clone()).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn core_entid(&self, ident: &Keyword) -> Result<KnownEntid> {
|
fn core_entid(&self, ident: &Keyword) -> Result<KnownEntid> {
|
||||||
self.get_entid(ident)
|
self.get_entid(ident)
|
||||||
.ok_or_else(|| ErrorKind::MissingCoreVocabulary(DB_SCHEMA_VERSION.clone()).into())
|
.ok_or_else(|| MentatError::MissingCoreVocabulary(DB_SCHEMA_VERSION.clone()).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn core_attribute(&self, ident: &Keyword) -> Result<KnownEntid> {
|
fn core_attribute(&self, ident: &Keyword) -> Result<KnownEntid> {
|
||||||
self.attribute_for_ident(ident)
|
self.attribute_for_ident(ident)
|
||||||
.ok_or_else(|| ErrorKind::MissingCoreVocabulary(DB_SCHEMA_VERSION.clone()).into())
|
.ok_or_else(|| MentatError::MissingCoreVocabulary(DB_SCHEMA_VERSION.clone()).into())
|
||||||
.map(|(_, e)| e)
|
.map(|(_, e)| e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -568,7 +568,7 @@ pub trait VersionedStore: HasVocabularies + HasSchema {
|
||||||
// We have two vocabularies with the same name, same version, and
|
// We have two vocabularies with the same name, same version, and
|
||||||
// different definitions for an attribute. That's a coding error.
|
// different definitions for an attribute. That's a coding error.
|
||||||
// We can't accept this vocabulary.
|
// We can't accept this vocabulary.
|
||||||
bail!(ErrorKind::ConflictingAttributeDefinitions(
|
bail!(MentatError::ConflictingAttributeDefinitions(
|
||||||
definition.name.to_string(),
|
definition.name.to_string(),
|
||||||
definition.version,
|
definition.version,
|
||||||
pair.0.to_string(),
|
pair.0.to_string(),
|
||||||
|
@ -615,13 +615,13 @@ pub trait VersionedStore: HasVocabularies + HasSchema {
|
||||||
fn verify_core_schema(&self) -> Result<()> {
|
fn verify_core_schema(&self) -> Result<()> {
|
||||||
if let Some(core) = self.read_vocabulary_named(&DB_SCHEMA_CORE)? {
|
if let Some(core) = self.read_vocabulary_named(&DB_SCHEMA_CORE)? {
|
||||||
if core.version != CORE_SCHEMA_VERSION {
|
if core.version != CORE_SCHEMA_VERSION {
|
||||||
bail!(ErrorKind::UnexpectedCoreSchema(Some(core.version)));
|
bail!(MentatError::UnexpectedCoreSchema(CORE_SCHEMA_VERSION, Some(core.version)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check things other than the version.
|
// TODO: check things other than the version.
|
||||||
} else {
|
} else {
|
||||||
// This would be seriously messed up.
|
// This would be seriously messed up.
|
||||||
bail!(ErrorKind::UnexpectedCoreSchema(None));
|
bail!(MentatError::UnexpectedCoreSchema(CORE_SCHEMA_VERSION, None));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -682,7 +682,7 @@ impl<'a, 'c> VersionedStore for InProgress<'a, 'c> {
|
||||||
VocabularyCheck::NotPresent => self.install_vocabulary(definition),
|
VocabularyCheck::NotPresent => self.install_vocabulary(definition),
|
||||||
VocabularyCheck::PresentButNeedsUpdate { older_version } => self.upgrade_vocabulary(definition, older_version),
|
VocabularyCheck::PresentButNeedsUpdate { older_version } => self.upgrade_vocabulary(definition, older_version),
|
||||||
VocabularyCheck::PresentButMissingAttributes { attributes } => self.install_attributes_for(definition, attributes),
|
VocabularyCheck::PresentButMissingAttributes { attributes } => self.install_attributes_for(definition, attributes),
|
||||||
VocabularyCheck::PresentButTooNew { newer_version } => Err(ErrorKind::ExistingVocabularyTooNew(definition.name.to_string(), newer_version.version, definition.version).into()),
|
VocabularyCheck::PresentButTooNew { newer_version } => Err(MentatError::ExistingVocabularyTooNew(definition.name.to_string(), newer_version.version, definition.version).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,7 +701,7 @@ impl<'a, 'c> VersionedStore for InProgress<'a, 'c> {
|
||||||
out.insert(definition.name.clone(), VocabularyOutcome::Existed);
|
out.insert(definition.name.clone(), VocabularyOutcome::Existed);
|
||||||
},
|
},
|
||||||
VocabularyCheck::PresentButTooNew { newer_version } => {
|
VocabularyCheck::PresentButTooNew { newer_version } => {
|
||||||
bail!(ErrorKind::ExistingVocabularyTooNew(definition.name.to_string(), newer_version.version, definition.version));
|
bail!(MentatError::ExistingVocabularyTooNew(definition.name.to_string(), newer_version.version, definition.version));
|
||||||
},
|
},
|
||||||
|
|
||||||
c @ VocabularyCheck::NotPresent |
|
c @ VocabularyCheck::NotPresent |
|
||||||
|
@ -868,7 +868,7 @@ impl<T> HasVocabularies for T where T: HasSchema + Queryable {
|
||||||
attributes: attributes,
|
attributes: attributes,
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
Some(_) => bail!(ErrorKind::InvalidVocabularyVersion),
|
Some(_) => bail!(MentatError::InvalidVocabularyVersion),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
|
|
@ -61,8 +61,7 @@ use mentat::query::q_uncached;
|
||||||
use mentat::conn::Conn;
|
use mentat::conn::Conn;
|
||||||
|
|
||||||
use mentat::errors::{
|
use mentat::errors::{
|
||||||
Error,
|
MentatError,
|
||||||
ErrorKind,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -234,11 +233,11 @@ fn test_unbound_inputs() {
|
||||||
let results = q_uncached(&c, &db.schema,
|
let results = q_uncached(&c, &db.schema,
|
||||||
"[:find ?i . :in ?e :where [?e :db/ident ?i]]", inputs);
|
"[:find ?i . :in ?e :where [?e :db/ident ?i]]", inputs);
|
||||||
|
|
||||||
match results {
|
match results.expect_err("expected unbound variables").downcast().expect("expected specific error") {
|
||||||
Result::Err(Error(ErrorKind::UnboundVariables(vars), _)) => {
|
MentatError::UnboundVariables(vars) => {
|
||||||
assert_eq!(vars, vec!["?e".to_string()].into_iter().collect());
|
assert_eq!(vars, vec!["?e".to_string()].into_iter().collect());
|
||||||
},
|
},
|
||||||
_ => panic!("Expected unbound variables."),
|
_ => panic!("Expected UnboundVariables variant."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,8 +411,8 @@ fn test_fulltext() {
|
||||||
[?a :foo/term ?term]
|
[?a :foo/term ?term]
|
||||||
]"#;
|
]"#;
|
||||||
let r = conn.q_once(&mut c, query, None);
|
let r = conn.q_once(&mut c, query, None);
|
||||||
match r {
|
match r.expect_err("expected query to fail").downcast() {
|
||||||
Err(Error(ErrorKind::QueryError(mentat_query_algebrizer::ErrorKind::InvalidArgument(PlainSymbol(s), ty, i)), _)) => {
|
Ok(mentat_query_algebrizer::AlgebrizerError::InvalidArgument(PlainSymbol(s), ty, i)) => {
|
||||||
assert_eq!(s, "fulltext");
|
assert_eq!(s, "fulltext");
|
||||||
assert_eq!(ty, "string");
|
assert_eq!(ty, "string");
|
||||||
assert_eq!(i, 2);
|
assert_eq!(i, 2);
|
||||||
|
@ -427,8 +426,8 @@ fn test_fulltext() {
|
||||||
[?a :foo/term ?term]
|
[?a :foo/term ?term]
|
||||||
[(fulltext $ :foo/fts ?a) [[?x ?val]]]]"#;
|
[(fulltext $ :foo/fts ?a) [[?x ?val]]]]"#;
|
||||||
let r = conn.q_once(&mut c, query, None);
|
let r = conn.q_once(&mut c, query, None);
|
||||||
match r {
|
match r.expect_err("expected query to fail").downcast() {
|
||||||
Err(Error(ErrorKind::QueryError(mentat_query_algebrizer::ErrorKind::InvalidArgument(PlainSymbol(s), ty, i)), _)) => {
|
Ok(mentat_query_algebrizer::AlgebrizerError::InvalidArgument(PlainSymbol(s), ty, i)) => {
|
||||||
assert_eq!(s, "fulltext");
|
assert_eq!(s, "fulltext");
|
||||||
assert_eq!(ty, "string");
|
assert_eq!(ty, "string");
|
||||||
assert_eq!(i, 2);
|
assert_eq!(i, 2);
|
||||||
|
@ -583,42 +582,25 @@ fn test_aggregates_type_handling() {
|
||||||
// No type limits => can't do it.
|
// No type limits => can't do it.
|
||||||
let r = store.q_once(r#"[:find (sum ?v) . :where [_ _ ?v]]"#, None);
|
let r = store.q_once(r#"[:find (sum ?v) . :where [_ _ ?v]]"#, None);
|
||||||
let all_types = ValueTypeSet::any();
|
let all_types = ValueTypeSet::any();
|
||||||
match r {
|
match r.expect_err("expected query to fail").downcast() {
|
||||||
Result::Err(
|
Ok(::mentat_query_projector::errors::ProjectorError::CannotApplyAggregateOperationToTypes(
|
||||||
Error(
|
SimpleAggregationOp::Sum, types)) => {
|
||||||
ErrorKind::TranslatorError(
|
assert_eq!(types, all_types);
|
||||||
::mentat_query_translator::ErrorKind::ProjectorError(
|
},
|
||||||
::mentat_query_projector::errors::ErrorKind::CannotApplyAggregateOperationToTypes(
|
e => panic!("Unexpected error type {:?}", e),
|
||||||
SimpleAggregationOp::Sum,
|
|
||||||
types
|
|
||||||
),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
_)) => {
|
|
||||||
assert_eq!(types, all_types);
|
|
||||||
},
|
|
||||||
r => panic!("Unexpected: {:?}", r),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// You can't sum instants.
|
// You can't sum instants.
|
||||||
let r = store.q_once(r#"[:find (sum ?v) .
|
let r = store.q_once(r#"[:find (sum ?v) .
|
||||||
:where [_ _ ?v] [(type ?v :db.type/instant)]]"#,
|
:where [_ _ ?v] [(type ?v :db.type/instant)]]"#,
|
||||||
None);
|
None);
|
||||||
match r {
|
match r.expect_err("expected query to fail").downcast() {
|
||||||
Result::Err(
|
Ok(::mentat_query_projector::errors::ProjectorError::CannotApplyAggregateOperationToTypes(
|
||||||
Error(
|
SimpleAggregationOp::Sum,
|
||||||
ErrorKind::TranslatorError(
|
types)) => {
|
||||||
::mentat_query_translator::ErrorKind::ProjectorError(
|
assert_eq!(types, ValueTypeSet::of_one(ValueType::Instant));
|
||||||
::mentat_query_projector::errors::ErrorKind::CannotApplyAggregateOperationToTypes(
|
},
|
||||||
SimpleAggregationOp::Sum,
|
e => panic!("Unexpected error type {:?}", e),
|
||||||
types
|
|
||||||
),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
_)) => {
|
|
||||||
assert_eq!(types, ValueTypeSet::of_one(ValueType::Instant));
|
|
||||||
},
|
|
||||||
r => panic!("Unexpected: {:?}", r),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// But you can count them.
|
// But you can count them.
|
||||||
|
@ -1354,19 +1336,13 @@ fn test_aggregation_implicit_grouping() {
|
||||||
[?person :foo/play ?game]
|
[?person :foo/play ?game]
|
||||||
[?person :foo/is-vegetarian true]
|
[?person :foo/is-vegetarian true]
|
||||||
[?person :foo/name ?name]]"#, None);
|
[?person :foo/name ?name]]"#, None);
|
||||||
match res {
|
match res.expect_err("expected query to fail").downcast() {
|
||||||
Result::Err(
|
Ok(::mentat_query_projector::errors::ProjectorError::AmbiguousAggregates(mmc, cc)) => {
|
||||||
Error(
|
|
||||||
ErrorKind::TranslatorError(
|
|
||||||
::mentat_query_translator::ErrorKind::ProjectorError(
|
|
||||||
::mentat_query_projector::errors::ErrorKind::AmbiguousAggregates(mmc, cc)
|
|
||||||
)
|
|
||||||
), _)) => {
|
|
||||||
assert_eq!(mmc, 2);
|
assert_eq!(mmc, 2);
|
||||||
assert_eq!(cc, 1);
|
assert_eq!(cc, 1);
|
||||||
},
|
},
|
||||||
r => {
|
e => {
|
||||||
panic!("Unexpected result {:?}.", r);
|
panic!("Unexpected error type {:?}.", e);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,10 +59,7 @@ use mentat::entity_builder::{
|
||||||
TermBuilder,
|
TermBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
use mentat::errors::{
|
use mentat::errors::MentatError;
|
||||||
Error,
|
|
||||||
ErrorKind,
|
|
||||||
};
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref FOO_NAME: Keyword = {
|
static ref FOO_NAME: Keyword = {
|
||||||
|
@ -289,8 +286,8 @@ fn test_add_vocab() {
|
||||||
// Scoped borrow of `conn`.
|
// Scoped borrow of `conn`.
|
||||||
{
|
{
|
||||||
let mut in_progress = conn.begin_transaction(&mut sqlite).expect("begun successfully");
|
let mut in_progress = conn.begin_transaction(&mut sqlite).expect("begun successfully");
|
||||||
match in_progress.ensure_vocabulary(&foo_v1_malformed) {
|
match in_progress.ensure_vocabulary(&foo_v1_malformed).expect_err("expected vocabulary to fail").downcast() {
|
||||||
Result::Err(Error(ErrorKind::ConflictingAttributeDefinitions(vocab, version, attr, theirs, ours), _)) => {
|
Ok(MentatError::ConflictingAttributeDefinitions(vocab, version, attr, theirs, ours)) => {
|
||||||
assert_eq!(vocab.as_str(), ":org.mozilla/foo");
|
assert_eq!(vocab.as_str(), ":org.mozilla/foo");
|
||||||
assert_eq!(attr.as_str(), ":foo/baz");
|
assert_eq!(attr.as_str(), ":foo/baz");
|
||||||
assert_eq!(version, 1);
|
assert_eq!(version, 1);
|
||||||
|
|
Loading…
Reference in a new issue