This commit is contained in:
Greg Burd 2020-01-24 11:45:54 -05:00
parent 131398758b
commit 85f0497cf5
41 changed files with 3070 additions and 290 deletions

2447
798.patch Normal file

File diff suppressed because it is too large Load diff

View file

@ -68,7 +68,7 @@ use query::FromValue;
// TODO: Support tagged elements // TODO: Support tagged elements
// TODO: Support discard // TODO: Support discard
pub type ParseError = peg::error::ParseError<peg::str::LineCol>; pub type ParseErrorKind = peg::error::ParseError<peg::str::LineCol>;
peg::parser!(pub grammar parse() for str { peg::parser!(pub grammar parse() for str {

View file

@ -26,7 +26,7 @@ use chrono::{TimeZone, Utc};
use edn::{ use edn::{
parse, symbols, parse, symbols,
types::{Span, SpannedValue, Value, ValueAndSpan}, types::{Span, SpannedValue, Value, ValueAndSpan},
utils, ParseError, utils, ParseErrorKind,
}; };
// Helper for making wrapped keywords with a namespace. // Helper for making wrapped keywords with a namespace.

View file

@ -16,6 +16,12 @@ use std::collections::BTreeSet;
use std::error::Error; use std::error::Error;
use rusqlite; use rusqlite;
use failure::{
Backtrace,
Context,
Fail,
};
+use std::fmt;
use uuid; use uuid;
use edn; use edn;
@ -39,8 +45,51 @@ use serde_json;
pub type Result<T> = std::result::Result<T, MentatError>; pub type Result<T> = std::result::Result<T, MentatError>;
#[derive(Debug)]
pub struct MentatError(Box<Context<MentatErrorKind>>);
impl Fail for MentatError {
#[inline]
fn cause(&self) -> Option<&Fail> {
self.0.cause()
}
#[inline]
fn backtrace(&self) -> Option<&Backtrace> {
self.0.backtrace()
}
}
impl fmt::Display for MentatError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&*self.0, f)
}
}
impl MentatError {
#[inline]
pub fn kind(&self) -> &MentatErrorKind {
&*self.0.get_context()
}
}
impl From<MentatErrorKind> for MentatError {
#[inline]
fn from(kind: MentatErrorKind) -> MentatError {
MentatError(Box::new(Context::new(kind)))
}
}
impl From<Context<MentatErrorKind>> for MentatError {
#[inline]
fn from(inner: Context<MentatErrorKind>) -> MentatError {
MentatError(Box::new(inner))
}
}
#[derive(Debug, Fail)] #[derive(Debug, Fail)]
pub enum MentatError { pub enum MentatErrorKind {
#[fail(display = "bad uuid {}", _0)] #[fail(display = "bad uuid {}", _0)]
BadUuid(String), BadUuid(String),
@ -140,9 +189,67 @@ pub enum MentatError {
SerializationError(#[cause] serde_json::Error), SerializationError(#[cause] serde_json::Error),
} }
impl From<std::io::Error> for MentatErrorKind {
fn from(error: std::io::Error) -> MentatErrorKind {
MentatErrorKind::IoError(error)
}
}
impl From<rusqlite::Error> for MentatErrorKind {
fn from(error: rusqlite::Error) -> MentatErrorKind {
MentatErrorKind::RusqliteError(error.to_string())
}
}
impl From<edn::ParseError> for MentatErrorKind {
fn from(error: edn::ParseError) -> MentatErrorKind {
MentatErrorKind::EdnParseError(error)
}
}
impl From<mentat_db::DbError> for MentatErrorKind {
fn from(error: mentat_db::DbError) -> MentatErrorKind {
MentatErrorKind::DbError(error)
}
}
impl From<mentat_query_algebrizer::AlgebrizerError> for MentatErrorKind {
fn from(error: mentat_query_algebrizer::AlgebrizerError) -> MentatErrorKind {
MentatErrorKind::AlgebrizerError(error)
}
}
impl From<mentat_query_projector::ProjectorError> for MentatErrorKind {
fn from(error: mentat_query_projector::ProjectorError) -> MentatErrorKind {
MentatErrorKind::ProjectorError(error)
}
}
impl From<mentat_query_pull::PullError> for MentatErrorKind {
fn from(error: mentat_query_pull::PullError) -> MentatErrorKind {
MentatErrorKind::PullError(error)
}
}
impl From<mentat_sql::SQLError> for MentatErrorKind {
fn from(error: mentat_sql::SQLError) -> MentatErrorKind {
MentatErrorKind::SQLError(error)
}
}
#[cfg(feature = "syncable")]
impl From<mentat_tolstoy::TolstoyError> for MentatErrorKind {
fn from(error: mentat_tolstoy::TolstoyError) -> MentatErrorKind {
MentatErrorKind::TolstoyError(error)
}
}
// XXX reduce dupe if this isn't completely throwaway
impl From<std::io::Error> for MentatError { impl From<std::io::Error> for MentatError {
fn from(error: std::io::Error) -> Self { fn from(error: std::io::Error) -> Self {
MentatError::IoError(error) MentatError::from(error).into()
} }
} }
@ -152,76 +259,76 @@ impl From<rusqlite::Error> for MentatError {
Some(e) => e.to_string(), Some(e) => e.to_string(),
None => "".to_string(), None => "".to_string(),
}; };
MentatError::RusqliteError(error.to_string(), cause) MentatError::from(error).into()
} }
} }
impl From<uuid::Error> for MentatError { impl From<uuid::Error> for MentatError {
fn from(error: uuid::Error) -> Self { fn from(error: uuid::Error) -> Self {
MentatError::UuidError(error) MentatError::from(error).into()
} }
} }
impl From<edn::ParseError> for MentatError { impl From<edn::ParseError> for MentatError {
fn from(error: edn::ParseError) -> Self { fn from(error: edn::ParseError) -> Self {
MentatError::EdnParseError(error) MentatError:from(error).into()
} }
} }
impl From<DbError> for MentatError { impl From<DbError> for MentatError {
fn from(error: DbError) -> Self { fn from(error: DbError) -> Self {
MentatError::DbError(error) MentatError::from(error).into()
} }
} }
impl From<AlgebrizerError> for MentatError { impl From<AlgebrizerError> for MentatError {
fn from(error: AlgebrizerError) -> Self { fn from(error: AlgebrizerError) -> Self {
MentatError::AlgebrizerError(error) MentatError::from(error).into()
} }
} }
impl From<ProjectorError> for MentatError { impl From<ProjectorError> for MentatError {
fn from(error: ProjectorError) -> Self { fn from(error: ProjectorError) -> Self {
MentatError::ProjectorError(error) MentatError::from(error).into()
} }
} }
impl From<PullError> for MentatError { impl From<PullError> for MentatError {
fn from(error: PullError) -> Self { fn from(error: PullError) -> Self {
MentatError::PullError(error) MentatError::from(error).into()
} }
} }
impl From<SQLError> for MentatError { impl From<SQLError> for MentatError {
fn from(error: SQLError) -> Self { fn from(error: SQLError) -> Self {
MentatError::SQLError(error) MentatError::from(error).into()
} }
} }
#[cfg(feature = "syncable")] #[cfg(feature = "syncable")]
impl From<TolstoyError> for MentatError { impl From<TolstoyError> for MentatError {
fn from(error: TolstoyError) -> Self { fn from(error: TolstoyError) -> Self {
MentatError::TolstoyError(error) MentatError::from(error).into()
} }
} }
#[cfg(feature = "syncable")] #[cfg(feature = "syncable")]
impl From<serde_json::Error> for MentatError { impl From<serde_json::Error> for MentatError {
fn from(error: serde_json::Error) -> Self { fn from(error: serde_json::Error) -> Self {
MentatError::SerializationError(error) MentatError::from(error).into()
} }
} }
#[cfg(feature = "syncable")] #[cfg(feature = "syncable")]
impl From<hyper::Error> for MentatError { impl From<hyper::Error> for MentatError {
fn from(error: hyper::Error) -> Self { fn from(error: hyper::Error) -> Self {
MentatError::NetworkError(error) MentatError::from(error).into()
} }
} }
#[cfg(feature = "syncable")] #[cfg(feature = "syncable")]
impl From<http::uri::InvalidUri> for MentatError { impl From<http::uri::InvalidUri> for MentatError {
fn from(error: http::uri::InvalidUri) -> Self { fn from(error: http::uri::InvalidUri) -> Self {
MentatError::UriError(error) MentatError::from(error).into()
} }
} }

View file

@ -12,10 +12,60 @@ use std; // To refer to std::result::Result.
use core_traits::{ValueType, ValueTypeSet}; use core_traits::{ValueType, ValueTypeSet};
use edn::{query::PlainSymbol, ParseError}; use std::fmt;
use failure::{
Backtrace,
Context,
Fail,
};
use edn::{query::PlainSymbol, ParseErrorKind};
pub type Result<T> = std::result::Result<T, AlgebrizerError>; pub type Result<T> = std::result::Result<T, AlgebrizerError>;
#[derive(Debug)]
pub struct AlgebrizerError(Box<Context<AlgebrizerErrorKind>>);
impl Fail for AlgebrizerError {
#[inline]
fn cause(&self) -> Option<&dyn Fail> {
self.0.cause()
}
#[inline]
fn backtrace(&self) -> Option<&Backtrace> {
self.0.backtrace()
}
}
impl fmt::Display for AlgebrizerError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&*self.0, f)
}
}
impl AlgebrizerError {
#[inline]
pub fn kind(&self) -> &AlgebrizerErrorKind {
&*self.0.get_context()
}
}
impl From<AlgebrizerErrorKind> for AlgebrizerError {
#[inline]
fn from(kind: AlgebrizerErrorKind) -> AlgebrizerError {
AlgebrizerError(Box::new(Context::new(kind)))
}
}
impl From<Context<AlgebrizerErrorKind>> for AlgebrizerError {
#[inline]
fn from(inner: Context<AlgebrizerErrorKind>) -> AlgebrizerError {
AlgebrizerError(Box::new(inner))
}
}
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum BindingError { pub enum BindingError {
NoBoundVariable, NoBoundVariable,
@ -40,7 +90,7 @@ pub enum BindingError {
} }
#[derive(Clone, Debug, Eq, Fail, PartialEq)] #[derive(Clone, Debug, Eq, Fail, PartialEq)]
pub enum AlgebrizerError { pub enum AlgebrizerErrorKind {
#[fail(display = "{} var {} is duplicated", _0, _1)] #[fail(display = "{} var {} is duplicated", _0, _1)]
DuplicateVariableError(PlainSymbol, &'static str), DuplicateVariableError(PlainSymbol, &'static str),
@ -107,11 +157,11 @@ pub enum AlgebrizerError {
InvalidBinding(PlainSymbol, BindingError), InvalidBinding(PlainSymbol, BindingError),
#[fail(display = "{}", _0)] #[fail(display = "{}", _0)]
EdnParseError(#[cause] ParseError), EdnParseError(#[cause] ParseErrorKind),
} }
impl From<ParseError> for AlgebrizerError { impl From<ParseErrorKind> for AlgebrizerError {
fn from(error: ParseError) -> AlgebrizerError { fn from(error: ParseErrorKind) -> AlgebrizerError {
AlgebrizerError::EdnParseError(error) AlgebrizerError::from(error).into()
} }
} }

View file

@ -9,9 +9,6 @@
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
extern crate failure; extern crate failure;
#[macro_use]
extern crate failure_derive;
extern crate core_traits; extern crate core_traits;
extern crate edn; extern crate edn;

View file

@ -16,7 +16,7 @@ use edn::query::{FnArg, NonIntegerConstant, Variable};
use clauses::ConjoiningClauses; use clauses::ConjoiningClauses;
use query_algebrizer_traits::errors::{AlgebrizerError, Result}; use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
use types::EmptyBecause; use types::EmptyBecause;
@ -62,11 +62,11 @@ impl ValueTypes for FnArg {
&FnArg::Constant(NonIntegerConstant::BigInteger(_)) => { &FnArg::Constant(NonIntegerConstant::BigInteger(_)) => {
// Not yet implemented. // Not yet implemented.
bail!(AlgebrizerError::UnsupportedArgument) bail!(AlgebrizerErrorKind::UnsupportedArgument)
} }
// These don't make sense here. TODO: split FnArg into scalar and non-scalar… // These don't make sense here. TODO: split FnArg into scalar and non-scalar…
&FnArg::Vector(_) | &FnArg::SrcVar(_) => bail!(AlgebrizerError::UnsupportedArgument), &FnArg::Vector(_) | &FnArg::SrcVar(_) => bail!(AlgebrizerErrorKind::UnsupportedArgument),
// These are all straightforward. // These are all straightforward.
&FnArg::Constant(NonIntegerConstant::Boolean(_)) => { &FnArg::Constant(NonIntegerConstant::Boolean(_)) => {
@ -191,7 +191,7 @@ impl ConjoiningClauses {
FnArg::Variable(in_var) => { FnArg::Variable(in_var) => {
// TODO: technically you could ground an existing variable inside the query…. // TODO: technically you could ground an existing variable inside the query….
if !self.input_variables.contains(&in_var) { if !self.input_variables.contains(&in_var) {
bail!(AlgebrizerError::UnboundVariable((*in_var.0).clone())) bail!(AlgebrizerErrorKind::UnboundVariable((*in_var.0).clone()))
} }
match self.bound_value(&in_var) { match self.bound_value(&in_var) {
// The type is already known if it's a bound variable…. // The type is already known if it's a bound variable….
@ -200,7 +200,7 @@ impl ConjoiningClauses {
// The variable is present in `:in`, but it hasn't yet been provided. // The variable is present in `:in`, but it hasn't yet been provided.
// This is a restriction we will eventually relax: we don't yet have a way // This is a restriction we will eventually relax: we don't yet have a way
// to collect variables as part of a computed table or substitution. // to collect variables as part of a computed table or substitution.
bail!(AlgebrizerError::UnboundVariable((*in_var.0).clone())) bail!(AlgebrizerErrorKind::UnboundVariable((*in_var.0).clone()))
} }
} }
} }
@ -209,7 +209,7 @@ impl ConjoiningClauses {
FnArg::Constant(NonIntegerConstant::BigInteger(_)) => unimplemented!(), FnArg::Constant(NonIntegerConstant::BigInteger(_)) => unimplemented!(),
// These don't make sense here. // These don't make sense here.
FnArg::Vector(_) | FnArg::SrcVar(_) => bail!(AlgebrizerError::InvalidGroundConstant), FnArg::Vector(_) | FnArg::SrcVar(_) => bail!(AlgebrizerErrorKind::InvalidGroundConstant),
// These are all straightforward. // These are all straightforward.
FnArg::Constant(NonIntegerConstant::Boolean(x)) => { FnArg::Constant(NonIntegerConstant::Boolean(x)) => {

View file

@ -18,7 +18,7 @@ use edn::query::{Binding, FnArg, NonIntegerConstant, SrcVar, VariableOrPlacehold
use clauses::ConjoiningClauses; use clauses::ConjoiningClauses;
use query_algebrizer_traits::errors::{AlgebrizerError, BindingError, Result}; use query_algebrizer_traits::errors::{AlgebrizerErrorKind, BindingError, Result};
use types::{ use types::{
Column, ColumnConstraint, DatomsColumn, DatomsTable, EmptyBecause, FulltextColumn, Column, ColumnConstraint, DatomsColumn, DatomsTable, EmptyBecause, FulltextColumn,
@ -31,7 +31,7 @@ impl ConjoiningClauses {
#[allow(unused_variables)] #[allow(unused_variables)]
pub(crate) fn apply_fulltext(&mut self, known: Known, where_fn: WhereFn) -> Result<()> { pub(crate) fn apply_fulltext(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
if where_fn.args.len() != 3 { if where_fn.args.len() != 3 {
bail!(AlgebrizerError::InvalidNumberOfArguments( bail!(AlgebrizerErrorKind::InvalidNumberOfArguments(
where_fn.operator.clone(), where_fn.operator.clone(),
where_fn.args.len(), where_fn.args.len(),
3 3
@ -40,7 +40,7 @@ impl ConjoiningClauses {
if where_fn.binding.is_empty() { if where_fn.binding.is_empty() {
// The binding must introduce at least one bound variable. // The binding must introduce at least one bound variable.
bail!(AlgebrizerError::InvalidBinding( bail!(AlgebrizerErrorKind::InvalidBinding(
where_fn.operator.clone(), where_fn.operator.clone(),
BindingError::NoBoundVariable BindingError::NoBoundVariable
)); ));
@ -48,7 +48,7 @@ impl ConjoiningClauses {
if !where_fn.binding.is_valid() { if !where_fn.binding.is_valid() {
// The binding must not duplicate bound variables. // The binding must not duplicate bound variables.
bail!(AlgebrizerError::InvalidBinding( bail!(AlgebrizerErrorKind::InvalidBinding(
where_fn.operator.clone(), where_fn.operator.clone(),
BindingError::RepeatedBoundVariable BindingError::RepeatedBoundVariable
)); ));
@ -59,7 +59,7 @@ impl ConjoiningClauses {
Binding::BindRel(bindings) => { Binding::BindRel(bindings) => {
let bindings_count = bindings.len(); let bindings_count = bindings.len();
if bindings_count < 1 || bindings_count > 4 { if bindings_count < 1 || bindings_count > 4 {
bail!(AlgebrizerError::InvalidBinding( bail!(AlgebrizerErrorKind::InvalidBinding(
where_fn.operator.clone(), where_fn.operator.clone(),
BindingError::InvalidNumberOfBindings { BindingError::InvalidNumberOfBindings {
number: bindings.len(), number: bindings.len(),
@ -70,7 +70,7 @@ impl ConjoiningClauses {
bindings bindings
} }
Binding::BindScalar(_) | Binding::BindTuple(_) | Binding::BindColl(_) => { Binding::BindScalar(_) | Binding::BindTuple(_) | Binding::BindColl(_) => {
bail!(AlgebrizerError::InvalidBinding( bail!(AlgebrizerErrorKind::InvalidBinding(
where_fn.operator.clone(), where_fn.operator.clone(),
BindingError::ExpectedBindRel BindingError::ExpectedBindRel
)) ))
@ -93,7 +93,7 @@ impl ConjoiningClauses {
// TODO: process source variables. // TODO: process source variables.
match args.next().unwrap() { match args.next().unwrap() {
FnArg::SrcVar(SrcVar::DefaultSrc) => {} FnArg::SrcVar(SrcVar::DefaultSrc) => {}
_ => bail!(AlgebrizerError::InvalidArgument( _ => bail!(AlgebrizerErrorKind::InvalidArgument(
where_fn.operator.clone(), where_fn.operator.clone(),
"source variable", "source variable",
0 0
@ -116,12 +116,12 @@ impl ConjoiningClauses {
// TODO: allow non-constant attributes. // TODO: allow non-constant attributes.
match self.bound_value(&v) { match self.bound_value(&v) {
Some(TypedValue::Ref(entid)) => Some(entid), Some(TypedValue::Ref(entid)) => Some(entid),
Some(tv) => bail!(AlgebrizerError::InputTypeDisagreement( Some(tv) => bail!(AlgebrizerErrorKind::InputTypeDisagreement(
v.name().clone(), v.name().clone(),
ValueType::Ref, ValueType::Ref,
tv.value_type() tv.value_type()
)), )),
None => bail!(AlgebrizerError::UnboundVariable((*v.0).clone())), None => bail!(AlgebrizerErrorKind::UnboundVariable((*v.0).clone())),
} }
} }
_ => None, _ => None,
@ -130,7 +130,7 @@ impl ConjoiningClauses {
// An unknown ident, or an entity that isn't present in the store, or isn't a fulltext // An unknown ident, or an entity that isn't present in the store, or isn't a fulltext
// attribute, is likely enough to be a coding error that we choose to bail instead of // attribute, is likely enough to be a coding error that we choose to bail instead of
// marking the pattern as known-empty. // marking the pattern as known-empty.
let a = a.ok_or(AlgebrizerError::InvalidArgument( let a = a.ok_or(AlgebrizerErrorKind::InvalidArgument(
where_fn.operator.clone(), where_fn.operator.clone(),
"attribute", "attribute",
1, 1,
@ -139,7 +139,7 @@ impl ConjoiningClauses {
schema schema
.attribute_for_entid(a) .attribute_for_entid(a)
.cloned() .cloned()
.ok_or(AlgebrizerError::InvalidArgument( .ok_or(AlgebrizerErrorKind::InvalidArgument(
where_fn.operator.clone(), where_fn.operator.clone(),
"attribute", "attribute",
1, 1,
@ -190,7 +190,7 @@ impl ConjoiningClauses {
FnArg::Variable(in_var) => { FnArg::Variable(in_var) => {
match self.bound_value(&in_var) { match self.bound_value(&in_var) {
Some(t @ TypedValue::String(_)) => Either::Left(t), Some(t @ TypedValue::String(_)) => Either::Left(t),
Some(_) => bail!(AlgebrizerError::InvalidArgument( Some(_) => bail!(AlgebrizerErrorKind::InvalidArgument(
where_fn.operator.clone(), where_fn.operator.clone(),
"string", "string",
2 2
@ -199,7 +199,7 @@ impl ConjoiningClauses {
// Regardless of whether we'll be providing a string later, or the value // Regardless of whether we'll be providing a string later, or the value
// comes from a column, it must be a string. // comes from a column, it must be a string.
if self.known_type(&in_var) != Some(ValueType::String) { if self.known_type(&in_var) != Some(ValueType::String) {
bail!(AlgebrizerError::InvalidArgument( bail!(AlgebrizerErrorKind::InvalidArgument(
where_fn.operator.clone(), where_fn.operator.clone(),
"string", "string",
2 2
@ -209,7 +209,7 @@ impl ConjoiningClauses {
if self.input_variables.contains(&in_var) { if self.input_variables.contains(&in_var) {
// Sorry, we haven't implemented late binding. // Sorry, we haven't implemented late binding.
// TODO: implement this. // TODO: implement this.
bail!(AlgebrizerError::UnboundVariable((*in_var.0).clone())) bail!(AlgebrizerErrorKind::UnboundVariable((*in_var.0).clone()))
} else { } else {
// It must be bound earlier in the query. We already established that // It must be bound earlier in the query. We already established that
// it must be a string column. // it must be a string column.
@ -220,13 +220,13 @@ impl ConjoiningClauses {
{ {
Either::Right(binding) Either::Right(binding)
} else { } else {
bail!(AlgebrizerError::UnboundVariable((*in_var.0).clone())) bail!(AlgebrizerErrorKind::UnboundVariable((*in_var.0).clone()))
} }
} }
} }
} }
} }
_ => bail!(AlgebrizerError::InvalidArgument( _ => bail!(AlgebrizerErrorKind::InvalidArgument(
where_fn.operator.clone(), where_fn.operator.clone(),
"string", "string",
2 2
@ -298,7 +298,7 @@ impl ConjoiningClauses {
// We do not allow the score to be bound. // We do not allow the score to be bound.
if self.value_bindings.contains_key(var) || self.input_variables.contains(var) { if self.value_bindings.contains_key(var) || self.input_variables.contains(var) {
bail!(AlgebrizerError::InvalidBinding( bail!(AlgebrizerErrorKind::InvalidBinding(
var.name(), var.name(),
BindingError::UnexpectedBinding BindingError::UnexpectedBinding
)); ));

View file

@ -18,7 +18,7 @@ use clauses::{ConjoiningClauses, PushComputed};
use clauses::convert::ValueConversion; use clauses::convert::ValueConversion;
use query_algebrizer_traits::errors::{AlgebrizerError, BindingError, Result}; use query_algebrizer_traits::errors::{AlgebrizerErrorKind, BindingError, Result};
use types::{ComputedTable, EmptyBecause, SourceAlias, VariableColumn}; use types::{ComputedTable, EmptyBecause, SourceAlias, VariableColumn};
@ -117,7 +117,7 @@ impl ConjoiningClauses {
pub(crate) fn apply_ground(&mut self, known: Known, where_fn: WhereFn) -> Result<()> { pub(crate) fn apply_ground(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
if where_fn.args.len() != 1 { if where_fn.args.len() != 1 {
bail!(AlgebrizerError::InvalidNumberOfArguments( bail!(AlgebrizerErrorKind::InvalidNumberOfArguments(
where_fn.operator.clone(), where_fn.operator.clone(),
where_fn.args.len(), where_fn.args.len(),
1 1
@ -128,7 +128,7 @@ impl ConjoiningClauses {
if where_fn.binding.is_empty() { if where_fn.binding.is_empty() {
// The binding must introduce at least one bound variable. // The binding must introduce at least one bound variable.
bail!(AlgebrizerError::InvalidBinding( bail!(AlgebrizerErrorKind::InvalidBinding(
where_fn.operator.clone(), where_fn.operator.clone(),
BindingError::NoBoundVariable BindingError::NoBoundVariable
)); ));
@ -136,7 +136,7 @@ impl ConjoiningClauses {
if !where_fn.binding.is_valid() { if !where_fn.binding.is_valid() {
// The binding must not duplicate bound variables. // The binding must not duplicate bound variables.
bail!(AlgebrizerError::InvalidBinding( bail!(AlgebrizerErrorKind::InvalidBinding(
where_fn.operator.clone(), where_fn.operator.clone(),
BindingError::RepeatedBoundVariable BindingError::RepeatedBoundVariable
)); ));
@ -154,7 +154,7 @@ impl ConjoiningClauses {
// Just the same, but we bind more than one column at a time. // Just the same, but we bind more than one column at a time.
if children.len() != places.len() { if children.len() != places.len() {
// Number of arguments don't match the number of values. TODO: better error message. // Number of arguments don't match the number of values. TODO: better error message.
bail!(AlgebrizerError::GroundBindingsMismatch) bail!(AlgebrizerErrorKind::GroundBindingsMismatch)
} }
for (place, arg) in places.into_iter().zip(children.into_iter()) { for (place, arg) in places.into_iter().zip(children.into_iter()) {
self.apply_ground_place(schema, place, arg)? // TODO: short-circuit on impossible. self.apply_ground_place(schema, place, arg)? // TODO: short-circuit on impossible.
@ -168,7 +168,7 @@ impl ConjoiningClauses {
// are all in a single structure. That makes it substantially simpler! // are all in a single structure. That makes it substantially simpler!
(Binding::BindColl(var), FnArg::Vector(children)) => { (Binding::BindColl(var), FnArg::Vector(children)) => {
if children.is_empty() { if children.is_empty() {
bail!(AlgebrizerError::InvalidGroundConstant) bail!(AlgebrizerErrorKind::InvalidGroundConstant)
} }
// Turn a collection of arguments into a Vec of `TypedValue`s of the same type. // Turn a collection of arguments into a Vec of `TypedValue`s of the same type.
@ -188,7 +188,7 @@ impl ConjoiningClauses {
&& !accumulated_types.is_unit() && !accumulated_types.is_unit()
{ {
// Values not all of the same type. // Values not all of the same type.
Some(Err(AlgebrizerError::InvalidGroundConstant.into())) Some(Err(AlgebrizerErrorKind::InvalidGroundConstant.into()))
} else { } else {
Some(Ok(tv)) Some(Ok(tv))
} }
@ -219,7 +219,7 @@ impl ConjoiningClauses {
(Binding::BindRel(places), FnArg::Vector(rows)) => { (Binding::BindRel(places), FnArg::Vector(rows)) => {
if rows.is_empty() { if rows.is_empty() {
bail!(AlgebrizerError::InvalidGroundConstant) bail!(AlgebrizerErrorKind::InvalidGroundConstant)
} }
// Grab the known types to which these args must conform, and track // Grab the known types to which these args must conform, and track
@ -243,7 +243,7 @@ impl ConjoiningClauses {
if expected_width == 0 { if expected_width == 0 {
// They can't all be placeholders. // They can't all be placeholders.
bail!(AlgebrizerError::InvalidGroundConstant) bail!(AlgebrizerErrorKind::InvalidGroundConstant)
} }
// Accumulate values into `matrix` and types into `a_t_f_c`. // Accumulate values into `matrix` and types into `a_t_f_c`.
@ -259,7 +259,7 @@ impl ConjoiningClauses {
FnArg::Vector(cols) => { FnArg::Vector(cols) => {
// Make sure that every row is the same length. // Make sure that every row is the same length.
if cols.len() != full_width { if cols.len() != full_width {
bail!(AlgebrizerError::InvalidGroundConstant) bail!(AlgebrizerErrorKind::InvalidGroundConstant)
} }
// TODO: don't accumulate twice. // TODO: don't accumulate twice.
@ -297,12 +297,12 @@ impl ConjoiningClauses {
let inserted = acc.insert(val.value_type()); let inserted = acc.insert(val.value_type());
if inserted && !acc.is_unit() { if inserted && !acc.is_unit() {
// Heterogeneous types. // Heterogeneous types.
bail!(AlgebrizerError::InvalidGroundConstant) bail!(AlgebrizerErrorKind::InvalidGroundConstant)
} }
matrix.push(val); matrix.push(val);
} }
} }
_ => bail!(AlgebrizerError::InvalidGroundConstant), _ => bail!(AlgebrizerErrorKind::InvalidGroundConstant),
} }
} }
@ -329,7 +329,7 @@ impl ConjoiningClauses {
self.collect_named_bindings(schema, names, types, matrix); self.collect_named_bindings(schema, names, types, matrix);
Ok(()) Ok(())
} }
(_, _) => bail!(AlgebrizerError::InvalidGroundConstant), (_, _) => bail!(AlgebrizerErrorKind::InvalidGroundConstant),
} }
} }
} }

View file

@ -14,7 +14,7 @@ use core_traits::{TypedValue, ValueType};
use edn::query::Variable; use edn::query::Variable;
use query_algebrizer_traits::errors::{AlgebrizerError, Result}; use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
/// Define the inputs to a query. This is in two parts: a set of values known now, and a set of /// Define the inputs to a query. This is in two parts: a set of values known now, and a set of
/// types known now. /// types known now.
@ -69,7 +69,7 @@ impl QueryInputs {
let old = types.insert(var.clone(), t); let old = types.insert(var.clone(), t);
if let Some(old) = old { if let Some(old) = old {
if old != t { if old != t {
bail!(AlgebrizerError::InputTypeDisagreement(var.name(), old, t)); bail!(AlgebrizerErrorKind::InputTypeDisagreement(var.name(), old, t));
} }
} }
} }

View file

@ -24,7 +24,7 @@ use mentat_core::counter::RcCounter;
use edn::query::{Element, FindSpec, Keyword, PatternNonValuePlace, Pull, Variable, WhereClause}; use edn::query::{Element, FindSpec, Keyword, PatternNonValuePlace, Pull, Variable, WhereClause};
use query_algebrizer_traits::errors::{AlgebrizerError, Result}; use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
use types::{ use types::{
Column, ColumnConstraint, ColumnIntersection, ComputedTable, DatomsColumn, DatomsTable, Column, ColumnConstraint, ColumnIntersection, ComputedTable, DatomsColumn, DatomsTable,
@ -1071,7 +1071,7 @@ impl ConjoiningClauses {
let qa = self let qa = self
.extracted_types .extracted_types
.get(&var) .get(&var)
.ok_or_else(|| AlgebrizerError::UnboundVariable(var.name()))?; .ok_or_else(|| AlgebrizerErrorKind::UnboundVariable(var.name()))?;
self.wheres.add_intersection(ColumnConstraint::HasTypes { self.wheres.add_intersection(ColumnConstraint::HasTypes {
value: qa.0.clone(), value: qa.0.clone(),
value_types: types, value_types: types,

View file

@ -12,7 +12,7 @@ use edn::query::{ContainsVariables, NotJoin, UnifyVars};
use clauses::ConjoiningClauses; use clauses::ConjoiningClauses;
use query_algebrizer_traits::errors::{AlgebrizerError, Result}; use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
use types::{ColumnConstraint, ComputedTable}; use types::{ColumnConstraint, ComputedTable};
@ -35,7 +35,7 @@ impl ConjoiningClauses {
let col = self.column_bindings.get(&v).unwrap()[0].clone(); let col = self.column_bindings.get(&v).unwrap()[0].clone();
template.column_bindings.insert(v.clone(), vec![col]); template.column_bindings.insert(v.clone(), vec![col]);
} else { } else {
bail!(AlgebrizerError::UnboundVariable(v.name())); bail!(AlgebrizerErrorKind::UnboundVariable(v.name()));
} }
} }
@ -89,7 +89,7 @@ mod testing {
use clauses::{add_attribute, associate_ident, QueryInputs}; use clauses::{add_attribute, associate_ident, QueryInputs};
use query_algebrizer_traits::errors::AlgebrizerError; use query_algebrizer_traits::errors::AlgebrizerErrorKind;
use types::{ use types::{
ColumnAlternation, ColumnConstraint, ColumnConstraintOrAlternation, ColumnIntersection, ColumnAlternation, ColumnConstraint, ColumnConstraintOrAlternation, ColumnIntersection,
@ -714,7 +714,7 @@ mod testing {
let parsed = parse_find_string(query).expect("parse failed"); let parsed = parse_find_string(query).expect("parse failed");
let err = algebrize(known, parsed).expect_err("algebrization should have failed"); let err = algebrize(known, parsed).expect_err("algebrization should have failed");
match err { match err {
AlgebrizerError::UnboundVariable(var) => { AlgebrizerErrorKind::UnboundVariable(var) => {
assert_eq!(var, PlainSymbol("?x".to_string())); assert_eq!(var, PlainSymbol("?x".to_string()));
} }
x => panic!("expected Unbound Variable error, got {:?}", x), x => panic!("expected Unbound Variable error, got {:?}", x),

View file

@ -18,7 +18,7 @@ use clauses::ConjoiningClauses;
use clauses::convert::ValueTypes; use clauses::convert::ValueTypes;
use query_algebrizer_traits::errors::{AlgebrizerError, Result}; use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
use types::{ColumnConstraint, EmptyBecause, Inequality, QueryValue}; use types::{ColumnConstraint, EmptyBecause, Inequality, QueryValue};
@ -38,7 +38,7 @@ impl ConjoiningClauses {
if let Some(op) = Inequality::from_datalog_operator(predicate.operator.0.as_str()) { if let Some(op) = Inequality::from_datalog_operator(predicate.operator.0.as_str()) {
self.apply_inequality(known, op, predicate) self.apply_inequality(known, op, predicate)
} else { } else {
bail!(AlgebrizerError::UnknownFunction(predicate.operator.clone())) bail!(AlgebrizerErrorKind::UnknownFunction(predicate.operator.clone()))
} }
} }
@ -56,7 +56,7 @@ impl ConjoiningClauses {
Some(value_type) => { Some(value_type) => {
self.add_type_requirement(anno.variable.clone(), ValueTypeSet::of_one(value_type)) self.add_type_requirement(anno.variable.clone(), ValueTypeSet::of_one(value_type))
} }
None => bail!(AlgebrizerError::InvalidArgumentType( None => bail!(AlgebrizerErrorKind::InvalidArgumentType(
PlainSymbol::plain("type"), PlainSymbol::plain("type"),
ValueTypeSet::any(), ValueTypeSet::any(),
2 2
@ -76,7 +76,7 @@ impl ConjoiningClauses {
predicate: Predicate, predicate: Predicate,
) -> Result<()> { ) -> Result<()> {
if predicate.args.len() != 2 { if predicate.args.len() != 2 {
bail!(AlgebrizerError::InvalidNumberOfArguments( bail!(AlgebrizerErrorKind::InvalidNumberOfArguments(
predicate.operator.clone(), predicate.operator.clone(),
predicate.args.len(), predicate.args.len(),
2 2
@ -97,7 +97,7 @@ impl ConjoiningClauses {
.potential_types(known.schema, &left)? .potential_types(known.schema, &left)?
.intersection(&supported_types); .intersection(&supported_types);
if left_types.is_empty() { if left_types.is_empty() {
bail!(AlgebrizerError::InvalidArgumentType( bail!(AlgebrizerErrorKind::InvalidArgumentType(
predicate.operator.clone(), predicate.operator.clone(),
supported_types, supported_types,
0 0
@ -108,7 +108,7 @@ impl ConjoiningClauses {
.potential_types(known.schema, &right)? .potential_types(known.schema, &right)?
.intersection(&supported_types); .intersection(&supported_types);
if right_types.is_empty() { if right_types.is_empty() {
bail!(AlgebrizerError::InvalidArgumentType( bail!(AlgebrizerErrorKind::InvalidArgumentType(
predicate.operator.clone(), predicate.operator.clone(),
supported_types, supported_types,
1 1
@ -160,7 +160,7 @@ impl ConjoiningClauses {
left_v = self.resolve_ref_argument(known.schema, &predicate.operator, 0, left)?; left_v = self.resolve_ref_argument(known.schema, &predicate.operator, 0, left)?;
right_v = self.resolve_ref_argument(known.schema, &predicate.operator, 1, right)?; right_v = self.resolve_ref_argument(known.schema, &predicate.operator, 1, right)?;
} else { } else {
bail!(AlgebrizerError::InvalidArgumentType( bail!(AlgebrizerErrorKind::InvalidArgumentType(
predicate.operator.clone(), predicate.operator.clone(),
supported_types, supported_types,
0 0

View file

@ -16,7 +16,7 @@ use edn::query::{FnArg, NonIntegerConstant, PlainSymbol};
use clauses::ConjoiningClauses; use clauses::ConjoiningClauses;
use query_algebrizer_traits::errors::{AlgebrizerError, Result}; use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
use types::{EmptyBecause, QueryValue}; use types::{EmptyBecause, QueryValue};
@ -41,14 +41,14 @@ impl ConjoiningClauses {
if v.value_type().is_numeric() { if v.value_type().is_numeric() {
Ok(QueryValue::TypedValue(v)) Ok(QueryValue::TypedValue(v))
} else { } else {
bail!(AlgebrizerError::InputTypeDisagreement(var.name().clone(), ValueType::Long, v.value_type())) bail!(AlgebrizerErrorKind::InputTypeDisagreement(var.name().clone(), ValueType::Long, v.value_type()))
} }
} else { } else {
self.constrain_var_to_numeric(var.clone()); self.constrain_var_to_numeric(var.clone());
self.column_bindings self.column_bindings
.get(&var) .get(&var)
.and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone()))) .and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone())))
.ok_or_else(|| AlgebrizerError::UnboundVariable(var.name()).into()) .ok_or_else(|| AlgebrizerErrorKind::UnboundVariable(var.name()).into())
} }
}, },
// Can't be an entid. // Can't be an entid.
@ -62,7 +62,7 @@ impl ConjoiningClauses {
Constant(NonIntegerConstant::BigInteger(_)) | Constant(NonIntegerConstant::BigInteger(_)) |
Vector(_) => { Vector(_) => {
self.mark_known_empty(EmptyBecause::NonNumericArgument); self.mark_known_empty(EmptyBecause::NonNumericArgument);
bail!(AlgebrizerError::InvalidArgument(function.clone(), "numeric", position)) bail!(AlgebrizerErrorKind::InvalidArgument(function.clone(), "numeric", position))
}, },
Constant(NonIntegerConstant::Float(f)) => Ok(QueryValue::TypedValue(TypedValue::Double(f))), Constant(NonIntegerConstant::Float(f)) => Ok(QueryValue::TypedValue(TypedValue::Double(f))),
} }
@ -79,7 +79,7 @@ impl ConjoiningClauses {
match arg { match arg {
FnArg::Variable(var) => match self.bound_value(&var) { FnArg::Variable(var) => match self.bound_value(&var) {
Some(TypedValue::Instant(v)) => Ok(QueryValue::TypedValue(TypedValue::Instant(v))), Some(TypedValue::Instant(v)) => Ok(QueryValue::TypedValue(TypedValue::Instant(v))),
Some(v) => bail!(AlgebrizerError::InputTypeDisagreement( Some(v) => bail!(AlgebrizerErrorKind::InputTypeDisagreement(
var.name().clone(), var.name().clone(),
ValueType::Instant, ValueType::Instant,
v.value_type() v.value_type()
@ -89,7 +89,7 @@ impl ConjoiningClauses {
self.column_bindings self.column_bindings
.get(&var) .get(&var)
.and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone()))) .and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone())))
.ok_or_else(|| AlgebrizerError::UnboundVariable(var.name()).into()) .ok_or_else(|| AlgebrizerErrorKind::UnboundVariable(var.name()).into())
} }
}, },
Constant(NonIntegerConstant::Instant(v)) => { Constant(NonIntegerConstant::Instant(v)) => {
@ -107,7 +107,7 @@ impl ConjoiningClauses {
| Constant(NonIntegerConstant::BigInteger(_)) | Constant(NonIntegerConstant::BigInteger(_))
| Vector(_) => { | Vector(_) => {
self.mark_known_empty(EmptyBecause::NonInstantArgument); self.mark_known_empty(EmptyBecause::NonInstantArgument);
bail!(AlgebrizerError::InvalidArgumentType( bail!(AlgebrizerErrorKind::InvalidArgumentType(
function.clone(), function.clone(),
ValueType::Instant.into(), ValueType::Instant.into(),
position position
@ -136,14 +136,14 @@ impl ConjoiningClauses {
self.column_bindings self.column_bindings
.get(&var) .get(&var)
.and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone()))) .and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone())))
.ok_or_else(|| AlgebrizerError::UnboundVariable(var.name()).into()) .ok_or_else(|| AlgebrizerErrorKind::UnboundVariable(var.name()).into())
} }
} }
EntidOrInteger(i) => Ok(QueryValue::TypedValue(TypedValue::Ref(i))), EntidOrInteger(i) => Ok(QueryValue::TypedValue(TypedValue::Ref(i))),
IdentOrKeyword(i) => schema IdentOrKeyword(i) => schema
.get_entid(&i) .get_entid(&i)
.map(|known_entid| QueryValue::Entid(known_entid.into())) .map(|known_entid| QueryValue::Entid(known_entid.into()))
.ok_or_else(|| AlgebrizerError::UnrecognizedIdent(i.to_string()).into()), .ok_or_else(|| AlgebrizerErrorKind::UnrecognizedIdent(i.to_string()).into()),
Constant(NonIntegerConstant::Boolean(_)) Constant(NonIntegerConstant::Boolean(_))
| Constant(NonIntegerConstant::Float(_)) | Constant(NonIntegerConstant::Float(_))
| Constant(NonIntegerConstant::Text(_)) | Constant(NonIntegerConstant::Text(_))
@ -153,7 +153,7 @@ impl ConjoiningClauses {
| SrcVar(_) | SrcVar(_)
| Vector(_) => { | Vector(_) => {
self.mark_known_empty(EmptyBecause::NonEntityArgument); self.mark_known_empty(EmptyBecause::NonEntityArgument);
bail!(AlgebrizerError::InvalidArgumentType( bail!(AlgebrizerErrorKind::InvalidArgumentType(
function.clone(), function.clone(),
ValueType::Ref.into(), ValueType::Ref.into(),
position position
@ -188,7 +188,7 @@ impl ConjoiningClauses {
.column_bindings .column_bindings
.get(&var) .get(&var)
.and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone()))) .and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone())))
.ok_or_else(|| AlgebrizerError::UnboundVariable(var.name()).into()), .ok_or_else(|| AlgebrizerErrorKind::UnboundVariable(var.name()).into()),
}, },
EntidOrInteger(i) => Ok(QueryValue::PrimitiveLong(i)), EntidOrInteger(i) => Ok(QueryValue::PrimitiveLong(i)),
IdentOrKeyword(_) => unimplemented!(), // TODO IdentOrKeyword(_) => unimplemented!(), // TODO

View file

@ -14,7 +14,7 @@ use edn::query::{Binding, FnArg, SrcVar, VariableOrPlaceholder, WhereFn};
use clauses::ConjoiningClauses; use clauses::ConjoiningClauses;
use query_algebrizer_traits::errors::{AlgebrizerError, BindingError, Result}; use query_algebrizer_traits::errors::{AlgebrizerErrorKind, BindingError, Result};
use types::{ use types::{
Column, ColumnConstraint, DatomsTable, Inequality, QualifiedAlias, QueryValue, SourceAlias, Column, ColumnConstraint, DatomsTable, Inequality, QualifiedAlias, QueryValue, SourceAlias,
@ -40,7 +40,7 @@ impl ConjoiningClauses {
// transactions that impact one of the given attributes. // transactions that impact one of the given attributes.
pub(crate) fn apply_tx_ids(&mut self, known: Known, where_fn: WhereFn) -> Result<()> { pub(crate) fn apply_tx_ids(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
if where_fn.args.len() != 3 { if where_fn.args.len() != 3 {
bail!(AlgebrizerError::InvalidNumberOfArguments( bail!(AlgebrizerErrorKind::InvalidNumberOfArguments(
where_fn.operator.clone(), where_fn.operator.clone(),
where_fn.args.len(), where_fn.args.len(),
3 3
@ -49,7 +49,7 @@ impl ConjoiningClauses {
if where_fn.binding.is_empty() { if where_fn.binding.is_empty() {
// The binding must introduce at least one bound variable. // The binding must introduce at least one bound variable.
bail!(AlgebrizerError::InvalidBinding( bail!(AlgebrizerErrorKind::InvalidBinding(
where_fn.operator.clone(), where_fn.operator.clone(),
BindingError::NoBoundVariable BindingError::NoBoundVariable
)); ));
@ -57,7 +57,7 @@ impl ConjoiningClauses {
if !where_fn.binding.is_valid() { if !where_fn.binding.is_valid() {
// The binding must not duplicate bound variables. // The binding must not duplicate bound variables.
bail!(AlgebrizerError::InvalidBinding( bail!(AlgebrizerErrorKind::InvalidBinding(
where_fn.operator.clone(), where_fn.operator.clone(),
BindingError::RepeatedBoundVariable BindingError::RepeatedBoundVariable
)); ));
@ -68,7 +68,7 @@ impl ConjoiningClauses {
Binding::BindRel(bindings) => { Binding::BindRel(bindings) => {
let bindings_count = bindings.len(); let bindings_count = bindings.len();
if bindings_count != 1 { if bindings_count != 1 {
bail!(AlgebrizerError::InvalidBinding( bail!(AlgebrizerErrorKind::InvalidBinding(
where_fn.operator.clone(), where_fn.operator.clone(),
BindingError::InvalidNumberOfBindings { BindingError::InvalidNumberOfBindings {
number: bindings_count, number: bindings_count,
@ -83,7 +83,7 @@ impl ConjoiningClauses {
} }
Binding::BindColl(v) => v, Binding::BindColl(v) => v,
Binding::BindScalar(_) | Binding::BindTuple(_) => { Binding::BindScalar(_) | Binding::BindTuple(_) => {
bail!(AlgebrizerError::InvalidBinding( bail!(AlgebrizerErrorKind::InvalidBinding(
where_fn.operator.clone(), where_fn.operator.clone(),
BindingError::ExpectedBindRelOrBindColl BindingError::ExpectedBindRelOrBindColl
)) ))
@ -95,7 +95,7 @@ impl ConjoiningClauses {
// TODO: process source variables. // TODO: process source variables.
match args.next().unwrap() { match args.next().unwrap() {
FnArg::SrcVar(SrcVar::DefaultSrc) => {} FnArg::SrcVar(SrcVar::DefaultSrc) => {}
_ => bail!(AlgebrizerError::InvalidArgument( _ => bail!(AlgebrizerErrorKind::InvalidArgument(
where_fn.operator.clone(), where_fn.operator.clone(),
"source variable", "source variable",
0 0
@ -150,7 +150,7 @@ impl ConjoiningClauses {
pub(crate) fn apply_tx_data(&mut self, known: Known, where_fn: WhereFn) -> Result<()> { pub(crate) fn apply_tx_data(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
if where_fn.args.len() != 2 { if where_fn.args.len() != 2 {
bail!(AlgebrizerError::InvalidNumberOfArguments( bail!(AlgebrizerErrorKind::InvalidNumberOfArguments(
where_fn.operator.clone(), where_fn.operator.clone(),
where_fn.args.len(), where_fn.args.len(),
2 2
@ -159,7 +159,7 @@ impl ConjoiningClauses {
if where_fn.binding.is_empty() { if where_fn.binding.is_empty() {
// The binding must introduce at least one bound variable. // The binding must introduce at least one bound variable.
bail!(AlgebrizerError::InvalidBinding( bail!(AlgebrizerErrorKind::InvalidBinding(
where_fn.operator.clone(), where_fn.operator.clone(),
BindingError::NoBoundVariable BindingError::NoBoundVariable
)); ));
@ -167,7 +167,7 @@ impl ConjoiningClauses {
if !where_fn.binding.is_valid() { if !where_fn.binding.is_valid() {
// The binding must not duplicate bound variables. // The binding must not duplicate bound variables.
bail!(AlgebrizerError::InvalidBinding( bail!(AlgebrizerErrorKind::InvalidBinding(
where_fn.operator.clone(), where_fn.operator.clone(),
BindingError::RepeatedBoundVariable BindingError::RepeatedBoundVariable
)); ));
@ -178,7 +178,7 @@ impl ConjoiningClauses {
Binding::BindRel(bindings) => { Binding::BindRel(bindings) => {
let bindings_count = bindings.len(); let bindings_count = bindings.len();
if bindings_count < 1 || bindings_count > 5 { if bindings_count < 1 || bindings_count > 5 {
bail!(AlgebrizerError::InvalidBinding( bail!(AlgebrizerErrorKind::InvalidBinding(
where_fn.operator.clone(), where_fn.operator.clone(),
BindingError::InvalidNumberOfBindings { BindingError::InvalidNumberOfBindings {
number: bindings.len(), number: bindings.len(),
@ -189,7 +189,7 @@ impl ConjoiningClauses {
bindings bindings
} }
Binding::BindScalar(_) | Binding::BindTuple(_) | Binding::BindColl(_) => { Binding::BindScalar(_) | Binding::BindTuple(_) | Binding::BindColl(_) => {
bail!(AlgebrizerError::InvalidBinding( bail!(AlgebrizerErrorKind::InvalidBinding(
where_fn.operator.clone(), where_fn.operator.clone(),
BindingError::ExpectedBindRel BindingError::ExpectedBindRel
)) ))
@ -217,7 +217,7 @@ impl ConjoiningClauses {
// TODO: process source variables. // TODO: process source variables.
match args.next().unwrap() { match args.next().unwrap() {
FnArg::SrcVar(SrcVar::DefaultSrc) => {} FnArg::SrcVar(SrcVar::DefaultSrc) => {}
_ => bail!(AlgebrizerError::InvalidArgument( _ => bail!(AlgebrizerErrorKind::InvalidArgument(
where_fn.operator.clone(), where_fn.operator.clone(),
"source variable", "source variable",
0 0

View file

@ -12,7 +12,7 @@ use edn::query::WhereFn;
use clauses::ConjoiningClauses; use clauses::ConjoiningClauses;
use query_algebrizer_traits::errors::{AlgebrizerError, Result}; use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
use Known; use Known;
@ -32,7 +32,7 @@ impl ConjoiningClauses {
"ground" => self.apply_ground(known, where_fn), "ground" => self.apply_ground(known, where_fn),
"tx-data" => self.apply_tx_data(known, where_fn), "tx-data" => self.apply_tx_data(known, where_fn),
"tx-ids" => self.apply_tx_ids(known, where_fn), "tx-ids" => self.apply_tx_ids(known, where_fn),
_ => bail!(AlgebrizerError::UnknownFunction(where_fn.operator.clone())), _ => bail!(AlgebrizerErrorKind::UnknownFunction(where_fn.operator.clone())),
} }
} }
} }

View file

@ -32,7 +32,7 @@ use mentat_core::counter::RcCounter;
use edn::query::{Element, FindSpec, Limit, Order, ParsedQuery, SrcVar, Variable, WhereClause}; use edn::query::{Element, FindSpec, Limit, Order, ParsedQuery, SrcVar, Variable, WhereClause};
use query_algebrizer_traits::errors::{AlgebrizerError, Result}; use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
pub use clauses::{QueryInputs, VariableBindings}; pub use clauses::{QueryInputs, VariableBindings};
@ -229,7 +229,7 @@ fn validate_and_simplify_order(
// Fail if the var isn't bound by the query. // Fail if the var isn't bound by the query.
if !cc.column_bindings.contains_key(&var) { if !cc.column_bindings.contains_key(&var) {
bail!(AlgebrizerError::UnboundVariable(var.name())) bail!(AlgebrizerErrorKind::UnboundVariable(var.name()))
} }
// Otherwise, determine if we also need to order by type… // Otherwise, determine if we also need to order by type…
@ -263,7 +263,7 @@ fn simplify_limit(mut query: AlgebraicQuery) -> Result<AlgebraicQuery> {
Some(TypedValue::Long(n)) => { Some(TypedValue::Long(n)) => {
if n <= 0 { if n <= 0 {
// User-specified limits should always be natural numbers (> 0). // User-specified limits should always be natural numbers (> 0).
bail!(AlgebrizerError::InvalidLimit( bail!(AlgebrizerErrorKind::InvalidLimit(
n.to_string(), n.to_string(),
ValueType::Long ValueType::Long
)) ))
@ -273,7 +273,7 @@ fn simplify_limit(mut query: AlgebraicQuery) -> Result<AlgebraicQuery> {
} }
Some(val) => { Some(val) => {
// Same. // Same.
bail!(AlgebrizerError::InvalidLimit( bail!(AlgebrizerErrorKind::InvalidLimit(
format!("{:?}", val), format!("{:?}", val),
val.value_type() val.value_type()
)) ))
@ -375,7 +375,7 @@ impl FindQuery {
for var in parsed.in_vars.into_iter() { for var in parsed.in_vars.into_iter() {
if !set.insert(var.clone()) { if !set.insert(var.clone()) {
bail!(AlgebrizerError::DuplicateVariableError(var.name(), ":in")); bail!(AlgebrizerErrorKind::DuplicateVariableError(var.name(), ":in"));
} }
} }
@ -387,7 +387,7 @@ impl FindQuery {
for var in parsed.with.into_iter() { for var in parsed.with.into_iter() {
if !set.insert(var.clone()) { if !set.insert(var.clone()) {
bail!(AlgebrizerError::DuplicateVariableError(var.name(), ":with")); bail!(AlgebrizerErrorKind::DuplicateVariableError(var.name(), ":with"));
} }
} }
@ -397,7 +397,7 @@ impl FindQuery {
// Make sure that if we have `:limit ?x`, `?x` appears in `:in`. // Make sure that if we have `:limit ?x`, `?x` appears in `:in`.
if let Limit::Variable(ref v) = parsed.limit { if let Limit::Variable(ref v) = parsed.limit {
if !in_vars.contains(v) { if !in_vars.contains(v) {
bail!(AlgebrizerError::UnknownLimitVar(v.name())); bail!(AlgebrizerErrorKind::UnknownLimitVar(v.name()));
} }
} }

View file

@ -12,7 +12,7 @@ use std::collections::BTreeSet;
use edn::query::{ContainsVariables, NotJoin, OrJoin, UnifyVars, Variable}; use edn::query::{ContainsVariables, NotJoin, OrJoin, UnifyVars, Variable};
use query_algebrizer_traits::errors::{AlgebrizerError, Result}; use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
/// In an `or` expression, every mentioned var is considered 'free'. /// In an `or` expression, every mentioned var is considered 'free'.
/// In an `or-join` expression, every var in the var list is 'required'. /// In an `or-join` expression, every var in the var list is 'required'.
@ -47,7 +47,7 @@ pub(crate) fn validate_or_join(or_join: &OrJoin) -> Result<()> {
let template = clauses.next().unwrap().collect_mentioned_variables(); let template = clauses.next().unwrap().collect_mentioned_variables();
for clause in clauses { for clause in clauses {
if template != clause.collect_mentioned_variables() { if template != clause.collect_mentioned_variables() {
bail!(AlgebrizerError::NonMatchingVariablesInOrClause) bail!(AlgebrizerErrorKind::NonMatchingVariablesInOrClause)
} }
} }
Ok(()) Ok(())
@ -58,7 +58,7 @@ pub(crate) fn validate_or_join(or_join: &OrJoin) -> Result<()> {
let var_set: BTreeSet<Variable> = vars.iter().cloned().collect(); let var_set: BTreeSet<Variable> = vars.iter().cloned().collect();
for clause in &or_join.clauses { for clause in &or_join.clauses {
if !var_set.is_subset(&clause.collect_mentioned_variables()) { if !var_set.is_subset(&clause.collect_mentioned_variables()) {
bail!(AlgebrizerError::NonMatchingVariablesInOrClause) bail!(AlgebrizerErrorKind::NonMatchingVariablesInOrClause)
} }
} }
Ok(()) Ok(())
@ -74,7 +74,7 @@ pub(crate) fn validate_not_join(not_join: &NotJoin) -> Result<()> {
// The joined vars must each appear somewhere in the clause's mentioned variables. // The joined vars must each appear somewhere in the clause's mentioned variables.
let var_set: BTreeSet<Variable> = vars.iter().cloned().collect(); let var_set: BTreeSet<Variable> = vars.iter().cloned().collect();
if !var_set.is_subset(&not_join.collect_mentioned_variables()) { if !var_set.is_subset(&not_join.collect_mentioned_variables()) {
bail!(AlgebrizerError::NonMatchingVariablesInNotClause) bail!(AlgebrizerErrorKind::NonMatchingVariablesInNotClause)
} }
Ok(()) Ok(())
} }

View file

@ -24,7 +24,7 @@ use mentat_core::Schema;
use edn::query::{Keyword, PlainSymbol, Variable}; use edn::query::{Keyword, PlainSymbol, Variable};
use query_algebrizer_traits::errors::{AlgebrizerError, BindingError}; use query_algebrizer_traits::errors::{AlgebrizerErrorKind, BindingError};
use mentat_query_algebrizer::{ComputedTable, Known, QueryInputs}; use mentat_query_algebrizer::{ComputedTable, Known, QueryInputs};
@ -297,7 +297,7 @@ fn test_ground_coll_heterogeneous_types() {
let q = r#"[:find ?x :where [?x _ ?v] [(ground [false 8.5]) [?v ...]]]"#; let q = r#"[:find ?x :where [?x _ ?v] [(ground [false 8.5]) [?v ...]]]"#;
let schema = prepopulated_schema(); let schema = prepopulated_schema();
let known = Known::for_schema(&schema); let known = Known::for_schema(&schema);
assert_eq!(bails(known, &q), AlgebrizerError::InvalidGroundConstant); assert_eq!(bails(known, &q), AlgebrizerErrorKind::InvalidGroundConstant);
} }
#[test] #[test]
@ -305,7 +305,7 @@ fn test_ground_rel_heterogeneous_types() {
let q = r#"[:find ?x :where [?x _ ?v] [(ground [[false] [5]]) [[?v]]]]"#; let q = r#"[:find ?x :where [?x _ ?v] [(ground [[false] [5]]) [[?v]]]]"#;
let schema = prepopulated_schema(); let schema = prepopulated_schema();
let known = Known::for_schema(&schema); let known = Known::for_schema(&schema);
assert_eq!(bails(known, &q), AlgebrizerError::InvalidGroundConstant); assert_eq!(bails(known, &q), AlgebrizerErrorKind::InvalidGroundConstant);
} }
#[test] #[test]
@ -315,7 +315,7 @@ fn test_ground_tuple_duplicate_vars() {
let known = Known::for_schema(&schema); let known = Known::for_schema(&schema);
assert_eq!( assert_eq!(
bails(known, &q), bails(known, &q),
AlgebrizerError::InvalidBinding( AlgebrizerErrorKind::InvalidBinding(
PlainSymbol::plain("ground"), PlainSymbol::plain("ground"),
BindingError::RepeatedBoundVariable BindingError::RepeatedBoundVariable
) )
@ -329,7 +329,7 @@ fn test_ground_rel_duplicate_vars() {
let known = Known::for_schema(&schema); let known = Known::for_schema(&schema);
assert_eq!( assert_eq!(
bails(known, &q), bails(known, &q),
AlgebrizerError::InvalidBinding( AlgebrizerErrorKind::InvalidBinding(
PlainSymbol::plain("ground"), PlainSymbol::plain("ground"),
BindingError::RepeatedBoundVariable BindingError::RepeatedBoundVariable
) )
@ -343,7 +343,7 @@ fn test_ground_nonexistent_variable_invalid() {
let known = Known::for_schema(&schema); let known = Known::for_schema(&schema);
assert_eq!( assert_eq!(
bails(known, &q), bails(known, &q),
AlgebrizerError::UnboundVariable(PlainSymbol::plain("?v")) AlgebrizerErrorKind::UnboundVariable(PlainSymbol::plain("?v"))
); );
} }
@ -362,6 +362,6 @@ fn test_unbound_input_variable_invalid() {
assert_eq!( assert_eq!(
bails_with_inputs(known, &q, i), bails_with_inputs(known, &q, i),
AlgebrizerError::UnboundVariable(PlainSymbol::plain("?x")) AlgebrizerErrorKind::UnboundVariable(PlainSymbol::plain("?x"))
); );
} }

View file

@ -22,7 +22,7 @@ use mentat_core::{DateTime, Schema, Utc};
use edn::query::{Keyword, PlainSymbol, Variable}; use edn::query::{Keyword, PlainSymbol, Variable};
use query_algebrizer_traits::errors::AlgebrizerError; use query_algebrizer_traits::errors::AlgebrizerErrorKind;
use mentat_query_algebrizer::{EmptyBecause, Known, QueryInputs}; use mentat_query_algebrizer::{EmptyBecause, Known, QueryInputs};
@ -75,7 +75,7 @@ fn test_instant_predicates_require_instants() {
[(> ?t "2017-06-16T00:56:41.257Z")]]"#; [(> ?t "2017-06-16T00:56:41.257Z")]]"#;
assert_eq!( assert_eq!(
bails(known, query), bails(known, query),
AlgebrizerError::InvalidArgumentType( AlgebrizerErrorKind::InvalidArgumentType(
PlainSymbol::plain(">"), PlainSymbol::plain(">"),
ValueTypeSet::of_numeric_and_instant_types(), ValueTypeSet::of_numeric_and_instant_types(),
1 1
@ -88,7 +88,7 @@ fn test_instant_predicates_require_instants() {
[(> "2017-06-16T00:56:41.257Z", ?t)]]"#; [(> "2017-06-16T00:56:41.257Z", ?t)]]"#;
assert_eq!( assert_eq!(
bails(known, query), bails(known, query),
AlgebrizerError::InvalidArgumentType( AlgebrizerErrorKind::InvalidArgumentType(
PlainSymbol::plain(">"), PlainSymbol::plain(">"),
ValueTypeSet::of_numeric_and_instant_types(), ValueTypeSet::of_numeric_and_instant_types(),
0 0

View file

@ -16,7 +16,7 @@ use mentat_query_algebrizer::{ColumnName, ConjoiningClauses, VariableColumn};
use mentat_query_sql::{ColumnOrExpression, Expression, Name, ProjectedColumn}; use mentat_query_sql::{ColumnOrExpression, Expression, Name, ProjectedColumn};
use errors::{ProjectorError, Result}; use errors::{ProjectorErrorKind, Result};
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SimpleAggregationOp { pub enum SimpleAggregationOp {
@ -60,7 +60,7 @@ impl SimpleAggregationOp {
pub fn is_applicable_to_types(&self, possibilities: ValueTypeSet) -> Result<ValueType> { pub fn is_applicable_to_types(&self, possibilities: ValueTypeSet) -> Result<ValueType> {
use self::SimpleAggregationOp::*; use self::SimpleAggregationOp::*;
if possibilities.is_empty() { if possibilities.is_empty() {
bail!(ProjectorError::CannotProjectImpossibleBinding(*self)) bail!(ProjectorErrorKind::CannotProjectImpossibleBinding(*self))
} }
match self { match self {
@ -73,7 +73,7 @@ impl SimpleAggregationOp {
// The mean of a set of numeric values will always, for our purposes, be a double. // The mean of a set of numeric values will always, for our purposes, be a double.
Ok(ValueType::Double) Ok(ValueType::Double)
} else { } else {
bail!(ProjectorError::CannotApplyAggregateOperationToTypes( bail!(ProjectorErrorKind::CannotApplyAggregateOperationToTypes(
*self, *self,
possibilities possibilities
)) ))
@ -88,7 +88,7 @@ impl SimpleAggregationOp {
Ok(ValueType::Long) Ok(ValueType::Long)
} }
} else { } else {
bail!(ProjectorError::CannotApplyAggregateOperationToTypes( bail!(ProjectorErrorKind::CannotApplyAggregateOperationToTypes(
*self, *self,
possibilities possibilities
)) ))
@ -111,7 +111,7 @@ impl SimpleAggregationOp {
// These types are unordered. // These types are unordered.
Keyword | Ref | Uuid => { Keyword | Ref | Uuid => {
bail!(ProjectorError::CannotApplyAggregateOperationToTypes( bail!(ProjectorErrorKind::CannotApplyAggregateOperationToTypes(
*self, *self,
possibilities possibilities
)) ))
@ -129,7 +129,7 @@ impl SimpleAggregationOp {
Ok(ValueType::Long) Ok(ValueType::Long)
} }
} else { } else {
bail!(ProjectorError::CannotApplyAggregateOperationToTypes( bail!(ProjectorErrorKind::CannotApplyAggregateOperationToTypes(
*self, *self,
possibilities possibilities
)) ))

View file

@ -15,14 +15,60 @@ use rusqlite;
use core_traits::ValueTypeSet; use core_traits::ValueTypeSet;
use db_traits::errors::DbError; use db_traits::errors::DbError;
use edn::query::PlainSymbol; use edn::query::PlainSymbol;
use failure::{ Backtrace, Context, Fail, };
use std::fmt;
use query_pull_traits::errors::PullError; use query_pull_traits::errors::PullError;
use aggregates::SimpleAggregationOp; use aggregates::SimpleAggregationOp;
pub type Result<T> = std::result::Result<T, ProjectorError>; pub type Result<T> = std::result::Result<T, ProjectorError>;
#[derive(Debug)]
pub struct ProjectorError(Box<Context<ProjectorErrorKind>>);
impl Fail for ProjectorError {
#[inline]
fn cause(&self) -> Option<&Fail> {
self.0.cause()
}
#[inline]
fn backtrace(&self) -> Option<&Backtrace> {
self.0.backtrace()
}
}
impl fmt::Display for ProjectorError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&*self.0, f)
}
}
impl ProjectorError {
#[inline]
pub fn kind(&self) -> &ProjectorErrorKind {
&*self.0.get_context()
}
}
impl From<ProjectorErrorKind> for ProjectorError {
#[inline]
fn from(kind: ProjectorErrorKind) -> ProjectorError {
ProjectorError(Box::new(Context::new(kind)))
}
}
impl From<Context<ProjectorErrorKind>> for ProjectorError {
#[inline]
fn from(inner: Context<ProjectorErrorKind>) -> ProjectorError {
ProjectorError(Box::new(inner))
}
}
#[derive(Debug, Fail)] #[derive(Debug, Fail)]
pub enum ProjectorError { pub enum ProjectorErrorKind {
/// We're just not done yet. Message that the feature is recognized but not yet /// We're just not done yet. Message that the feature is recognized but not yet
/// implemented. /// implemented.
#[fail(display = "not yet implemented: {}", _0)] #[fail(display = "not yet implemented: {}", _0)]
@ -70,6 +116,24 @@ pub enum ProjectorError {
PullError(#[cause] PullError), PullError(#[cause] PullError),
} }
impl From<rusqlite::Error> for ProjectorErrorKind {
fn from(error: rusqlite::Error) -> ProjectorErrorKind {
ProjectorErrorKind::from(error).into()
}
}
impl From<mentat_db::DbError> for ProjectorErrorKind {
fn from(error: mentat_db::DbError) -> ProjectorErrorKind {
ProjectorErrorKind::from(error).into()
}
}
impl From<mentat_query_pull::PullError> for ProjectorErrorKind {
fn from(error: mentat_query_pull::PullError) -> ProjectorErrorKind {
ProjectorErrorKind::from(error).into()
}
}
impl From<rusqlite::Error> for ProjectorError { impl From<rusqlite::Error> for ProjectorError {
fn from(error: rusqlite::Error) -> ProjectorError { fn from(error: rusqlite::Error) -> ProjectorError {
ProjectorError::RusqliteError(error.to_string()) ProjectorError::RusqliteError(error.to_string())

View file

@ -101,9 +101,9 @@ fn test_the_without_max_or_min() {
// … when we look at the projection list, we cannot reconcile the types. // … when we look at the projection list, we cannot reconcile the types.
let projection = query_projection(&schema, &algebrized); let projection = query_projection(&schema, &algebrized);
assert!(projection.is_err()); assert!(projection.is_err());
use query_projector_traits::errors::ProjectorError; use query_projector_traits::errors::ProjectorErrorKind;
match projection.err().expect("expected failure") { match projection.err().expect("expected failure") {
ProjectorError::InvalidProjection(s) => { ProjectorErrorKind::InvalidProjection(s) => {
assert_eq!(s.as_str(), "Warning: used `the` without `min` or `max`."); assert_eq!(s.as_str(), "Warning: used `the` without `min` or `max`.");
} }
_ => panic!(), _ => panic!(),

View file

@ -10,7 +10,7 @@
use core_traits::Binding; use core_traits::Binding;
use query_projector_traits::errors::{ProjectorError, Result}; use query_projector_traits::errors::{ProjectorErrorKind, Result};
/// A `BindingTuple` is any type that can accommodate a Mentat tuple query result of fixed length. /// A `BindingTuple` is any type that can accommodate a Mentat tuple query result of fixed length.
/// ///
@ -27,7 +27,7 @@ impl BindingTuple for Vec<Binding> {
None => Ok(None), None => Ok(None),
Some(vec) => { Some(vec) => {
if expected != vec.len() { if expected != vec.len() {
Err(ProjectorError::UnexpectedResultsTupleLength( Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
expected, expected,
vec.len(), vec.len(),
)) ))
@ -43,13 +43,13 @@ impl BindingTuple for Vec<Binding> {
impl BindingTuple for (Binding,) { impl BindingTuple for (Binding,) {
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> { fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
if expected != 1 { if expected != 1 {
return Err(ProjectorError::UnexpectedResultsTupleLength(1, expected)); return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(1, expected));
} }
match vec { match vec {
None => Ok(None), None => Ok(None),
Some(vec) => { Some(vec) => {
if expected != vec.len() { if expected != vec.len() {
Err(ProjectorError::UnexpectedResultsTupleLength( Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
expected, expected,
vec.len(), vec.len(),
)) ))
@ -65,13 +65,13 @@ impl BindingTuple for (Binding,) {
impl BindingTuple for (Binding, Binding) { impl BindingTuple for (Binding, Binding) {
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> { fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
if expected != 2 { if expected != 2 {
return Err(ProjectorError::UnexpectedResultsTupleLength(2, expected)); return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(2, expected));
} }
match vec { match vec {
None => Ok(None), None => Ok(None),
Some(vec) => { Some(vec) => {
if expected != vec.len() { if expected != vec.len() {
Err(ProjectorError::UnexpectedResultsTupleLength( Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
expected, expected,
vec.len(), vec.len(),
)) ))
@ -87,13 +87,13 @@ impl BindingTuple for (Binding, Binding) {
impl BindingTuple for (Binding, Binding, Binding) { impl BindingTuple for (Binding, Binding, Binding) {
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> { fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
if expected != 3 { if expected != 3 {
return Err(ProjectorError::UnexpectedResultsTupleLength(3, expected)); return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(3, expected));
} }
match vec { match vec {
None => Ok(None), None => Ok(None),
Some(vec) => { Some(vec) => {
if expected != vec.len() { if expected != vec.len() {
Err(ProjectorError::UnexpectedResultsTupleLength( Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
expected, expected,
vec.len(), vec.len(),
)) ))
@ -113,13 +113,13 @@ impl BindingTuple for (Binding, Binding, Binding) {
impl BindingTuple for (Binding, Binding, Binding, Binding) { impl BindingTuple for (Binding, Binding, Binding, Binding) {
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> { fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
if expected != 4 { if expected != 4 {
return Err(ProjectorError::UnexpectedResultsTupleLength(4, expected)); return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(4, expected));
} }
match vec { match vec {
None => Ok(None), None => Ok(None),
Some(vec) => { Some(vec) => {
if expected != vec.len() { if expected != vec.len() {
Err(ProjectorError::UnexpectedResultsTupleLength( Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
expected, expected,
vec.len(), vec.len(),
)) ))
@ -140,13 +140,13 @@ impl BindingTuple for (Binding, Binding, Binding, Binding) {
impl BindingTuple for (Binding, Binding, Binding, Binding, Binding) { impl BindingTuple for (Binding, Binding, Binding, Binding, Binding) {
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> { fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
if expected != 5 { if expected != 5 {
return Err(ProjectorError::UnexpectedResultsTupleLength(5, expected)); return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(5, expected));
} }
match vec { match vec {
None => Ok(None), None => Ok(None),
Some(vec) => { Some(vec) => {
if expected != vec.len() { if expected != vec.len() {
Err(ProjectorError::UnexpectedResultsTupleLength( Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
expected, expected,
vec.len(), vec.len(),
)) ))
@ -170,13 +170,13 @@ impl BindingTuple for (Binding, Binding, Binding, Binding, Binding) {
impl BindingTuple for (Binding, Binding, Binding, Binding, Binding, Binding) { impl BindingTuple for (Binding, Binding, Binding, Binding, Binding, Binding) {
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> { fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
if expected != 6 { if expected != 6 {
return Err(ProjectorError::UnexpectedResultsTupleLength(6, expected)); return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(6, expected));
} }
match vec { match vec {
None => Ok(None), None => Ok(None),
Some(vec) => { Some(vec) => {
if expected != vec.len() { if expected != vec.len() {
Err(ProjectorError::UnexpectedResultsTupleLength( Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
expected, expected,
vec.len(), vec.len(),
)) ))

View file

@ -69,7 +69,7 @@ use projectors::{
pub use relresult::{RelResult, StructuredRelResult}; pub use relresult::{RelResult, StructuredRelResult};
use query_projector_traits::errors::{ProjectorError, Result}; use query_projector_traits::errors::{ProjectorErrorKind, Result};
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct QueryOutput { pub struct QueryOutput {
@ -275,43 +275,43 @@ impl QueryResults {
pub fn into_scalar(self) -> Result<Option<Binding>> { pub fn into_scalar(self) -> Result<Option<Binding>> {
match self { match self {
QueryResults::Scalar(o) => Ok(o), QueryResults::Scalar(o) => Ok(o),
QueryResults::Coll(_) => bail!(ProjectorError::UnexpectedResultsType("coll", "scalar")), QueryResults::Coll(_) => bail!(ProjectorErrorKind::UnexpectedResultsType("coll", "scalar")),
QueryResults::Tuple(_) => { QueryResults::Tuple(_) => {
bail!(ProjectorError::UnexpectedResultsType("tuple", "scalar")) bail!(ProjectorErrorKind::UnexpectedResultsType("tuple", "scalar"))
} }
QueryResults::Rel(_) => bail!(ProjectorError::UnexpectedResultsType("rel", "scalar")), QueryResults::Rel(_) => bail!(ProjectorErrorKind::UnexpectedResultsType("rel", "scalar")),
} }
} }
pub fn into_coll(self) -> Result<Vec<Binding>> { pub fn into_coll(self) -> Result<Vec<Binding>> {
match self { match self {
QueryResults::Scalar(_) => { QueryResults::Scalar(_) => {
bail!(ProjectorError::UnexpectedResultsType("scalar", "coll")) bail!(ProjectorErrorKind::UnexpectedResultsType("scalar", "coll"))
} }
QueryResults::Coll(c) => Ok(c), QueryResults::Coll(c) => Ok(c),
QueryResults::Tuple(_) => bail!(ProjectorError::UnexpectedResultsType("tuple", "coll")), QueryResults::Tuple(_) => bail!(ProjectorErrorKind::UnexpectedResultsType("tuple", "coll")),
QueryResults::Rel(_) => bail!(ProjectorError::UnexpectedResultsType("rel", "coll")), QueryResults::Rel(_) => bail!(ProjectorErrorKind::UnexpectedResultsType("rel", "coll")),
} }
} }
pub fn into_tuple(self) -> Result<Option<Vec<Binding>>> { pub fn into_tuple(self) -> Result<Option<Vec<Binding>>> {
match self { match self {
QueryResults::Scalar(_) => { QueryResults::Scalar(_) => {
bail!(ProjectorError::UnexpectedResultsType("scalar", "tuple")) bail!(ProjectorErrorKind::UnexpectedResultsType("scalar", "tuple"))
} }
QueryResults::Coll(_) => bail!(ProjectorError::UnexpectedResultsType("coll", "tuple")), QueryResults::Coll(_) => bail!(ProjectorErrorKind::UnexpectedResultsType("coll", "tuple")),
QueryResults::Tuple(t) => Ok(t), QueryResults::Tuple(t) => Ok(t),
QueryResults::Rel(_) => bail!(ProjectorError::UnexpectedResultsType("rel", "tuple")), QueryResults::Rel(_) => bail!(ProjectorErrorKind::UnexpectedResultsType("rel", "tuple")),
} }
} }
pub fn into_rel(self) -> Result<RelResult<Binding>> { pub fn into_rel(self) -> Result<RelResult<Binding>> {
match self { match self {
QueryResults::Scalar(_) => { QueryResults::Scalar(_) => {
bail!(ProjectorError::UnexpectedResultsType("scalar", "rel")) bail!(ProjectorErrorKind::UnexpectedResultsType("scalar", "rel"))
} }
QueryResults::Coll(_) => bail!(ProjectorError::UnexpectedResultsType("coll", "rel")), QueryResults::Coll(_) => bail!(ProjectorErrorKind::UnexpectedResultsType("coll", "rel")),
QueryResults::Tuple(_) => bail!(ProjectorError::UnexpectedResultsType("tuple", "rel")), QueryResults::Tuple(_) => bail!(ProjectorErrorKind::UnexpectedResultsType("tuple", "rel")),
QueryResults::Rel(r) => Ok(r), QueryResults::Rel(r) => Ok(r),
} }
} }
@ -526,7 +526,7 @@ fn test_into_tuple() {
); );
match query_output.clone().into_tuple() { match query_output.clone().into_tuple() {
Err(ProjectorError::UnexpectedResultsTupleLength(expected, got)) => { Err(ProjectorErrorKind::UnexpectedResultsTupleLength(expected, got)) => {
assert_eq!((expected, got), (3, 2)); assert_eq!((expected, got), (3, 2));
} }
// This forces the result type. // This forces the result type.
@ -548,7 +548,7 @@ fn test_into_tuple() {
} }
match query_output.clone().into_tuple() { match query_output.clone().into_tuple() {
Err(ProjectorError::UnexpectedResultsTupleLength(expected, got)) => { Err(ProjectorErrorKind::UnexpectedResultsTupleLength(expected, got)) => {
assert_eq!((expected, got), (3, 2)); assert_eq!((expected, got), (3, 2));
} }
// This forces the result type. // This forces the result type.

View file

@ -30,7 +30,7 @@ use query_projector_traits::aggregates::{
projected_column_for_simple_aggregate, SimpleAggregation, projected_column_for_simple_aggregate, SimpleAggregation,
}; };
use query_projector_traits::errors::{ProjectorError, Result}; use query_projector_traits::errors::{ProjectorErrorKind, Result};
use projectors::Projector; use projectors::Projector;
@ -98,14 +98,14 @@ fn candidate_type_column(
let type_name = VariableColumn::VariableTypeTag(var.clone()).column_name(); let type_name = VariableColumn::VariableTypeTag(var.clone()).column_name();
(ColumnOrExpression::Column(alias), type_name) (ColumnOrExpression::Column(alias), type_name)
}) })
.ok_or_else(|| ProjectorError::UnboundVariable(var.name()).into()) .ok_or_else(|| ProjectorErrorKind::UnboundVariable(var.name()).into())
} }
fn cc_column(cc: &ConjoiningClauses, var: &Variable) -> Result<QualifiedAlias> { fn cc_column(cc: &ConjoiningClauses, var: &Variable) -> Result<QualifiedAlias> {
cc.column_bindings cc.column_bindings
.get(var) .get(var)
.and_then(|cols| cols.get(0).cloned()) .and_then(|cols| cols.get(0).cloned())
.ok_or_else(|| ProjectorError::UnboundVariable(var.name()).into()) .ok_or_else(|| ProjectorErrorKind::UnboundVariable(var.name()).into())
} }
fn candidate_column(cc: &ConjoiningClauses, var: &Variable) -> Result<(ColumnOrExpression, Name)> { fn candidate_column(cc: &ConjoiningClauses, var: &Variable) -> Result<(ColumnOrExpression, Name)> {
@ -187,13 +187,13 @@ pub(crate) fn project_elements<'a, I: IntoIterator<Item = &'a Element>>(
match e { match e {
&Element::Variable(ref var) => { &Element::Variable(ref var) => {
if outer_variables.contains(var) { if outer_variables.contains(var) {
bail!(ProjectorError::InvalidProjection(format!( bail!(ProjectorErrorKind::InvalidProjection(format!(
"Duplicate variable {} in query.", "Duplicate variable {} in query.",
var var
))); )));
} }
if corresponded_variables.contains(var) { if corresponded_variables.contains(var) {
bail!(ProjectorError::InvalidProjection(format!( bail!(ProjectorErrorKind::InvalidProjection(format!(
"Can't project both {} and `(the {})` from a query.", "Can't project both {} and `(the {})` from a query.",
var, var var, var
))); )));
@ -201,13 +201,13 @@ pub(crate) fn project_elements<'a, I: IntoIterator<Item = &'a Element>>(
} }
&Element::Corresponding(ref var) => { &Element::Corresponding(ref var) => {
if outer_variables.contains(var) { if outer_variables.contains(var) {
bail!(ProjectorError::InvalidProjection(format!( bail!(ProjectorErrorKind::InvalidProjection(format!(
"Can't project both {} and `(the {})` from a query.", "Can't project both {} and `(the {})` from a query.",
var, var var, var
))); )));
} }
if corresponded_variables.contains(var) { if corresponded_variables.contains(var) {
bail!(ProjectorError::InvalidProjection(format!( bail!(ProjectorErrorKind::InvalidProjection(format!(
"`(the {})` appears twice in query.", "`(the {})` appears twice in query.",
var var
))); )));
@ -344,7 +344,7 @@ pub(crate) fn project_elements<'a, I: IntoIterator<Item = &'a Element>>(
i += 1; i += 1;
} else { } else {
// TODO: complex aggregates. // TODO: complex aggregates.
bail!(ProjectorError::NotYetImplemented( bail!(ProjectorErrorKind::NotYetImplemented(
"complex aggregates".into() "complex aggregates".into()
)); ));
} }
@ -355,7 +355,7 @@ pub(crate) fn project_elements<'a, I: IntoIterator<Item = &'a Element>>(
match (min_max_count, corresponded_variables.len()) { match (min_max_count, corresponded_variables.len()) {
(0, 0) | (_, 0) => {} (0, 0) | (_, 0) => {}
(0, _) => { (0, _) => {
bail!(ProjectorError::InvalidProjection( bail!(ProjectorErrorKind::InvalidProjection(
"Warning: used `the` without `min` or `max`.".to_string() "Warning: used `the` without `min` or `max`.".to_string()
)); ));
} }
@ -363,7 +363,7 @@ pub(crate) fn project_elements<'a, I: IntoIterator<Item = &'a Element>>(
// This is the success case! // This is the success case!
} }
(n, c) => { (n, c) => {
bail!(ProjectorError::AmbiguousAggregates(n, c)); bail!(ProjectorErrorKind::AmbiguousAggregates(n, c));
} }
} }
@ -466,7 +466,7 @@ pub(crate) fn project_elements<'a, I: IntoIterator<Item = &'a Element>>(
let type_name = VariableColumn::VariableTypeTag(var.clone()).column_name(); let type_name = VariableColumn::VariableTypeTag(var.clone()).column_name();
if !already_inner { if !already_inner {
let type_col = query.cc.extracted_types.get(&var).cloned().ok_or_else(|| { let type_col = query.cc.extracted_types.get(&var).cloned().ok_or_else(|| {
ProjectorError::NoTypeAvailableForVariable(var.name().clone()) ProjectorErrorKind::NoTypeAvailableForVariable(var.name().clone())
})?; })?;
inner_projection.push(ProjectedColumn( inner_projection.push(ProjectedColumn(
ColumnOrExpression::Column(type_col), ColumnOrExpression::Column(type_col),

View file

@ -12,10 +12,50 @@ use std; // To refer to std::result::Result.
use db_traits::errors::DbError; use db_traits::errors::DbError;
use failure::{ Backtrace, Context, Fail, };
use core_traits::Entid; use core_traits::Entid;
use std::fmt;
pub type Result<T> = std::result::Result<T, PullError>; pub type Result<T> = std::result::Result<T, PullError>;
#[derive(Debug)]
pub struct PullErrorKind(Box<Context<PullErrorKind>>);
impl Fail for PullError {
#[inline]
fn cause(&self) -> Option<&dyn Fail> {
self.0.cause()
}
#[inline]
fn backtrace(&self) -> Option<&Backtrace> {
self.0.backtrace()
}
}
impl fmt::Display for PullError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&*self.0, f)
}
}
impl PullError {
#[inline]
pub fn kind(&self) -> &PullErrorKind {
&*self.0.get_context()
}
}
impl From<PullErrorKind> for PullError {
#[inline]
fn from(kind: PullErrorKind) -> PullError {
PullErrorKind(Box::new(Context::new(kind)))
}
}
#[derive(Debug, Fail)] #[derive(Debug, Fail)]
pub enum PullError { pub enum PullError {
#[fail(display = "attribute {:?} has no name", _0)] #[fail(display = "attribute {:?} has no name", _0)]
@ -28,8 +68,13 @@ pub enum PullError {
DbError(#[cause] DbError), DbError(#[cause] DbError),
} }
impl From<DbError> for PullError { impl From<DbError> for PullErrorKind {
fn from(error: DbError) -> PullError { fn from(error: DbError) -> PullErrorKind {
PullError::DbError(error) PullErrorKind::DbError(error)
}
}
impl From<DbError> for PullError {
fn from(error: DbError) -> PullError {
PullErrorKind::from(error).into()
} }
} }

View file

@ -9,8 +9,6 @@
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
extern crate failure; extern crate failure;
#[macro_use]
extern crate failure_derive;
extern crate core_traits; extern crate core_traits;
extern crate db_traits; extern crate db_traits;

View file

@ -77,7 +77,7 @@ use mentat_db::cache;
use edn::query::{NamedPullAttribute, PullAttributeSpec, PullConcreteAttribute}; use edn::query::{NamedPullAttribute, PullAttributeSpec, PullConcreteAttribute};
use query_pull_traits::errors::{PullError, Result}; use query_pull_traits::errors::{PullErrorKind, Result};
type PullResults = BTreeMap<Entid, ValueRc<StructuredMap>>; type PullResults = BTreeMap<Entid, ValueRc<StructuredMap>>;
@ -149,7 +149,7 @@ impl Puller {
schema schema
.get_ident(*i) .get_ident(*i)
.map(|ident| ValueRc::new(ident.clone())) .map(|ident| ValueRc::new(ident.clone()))
.ok_or_else(|| PullError::UnnamedAttribute(*i)) .ok_or_else(|| PullErrorKind::UnnamedAttribute(*i))
}; };
let mut names: BTreeMap<Entid, ValueRc<Keyword>> = Default::default(); let mut names: BTreeMap<Entid, ValueRc<Keyword>> = Default::default();
@ -177,7 +177,7 @@ impl Puller {
&PullConcreteAttribute::Ident(ref i) if i.as_ref() == db_id.as_ref() => { &PullConcreteAttribute::Ident(ref i) if i.as_ref() == db_id.as_ref() => {
// We only allow :db/id once. // We only allow :db/id once.
if db_id_alias.is_some() { if db_id_alias.is_some() {
Err(PullError::RepeatedDbId)? Err(PullErrorKind::RepeatedDbId)?
} }
db_id_alias = Some(alias.unwrap_or_else(|| db_id.to_value_rc())); db_id_alias = Some(alias.unwrap_or_else(|| db_id.to_value_rc()));
} }

View file

@ -8,8 +8,54 @@
// 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.
use failure::{ Backtrace, Context, Fail, };
use std::fmt;
#[derive(Debug)]
pub struct SQLError(Box<Context<SQLErrorKind>>);
impl Fail for SQLError {
#[inline]
fn cause(&self) -> Option<&dyn Fail> {
self.0.cause()
}
#[inline]
fn backtrace(&self) -> Option<&Backtrace> {
self.0.backtrace()
}
}
impl fmt::Display for SQLError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&*self.0, f)
}
}
impl SQLError {
#[inline]
pub fn kind(&self) -> &SQLErrorKind {
&*self.0.get_context()
}
}
impl From<SQLErrorKind> for SQLError {
#[inline]
fn from(kind: SQLErrorKind) -> SQLError {
SQLError(Box::new(Context::new(kind)))
}
}
impl From<Context<SQLErrorKind>> for SQLError {
#[inline]
fn from(inner: Context<SQLErrorKind>) -> SQLError {
SQLError(Box::new(inner))
}
}
#[derive(Debug, Fail)] #[derive(Debug, Fail)]
pub enum SQLError { pub enum SQLErrorKind {
#[fail(display = "invalid parameter name: {}", _0)] #[fail(display = "invalid parameter name: {}", _0)]
InvalidParameterName(String), InvalidParameterName(String),

View file

@ -9,7 +9,5 @@
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
extern crate failure; extern crate failure;
#[macro_use]
extern crate failure_derive;
pub mod errors; pub mod errors;

View file

@ -18,14 +18,13 @@ extern crate mentat_core;
extern crate sql_traits; extern crate sql_traits;
use std::rc::Rc; use std::rc::Rc;
use std::collections::HashMap; use std::collections::HashMap;
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use core_traits::TypedValue; use core_traits::TypedValue;
use sql_traits::errors::{BuildQueryResult, SQLError}; use sql_traits::errors::{BuildQueryResult, SQLErrorKind};
use mentat_core::{ToMicros, ValueRc}; use mentat_core::{ToMicros, ValueRc};
@ -194,7 +193,7 @@ impl QueryBuilder for SQLiteQueryBuilder {
// Do some validation first. // Do some validation first.
// This is not free, but it's probably worth it for now. // This is not free, but it's probably worth it for now.
if !name.chars().all(|c| char::is_alphanumeric(c) || c == '_') { if !name.chars().all(|c| char::is_alphanumeric(c) || c == '_') {
return Err(SQLError::InvalidParameterName(name.to_string())); return Err(SQLErrorKind::InvalidParameterName(name.to_string()));
} }
if name.starts_with(self.arg_prefix.as_str()) if name.starts_with(self.arg_prefix.as_str())
@ -203,7 +202,7 @@ impl QueryBuilder for SQLiteQueryBuilder {
.skip(self.arg_prefix.len()) .skip(self.arg_prefix.len())
.all(char::is_numeric) .all(char::is_numeric)
{ {
return Err(SQLError::BindParamCouldBeGenerated(name.to_string())); return Err(SQLErrorKind::BindParamCouldBeGenerated(name.to_string()));
} }
self.push_sql("$"); self.push_sql("$");

View file

@ -36,7 +36,7 @@ use mentat_query_pull::{pull_attributes_for_entities, pull_attributes_for_entity
use mentat_transaction::{CacheAction, CacheDirection, InProgress, InProgressRead, Metadata}; use mentat_transaction::{CacheAction, CacheDirection, InProgress, InProgressRead, Metadata};
use public_traits::errors::{MentatError, Result}; use public_traits::errors::{MentatErrorKind, Result};
use mentat_transaction::query::{ use mentat_transaction::query::{
lookup_value_for_attribute, lookup_values_for_attribute, q_explain, q_once, q_prepare, lookup_value_for_attribute, lookup_values_for_attribute, q_explain, q_once, q_prepare,
@ -340,7 +340,7 @@ impl Conn {
attribute_entid = metadata attribute_entid = metadata
.schema .schema
.attribute_for_ident(&attribute) .attribute_for_ident(&attribute)
.ok_or_else(|| MentatError::UnknownAttribute(attribute.to_string()))? .ok_or_else(|| MentatErrorKind::UnknownAttribute(attribute.to_string()))?
.1 .1
.into(); .into();
} }
@ -404,12 +404,16 @@ mod tests {
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()) { match conn.transact(&mut sqlite, t.as_str()) {
Err(MentatError::DbError(e)) => { Err(e) => {
assert_eq!( match e.kind() {
e.kind(), &MentatErrorKind::DbError(ref e) => {
::db_traits::errors::DbErrorKind::UnallocatedEntid(next + 1) assert_eq!(e.kind(), ::mentat_db::DbErrorKind::UnallocatedEntid(next + 1));
); }
} x => {
panic!("expected db error, got {:?}", x);
}
}
},
x => panic!("expected db error, got {:?}", x), x => panic!("expected db error, got {:?}", x),
} }
@ -434,12 +438,15 @@ mod tests {
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()) { match conn.transact(&mut sqlite, t.as_str()) {
Err(MentatError::DbError(e)) => { Err(e) => {
// All this, despite this being the ID we were about to allocate! match e.kind() {
assert_eq!( &MentatErrorKind::DbError(ref e) => {
e.kind(), assert_eq!(e.kind(), ::mentat_db::DbErrorKind::UnallocatedEntid(next + 1));
::db_traits::errors::DbErrorKind::UnallocatedEntid(next) }
); x => {
panic!("expected db error, got {:?}", x);
}
}
} }
x => panic!("expected db error, got {:?}", x), x => panic!("expected db error, got {:?}", x),
} }
@ -642,8 +649,8 @@ 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.expect_err("expected transact to fail for bad edn") { match report.expect_err("expected transact to fail for bad edn").kind() {
MentatError::EdnParseError(_) => {} &MentatErrorKind::EdnParseError(_) => { }
x => panic!("expected EDN parse error, got {:?}", x), x => panic!("expected EDN parse error, got {:?}", x),
} }
@ -655,8 +662,8 @@ 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.expect_err("expected transact error") { match report.expect_err("expected transact error").kind() {
MentatError::EdnParseError(_) => {} &MentatErrorKind::EdnParseError(_) => { }
x => panic!("expected EDN parse error, got {:?}", x), x => panic!("expected EDN parse error, got {:?}", x),
} }
@ -668,12 +675,10 @@ mod tests {
// Bad transaction based on state of store: conflicting upsert. // Bad transaction based on state of store: conflicting upsert.
let report = conn.transact( let report = conn.transact(
&mut sqlite, &mut sqlite, "[[:db/add \"u\" :db/ident :a/keyword]
"[[:db/add \"u\" :db/ident :a/keyword] [:db/add \"u\" :db/ident :b/keyword]]");
[:db/add \"u\" :db/ident :b/keyword]]", match report.expect_err("expected transact error").kind() {
); &MentatErrorKind::DbError(ref e) => {
match report.expect_err("expected transact error") {
MentatError::DbError(e) => match e.kind() {
::db_traits::errors::DbErrorKind::SchemaConstraintViolation(_) => {} ::db_traits::errors::DbErrorKind::SchemaConstraintViolation(_) => {}
_ => panic!("expected SchemaConstraintViolation"), _ => panic!("expected SchemaConstraintViolation"),
}, },
@ -705,8 +710,8 @@ mod tests {
CacheDirection::Forward, CacheDirection::Forward,
CacheAction::Register, CacheAction::Register,
); );
match res.expect_err("expected cache to fail") { match res.expect_err("expected cache to fail").kind() {
MentatError::UnknownAttribute(msg) => assert_eq!(msg, ":foo/bat"), &MentatErrorKind::UnknownAttribute(ref msg) => assert_eq!(msg, ":foo/bat")
x => panic!("expected UnknownAttribute error, got {:?}", x), x => panic!("expected UnknownAttribute error, got {:?}", x),
} }
} }

View file

@ -82,7 +82,7 @@ macro_rules! kw {
} }
pub use public_traits::errors; pub use public_traits::errors;
pub use public_traits::errors::{MentatError, Result}; pub use public_traits::errors::{MentatErrorKind, Result};
pub use edn::{FromMicros, FromMillis, ParseError, ToMicros, ToMillis}; pub use edn::{FromMicros, FromMillis, ParseError, ToMicros, ToMillis};
pub use mentat_query_projector::BindingTuple; pub use mentat_query_projector::BindingTuple;

View file

@ -17,7 +17,7 @@ use mentat_core::{DateTime, Keyword, Utc};
use super::{HasSchema, QueryInputs, QueryOutput, Queryable, RelResult, Store, Variable}; use super::{HasSchema, QueryInputs, QueryOutput, Queryable, RelResult, Store, Variable};
use public_traits::errors::{MentatError, Result}; use public_traits::errors::{MentatErrorKind, Result};
pub struct QueryBuilder<'a> { pub struct QueryBuilder<'a> {
query: String, query: String,
@ -49,12 +49,8 @@ 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 let entid = self.store.conn().current_schema().get_entid(&value).ok_or_else(||
.store MentatError::from(MentatErrorKind::UnknownAttribute(value.to_string())))?;
.conn()
.current_schema()
.get_entid(&value)
.ok_or(MentatError::UnknownAttribute(value.to_string()))?;
self.values.insert( self.values.insert(
Variable::from_valid_name(var), Variable::from_valid_name(var),
TypedValue::Ref(entid.into()), TypedValue::Ref(entid.into()),

29
src/store.rs.rej Normal file
View file

@ -0,0 +1,29 @@
--- src/store.rs
+++ src/store.rs
@@ -85,7 +85,7 @@ impl Store {
pub fn open_empty(path: &str) -> Result<Store> {
if !path.is_empty() {
if Path::new(path).exists() {
- bail!(MentatError::PathAlreadyExists(path.to_string()));
+ bail!(MentatErrorKind::PathAlreadyExists(path.to_string()));
}
}
@@ -125,7 +125,7 @@ impl Store {
pub fn open_empty_with_key(path: &str, encryption_key: &str) -> Result<Store> {
if !path.is_empty() {
if Path::new(path).exists() {
- bail!(MentatError::PathAlreadyExists(path.to_string()));
+ bail!(MentatErrorKind::PathAlreadyExists(path.to_string()));
}
}
@@ -241,7 +241,7 @@ impl Pullable for Store {
#[cfg(feature = "syncable")]
impl Syncable for Store {
fn sync(&mut self, server_uri: &String, user_uuid: &String) -> Result<()> {
- let uuid = Uuid::parse_str(&user_uuid).map_err(|_| MentatError::BadUuid(user_uuid.clone()))?;
+ let uuid = Uuid::parse_str(&user_uuid).map_err(|_| MentatErrorKind::BadUuid(user_uuid.clone()))?;
Ok(Syncer::flow(&mut self.sqlite, server_uri, &uuid)?)
}
}

View file

@ -101,7 +101,7 @@ use super::{
CORE_SCHEMA_VERSION, CORE_SCHEMA_VERSION,
}; };
use super::errors::{MentatError, Result}; use super::errors::{MentatErrorKind, Result};
use mentat_transaction::{InProgress, Queryable}; use mentat_transaction::{InProgress, Queryable};
@ -325,17 +325,17 @@ where
{ {
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(|| MentatError::MissingCoreVocabulary(DB_SCHEMA_VERSION.clone()).into()) .ok_or_else(|| MentatErrorKind::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(|| MentatError::MissingCoreVocabulary(DB_SCHEMA_VERSION.clone()).into()) .ok_or_else(|| MentatErrorKind::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(|| MentatError::MissingCoreVocabulary(DB_SCHEMA_VERSION.clone()).into()) .ok_or_else(|| MentatErrorKind::MissingCoreVocabulary(DB_SCHEMA_VERSION.clone()).into())
.map(|(_, e)| e) .map(|(_, e)| e)
} }
} }
@ -548,7 +548,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!(MentatError::ConflictingAttributeDefinitions( bail!(MentatErrorKind::ConflictingAttributeDefinitions(
definition.name.to_string(), definition.name.to_string(),
definition.version, definition.version,
pair.0.to_string(), pair.0.to_string(),
@ -604,7 +604,7 @@ 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!(MentatError::UnexpectedCoreSchema( bail!(MentatErrorKind::UnexpectedCoreSchema(
CORE_SCHEMA_VERSION, CORE_SCHEMA_VERSION,
Some(core.version) Some(core.version)
)); ));
@ -613,7 +613,7 @@ pub trait VersionedStore: HasVocabularies + HasSchema {
// 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!(MentatError::UnexpectedCoreSchema(CORE_SCHEMA_VERSION, None)); bail!(MentatErrorKind::UnexpectedCoreSchema(CORE_SCHEMA_VERSION, None));
} }
Ok(()) Ok(())
} }
@ -694,7 +694,7 @@ impl<'a, 'c> VersionedStore for InProgress<'a, 'c> {
self.install_attributes_for(definition, attributes) self.install_attributes_for(definition, attributes)
} }
VocabularyCheck::PresentButTooNew { newer_version } => { VocabularyCheck::PresentButTooNew { newer_version } => {
Err(MentatError::ExistingVocabularyTooNew( Err(MentatErrorKind::ExistingVocabularyTooNew(
definition.name.to_string(), definition.name.to_string(),
newer_version.version, newer_version.version,
definition.version, definition.version,
@ -722,7 +722,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!(MentatError::ExistingVocabularyTooNew( bail!(MentatErrorKind::ExistingVocabularyTooNew(
definition.name.to_string(), definition.name.to_string(),
newer_version.version, newer_version.version,
definition.version definition.version
@ -914,7 +914,7 @@ where
attributes: attributes, attributes: attributes,
})) }))
} }
Some(_) => bail!(MentatError::InvalidVocabularyVersion), Some(_) => bail!(MentatErrorKind::InvalidVocabularyVersion),
} }
} else { } else {
Ok(None) Ok(None)

View file

@ -37,7 +37,7 @@ use mentat::query::q_uncached;
use mentat::conn::Conn; use mentat::conn::Conn;
use public_traits::errors::MentatError; use public_traits::errors::MentatErrorKind;
#[test] #[test]
fn test_rel() { fn test_rel() {
@ -243,10 +243,9 @@ fn test_unbound_inputs() {
inputs, inputs,
); );
match results.expect_err("expected unbound variables") { match results.expect_err("expected unbound variables").kind() {
MentatError::UnboundVariables(vars) => { &MentatErrorKind::UnboundVariables(ref vars) => {
assert_eq!(vars, vec!["?e".to_string()].into_iter().collect()); assert_eq!(vars, &vec!["?e".to_string()].into_iter().collect());
}
_ => panic!("Expected UnboundVariables variant."), _ => panic!("Expected UnboundVariables variant."),
} }
} }
@ -495,17 +494,15 @@ 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.expect_err("expected query to fail") { match r.expect_err("expected query to fail").kind() {
MentatError::AlgebrizerError( &MentatErrorKind::AlgebrizerError(ref e) => {
query_algebrizer_traits::errors::AlgebrizerError::InvalidArgument( if let &mentat_query_algebrizer::AlgebrizerErrorKind::InvalidArgument(PlainSymbol(ref s), ref ty, ref i) = e.kind() {
PlainSymbol(s), assert_eq!(*s, "fulltext");
ty, assert_eq!(*ty, "string");
i, assert_eq!(*i, 2);
), } else {
) => { panic!("Expected invalid argument");
assert_eq!(s, "fulltext"); }
assert_eq!(ty, "string");
assert_eq!(i, 2);
} }
_ => panic!("Expected query to fail."), _ => panic!("Expected query to fail."),
} }
@ -516,17 +513,15 @@ 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.expect_err("expected query to fail") { match r.expect_err("expected query to fail").kind() {
MentatError::AlgebrizerError( &MentatErrorKind::AlgebrizerError(ref e) => {
query_algebrizer_traits::errors::AlgebrizerError::InvalidArgument( if let &mentat_query_algebrizer::AlgebrizerErrorKind::InvalidArgument(PlainSymbol(ref s), ref ty, ref i) = e.kind() {
PlainSymbol(s), assert_eq!(*s, "fulltext");
ty, assert_eq!(*ty, "string");
i, assert_eq!(*i, 2);
), } else {
) => { panic!("expected AlgebrizerError::InvalidArgument");
assert_eq!(s, "fulltext"); }
assert_eq!(ty, "string");
assert_eq!(i, 2);
} }
_ => panic!("Expected query to fail."), _ => panic!("Expected query to fail."),
} }
@ -732,14 +727,15 @@ 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.expect_err("expected query to fail") { use mentat_query_projector::errors::ProjectorErrorKind;
MentatError::ProjectorError( match r.expect_err("expected query to fail").kind() {
::query_projector_traits::errors::ProjectorError::CannotApplyAggregateOperationToTypes( &MentatErrorKind::ProjectorError(ref e) => {
SimpleAggregationOp::Sum, if let &ProjectorErrorKind::CannotApplyAggregateOperationToTypes(
types, SimpleAggregationOp::Sum, ref types) = e.kind() {
), assert_eq!(types, &all_types);
) => { } else {
assert_eq!(types, all_types); panic!("Unexpected error type {:?}", e);
}
} }
e => panic!("Unexpected error type {:?}", e), e => panic!("Unexpected error type {:?}", e),
} }
@ -750,14 +746,14 @@ fn test_aggregates_type_handling() {
:where [_ _ ?v] [(type ?v :db.type/instant)]]"#, :where [_ _ ?v] [(type ?v :db.type/instant)]]"#,
None, None,
); );
match r.expect_err("expected query to fail") { match r.expect_err("expected query to fail").kind() {
MentatError::ProjectorError( &MentatErrorKind::ProjectorError(ref e) => {
::query_projector_traits::errors::ProjectorError::CannotApplyAggregateOperationToTypes( if let &ProjectorErrorKind::CannotApplyAggregateOperationToTypes(
SimpleAggregationOp::Sum, SimpleAggregationOp::Sum, ref types) = e.kind() {
types, assert_eq!(types, &ValueTypeSet::of_one(ValueType::Instant));
), } else {
) => { panic!("Unexpected error type {:?}", e);
assert_eq!(types, ValueTypeSet::of_one(ValueType::Instant)); }
} }
e => panic!("Unexpected error type {:?}", e), e => panic!("Unexpected error type {:?}", e),
} }
@ -1705,12 +1701,15 @@ fn test_aggregation_implicit_grouping() {
[?person :foo/name ?name]]"#, [?person :foo/name ?name]]"#,
None, None,
); );
match res.expect_err("expected query to fail") { use mentat_query_projector::errors::ProjectorErrorKind;
MentatError::ProjectorError( match res.expect_err("expected query to fail").kind() {
::query_projector_traits::errors::ProjectorError::AmbiguousAggregates(mmc, cc), &MentatErrorKind::ProjectorError(ref e) => {
) => { if let &ProjectorErrorKind::AmbiguousAggregates(mmc, cc) = e.kind() {
assert_eq!(mmc, 2); assert_eq!(mmc, 2);
assert_eq!(cc, 1); assert_eq!(cc, 1);
} else {
panic!("Unexpected error type {:?}.", e);
}
} }
e => { e => {
panic!("Unexpected error type {:?}.", e); panic!("Unexpected error type {:?}.", e);

View file

@ -40,7 +40,7 @@ use mentat::{
use mentat::entity_builder::{BuildTerms, TermBuilder}; use mentat::entity_builder::{BuildTerms, TermBuilder};
use mentat::errors::MentatError; use mentat::errors::MentatErrorKind;
lazy_static! { lazy_static! {
static ref FOO_NAME: Keyword = { kw!(:foo/name) }; static ref FOO_NAME: Keyword = { kw!(:foo/name) };
@ -327,12 +327,12 @@ fn test_add_vocab() {
.ensure_vocabulary(&foo_v1_malformed) .ensure_vocabulary(&foo_v1_malformed)
.expect_err("expected vocabulary to fail") .expect_err("expected vocabulary to fail")
{ {
MentatError::ConflictingAttributeDefinitions(vocab, version, attr, theirs, ours) => { &MentatErrorKind::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);
assert_eq!(&theirs, &baz); assert_eq!(theirs, &baz);
assert_eq!(&ours, &malformed_baz); assert_eq!(ours, &malformed_baz);
} }
_ => panic!(), _ => panic!(),
} }

View file

@ -376,7 +376,7 @@ impl Repl {
let next = match encryption_key { let next = match encryption_key {
#[cfg(not(feature = "sqlcipher"))] #[cfg(not(feature = "sqlcipher"))]
Some(_) => { Some(_) => {
return Err(::mentat::MentatError::RusqliteError( return Err(::mentat::MentatErrorKind::RusqliteError(
".open_encrypted requires the sqlcipher Mentat feature".into(), ".open_encrypted requires the sqlcipher Mentat feature".into(),
"".into(), "".into(),
)) ))

View file

@ -43,7 +43,7 @@ pub use mentat_query_projector::{
RelResult, RelResult,
}; };
use public_traits::errors::{MentatError, Result}; use public_traits::errors::{MentatErrorKind, Result};
pub type QueryExecutionResult = Result<QueryOutput>; pub type QueryExecutionResult = Result<QueryOutput>;
pub type PreparedResult<'sqlite> = Result<PreparedQuery<'sqlite>>; pub type PreparedResult<'sqlite> = Result<PreparedQuery<'sqlite>>;
@ -156,7 +156,7 @@ where
// 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!(MentatError::UnboundVariables( bail!(MentatErrorKind::UnboundVariables(
unbound.into_iter().map(|v| v.to_string()).collect() unbound.into_iter().map(|v| v.to_string()).collect()
)); ));
} }
@ -198,7 +198,7 @@ fn fetch_values<'sqlite>(
fn lookup_attribute(schema: &Schema, attribute: &Keyword) -> Result<KnownEntid> { fn lookup_attribute(schema: &Schema, attribute: &Keyword) -> Result<KnownEntid> {
schema schema
.get_entid(attribute) .get_entid(attribute)
.ok_or_else(|| MentatError::UnknownAttribute(attribute.name().into()).into()) .ok_or_else(|| MentatErrorKind::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.
@ -415,7 +415,7 @@ where
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!(MentatError::UnboundVariables( bail!(MentatErrorKind::UnboundVariables(
unbound.into_iter().map(|v| v.to_string()).collect() unbound.into_iter().map(|v| v.to_string()).collect()
)); ));
} }