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

View file

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

View file

@ -16,6 +16,12 @@ use std::collections::BTreeSet;
use std::error::Error;
use rusqlite;
use failure::{
Backtrace,
Context,
Fail,
};
+use std::fmt;
use uuid;
use edn;
@ -39,8 +45,51 @@ use serde_json;
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)]
pub enum MentatError {
pub enum MentatErrorKind {
#[fail(display = "bad uuid {}", _0)]
BadUuid(String),
@ -140,9 +189,67 @@ pub enum MentatError {
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 {
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(),
None => "".to_string(),
};
MentatError::RusqliteError(error.to_string(), cause)
MentatError::from(error).into()
}
}
impl From<uuid::Error> for MentatError {
fn from(error: uuid::Error) -> Self {
MentatError::UuidError(error)
MentatError::from(error).into()
}
}
impl From<edn::ParseError> for MentatError {
fn from(error: edn::ParseError) -> Self {
MentatError::EdnParseError(error)
MentatError:from(error).into()
}
}
impl From<DbError> for MentatError {
fn from(error: DbError) -> Self {
MentatError::DbError(error)
MentatError::from(error).into()
}
}
impl From<AlgebrizerError> for MentatError {
fn from(error: AlgebrizerError) -> Self {
MentatError::AlgebrizerError(error)
MentatError::from(error).into()
}
}
impl From<ProjectorError> for MentatError {
fn from(error: ProjectorError) -> Self {
MentatError::ProjectorError(error)
MentatError::from(error).into()
}
}
impl From<PullError> for MentatError {
fn from(error: PullError) -> Self {
MentatError::PullError(error)
MentatError::from(error).into()
}
}
impl From<SQLError> for MentatError {
fn from(error: SQLError) -> Self {
MentatError::SQLError(error)
MentatError::from(error).into()
}
}
#[cfg(feature = "syncable")]
impl From<TolstoyError> for MentatError {
fn from(error: TolstoyError) -> Self {
MentatError::TolstoyError(error)
MentatError::from(error).into()
}
}
#[cfg(feature = "syncable")]
impl From<serde_json::Error> for MentatError {
fn from(error: serde_json::Error) -> Self {
MentatError::SerializationError(error)
MentatError::from(error).into()
}
}
#[cfg(feature = "syncable")]
impl From<hyper::Error> for MentatError {
fn from(error: hyper::Error) -> Self {
MentatError::NetworkError(error)
MentatError::from(error).into()
}
}
#[cfg(feature = "syncable")]
impl From<http::uri::InvalidUri> for MentatError {
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 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>;
#[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)]
pub enum BindingError {
NoBoundVariable,
@ -40,7 +90,7 @@ pub enum BindingError {
}
#[derive(Clone, Debug, Eq, Fail, PartialEq)]
pub enum AlgebrizerError {
pub enum AlgebrizerErrorKind {
#[fail(display = "{} var {} is duplicated", _0, _1)]
DuplicateVariableError(PlainSymbol, &'static str),
@ -107,11 +157,11 @@ pub enum AlgebrizerError {
InvalidBinding(PlainSymbol, BindingError),
#[fail(display = "{}", _0)]
EdnParseError(#[cause] ParseError),
EdnParseError(#[cause] ParseErrorKind),
}
impl From<ParseError> for AlgebrizerError {
fn from(error: ParseError) -> AlgebrizerError {
AlgebrizerError::EdnParseError(error)
impl From<ParseErrorKind> for AlgebrizerError {
fn from(error: ParseErrorKind) -> AlgebrizerError {
AlgebrizerError::from(error).into()
}
}

View file

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

View file

@ -16,7 +16,7 @@ use edn::query::{FnArg, NonIntegerConstant, Variable};
use clauses::ConjoiningClauses;
use query_algebrizer_traits::errors::{AlgebrizerError, Result};
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
use types::EmptyBecause;
@ -62,11 +62,11 @@ impl ValueTypes for FnArg {
&FnArg::Constant(NonIntegerConstant::BigInteger(_)) => {
// Not yet implemented.
bail!(AlgebrizerError::UnsupportedArgument)
bail!(AlgebrizerErrorKind::UnsupportedArgument)
}
// 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.
&FnArg::Constant(NonIntegerConstant::Boolean(_)) => {
@ -191,7 +191,7 @@ impl ConjoiningClauses {
FnArg::Variable(in_var) => {
// TODO: technically you could ground an existing variable inside the query….
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) {
// 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.
// 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.
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!(),
// These don't make sense here.
FnArg::Vector(_) | FnArg::SrcVar(_) => bail!(AlgebrizerError::InvalidGroundConstant),
FnArg::Vector(_) | FnArg::SrcVar(_) => bail!(AlgebrizerErrorKind::InvalidGroundConstant),
// These are all straightforward.
FnArg::Constant(NonIntegerConstant::Boolean(x)) => {

View file

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

View file

@ -18,7 +18,7 @@ use clauses::{ConjoiningClauses, PushComputed};
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};
@ -117,7 +117,7 @@ impl ConjoiningClauses {
pub(crate) fn apply_ground(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
if where_fn.args.len() != 1 {
bail!(AlgebrizerError::InvalidNumberOfArguments(
bail!(AlgebrizerErrorKind::InvalidNumberOfArguments(
where_fn.operator.clone(),
where_fn.args.len(),
1
@ -128,7 +128,7 @@ impl ConjoiningClauses {
if where_fn.binding.is_empty() {
// The binding must introduce at least one bound variable.
bail!(AlgebrizerError::InvalidBinding(
bail!(AlgebrizerErrorKind::InvalidBinding(
where_fn.operator.clone(),
BindingError::NoBoundVariable
));
@ -136,7 +136,7 @@ impl ConjoiningClauses {
if !where_fn.binding.is_valid() {
// The binding must not duplicate bound variables.
bail!(AlgebrizerError::InvalidBinding(
bail!(AlgebrizerErrorKind::InvalidBinding(
where_fn.operator.clone(),
BindingError::RepeatedBoundVariable
));
@ -154,7 +154,7 @@ impl ConjoiningClauses {
// Just the same, but we bind more than one column at a time.
if children.len() != places.len() {
// 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()) {
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!
(Binding::BindColl(var), FnArg::Vector(children)) => {
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.
@ -188,7 +188,7 @@ impl ConjoiningClauses {
&& !accumulated_types.is_unit()
{
// Values not all of the same type.
Some(Err(AlgebrizerError::InvalidGroundConstant.into()))
Some(Err(AlgebrizerErrorKind::InvalidGroundConstant.into()))
} else {
Some(Ok(tv))
}
@ -219,7 +219,7 @@ impl ConjoiningClauses {
(Binding::BindRel(places), FnArg::Vector(rows)) => {
if rows.is_empty() {
bail!(AlgebrizerError::InvalidGroundConstant)
bail!(AlgebrizerErrorKind::InvalidGroundConstant)
}
// Grab the known types to which these args must conform, and track
@ -243,7 +243,7 @@ impl ConjoiningClauses {
if expected_width == 0 {
// They can't all be placeholders.
bail!(AlgebrizerError::InvalidGroundConstant)
bail!(AlgebrizerErrorKind::InvalidGroundConstant)
}
// Accumulate values into `matrix` and types into `a_t_f_c`.
@ -259,7 +259,7 @@ impl ConjoiningClauses {
FnArg::Vector(cols) => {
// Make sure that every row is the same length.
if cols.len() != full_width {
bail!(AlgebrizerError::InvalidGroundConstant)
bail!(AlgebrizerErrorKind::InvalidGroundConstant)
}
// TODO: don't accumulate twice.
@ -297,12 +297,12 @@ impl ConjoiningClauses {
let inserted = acc.insert(val.value_type());
if inserted && !acc.is_unit() {
// Heterogeneous types.
bail!(AlgebrizerError::InvalidGroundConstant)
bail!(AlgebrizerErrorKind::InvalidGroundConstant)
}
matrix.push(val);
}
}
_ => bail!(AlgebrizerError::InvalidGroundConstant),
_ => bail!(AlgebrizerErrorKind::InvalidGroundConstant),
}
}
@ -329,7 +329,7 @@ impl ConjoiningClauses {
self.collect_named_bindings(schema, names, types, matrix);
Ok(())
}
(_, _) => bail!(AlgebrizerError::InvalidGroundConstant),
(_, _) => bail!(AlgebrizerErrorKind::InvalidGroundConstant),
}
}
}

View file

@ -14,7 +14,7 @@ use core_traits::{TypedValue, ValueType};
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
/// types known now.
@ -69,7 +69,7 @@ impl QueryInputs {
let old = types.insert(var.clone(), t);
if let Some(old) = old {
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 query_algebrizer_traits::errors::{AlgebrizerError, Result};
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
use types::{
Column, ColumnConstraint, ColumnIntersection, ComputedTable, DatomsColumn, DatomsTable,
@ -1071,7 +1071,7 @@ impl ConjoiningClauses {
let qa = self
.extracted_types
.get(&var)
.ok_or_else(|| AlgebrizerError::UnboundVariable(var.name()))?;
.ok_or_else(|| AlgebrizerErrorKind::UnboundVariable(var.name()))?;
self.wheres.add_intersection(ColumnConstraint::HasTypes {
value: qa.0.clone(),
value_types: types,

View file

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

View file

@ -18,7 +18,7 @@ use clauses::ConjoiningClauses;
use clauses::convert::ValueTypes;
use query_algebrizer_traits::errors::{AlgebrizerError, Result};
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
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()) {
self.apply_inequality(known, op, predicate)
} else {
bail!(AlgebrizerError::UnknownFunction(predicate.operator.clone()))
bail!(AlgebrizerErrorKind::UnknownFunction(predicate.operator.clone()))
}
}
@ -56,7 +56,7 @@ impl ConjoiningClauses {
Some(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"),
ValueTypeSet::any(),
2
@ -76,7 +76,7 @@ impl ConjoiningClauses {
predicate: Predicate,
) -> Result<()> {
if predicate.args.len() != 2 {
bail!(AlgebrizerError::InvalidNumberOfArguments(
bail!(AlgebrizerErrorKind::InvalidNumberOfArguments(
predicate.operator.clone(),
predicate.args.len(),
2
@ -97,7 +97,7 @@ impl ConjoiningClauses {
.potential_types(known.schema, &left)?
.intersection(&supported_types);
if left_types.is_empty() {
bail!(AlgebrizerError::InvalidArgumentType(
bail!(AlgebrizerErrorKind::InvalidArgumentType(
predicate.operator.clone(),
supported_types,
0
@ -108,7 +108,7 @@ impl ConjoiningClauses {
.potential_types(known.schema, &right)?
.intersection(&supported_types);
if right_types.is_empty() {
bail!(AlgebrizerError::InvalidArgumentType(
bail!(AlgebrizerErrorKind::InvalidArgumentType(
predicate.operator.clone(),
supported_types,
1
@ -160,7 +160,7 @@ impl ConjoiningClauses {
left_v = self.resolve_ref_argument(known.schema, &predicate.operator, 0, left)?;
right_v = self.resolve_ref_argument(known.schema, &predicate.operator, 1, right)?;
} else {
bail!(AlgebrizerError::InvalidArgumentType(
bail!(AlgebrizerErrorKind::InvalidArgumentType(
predicate.operator.clone(),
supported_types,
0

View file

@ -16,7 +16,7 @@ use edn::query::{FnArg, NonIntegerConstant, PlainSymbol};
use clauses::ConjoiningClauses;
use query_algebrizer_traits::errors::{AlgebrizerError, Result};
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
use types::{EmptyBecause, QueryValue};
@ -41,14 +41,14 @@ impl ConjoiningClauses {
if v.value_type().is_numeric() {
Ok(QueryValue::TypedValue(v))
} else {
bail!(AlgebrizerError::InputTypeDisagreement(var.name().clone(), ValueType::Long, v.value_type()))
bail!(AlgebrizerErrorKind::InputTypeDisagreement(var.name().clone(), ValueType::Long, v.value_type()))
}
} else {
self.constrain_var_to_numeric(var.clone());
self.column_bindings
.get(&var)
.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.
@ -62,7 +62,7 @@ impl ConjoiningClauses {
Constant(NonIntegerConstant::BigInteger(_)) |
Vector(_) => {
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))),
}
@ -79,7 +79,7 @@ impl ConjoiningClauses {
match arg {
FnArg::Variable(var) => match self.bound_value(&var) {
Some(TypedValue::Instant(v)) => Ok(QueryValue::TypedValue(TypedValue::Instant(v))),
Some(v) => bail!(AlgebrizerError::InputTypeDisagreement(
Some(v) => bail!(AlgebrizerErrorKind::InputTypeDisagreement(
var.name().clone(),
ValueType::Instant,
v.value_type()
@ -89,7 +89,7 @@ impl ConjoiningClauses {
self.column_bindings
.get(&var)
.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)) => {
@ -107,7 +107,7 @@ impl ConjoiningClauses {
| Constant(NonIntegerConstant::BigInteger(_))
| Vector(_) => {
self.mark_known_empty(EmptyBecause::NonInstantArgument);
bail!(AlgebrizerError::InvalidArgumentType(
bail!(AlgebrizerErrorKind::InvalidArgumentType(
function.clone(),
ValueType::Instant.into(),
position
@ -136,14 +136,14 @@ impl ConjoiningClauses {
self.column_bindings
.get(&var)
.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))),
IdentOrKeyword(i) => schema
.get_entid(&i)
.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::Float(_))
| Constant(NonIntegerConstant::Text(_))
@ -153,7 +153,7 @@ impl ConjoiningClauses {
| SrcVar(_)
| Vector(_) => {
self.mark_known_empty(EmptyBecause::NonEntityArgument);
bail!(AlgebrizerError::InvalidArgumentType(
bail!(AlgebrizerErrorKind::InvalidArgumentType(
function.clone(),
ValueType::Ref.into(),
position
@ -188,7 +188,7 @@ impl ConjoiningClauses {
.column_bindings
.get(&var)
.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)),
IdentOrKeyword(_) => unimplemented!(), // TODO

View file

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

View file

@ -12,7 +12,7 @@ use edn::query::WhereFn;
use clauses::ConjoiningClauses;
use query_algebrizer_traits::errors::{AlgebrizerError, Result};
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
use Known;
@ -32,7 +32,7 @@ impl ConjoiningClauses {
"ground" => self.apply_ground(known, where_fn),
"tx-data" => self.apply_tx_data(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 query_algebrizer_traits::errors::{AlgebrizerError, Result};
use query_algebrizer_traits::errors::{AlgebrizerErrorKind, Result};
pub use clauses::{QueryInputs, VariableBindings};
@ -229,7 +229,7 @@ fn validate_and_simplify_order(
// Fail if the var isn't bound by the query.
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…
@ -263,7 +263,7 @@ fn simplify_limit(mut query: AlgebraicQuery) -> Result<AlgebraicQuery> {
Some(TypedValue::Long(n)) => {
if n <= 0 {
// User-specified limits should always be natural numbers (> 0).
bail!(AlgebrizerError::InvalidLimit(
bail!(AlgebrizerErrorKind::InvalidLimit(
n.to_string(),
ValueType::Long
))
@ -273,7 +273,7 @@ fn simplify_limit(mut query: AlgebraicQuery) -> Result<AlgebraicQuery> {
}
Some(val) => {
// Same.
bail!(AlgebrizerError::InvalidLimit(
bail!(AlgebrizerErrorKind::InvalidLimit(
format!("{:?}", val),
val.value_type()
))
@ -375,7 +375,7 @@ impl FindQuery {
for var in parsed.in_vars.into_iter() {
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() {
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`.
if let Limit::Variable(ref v) = parsed.limit {
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 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-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();
for clause in clauses {
if template != clause.collect_mentioned_variables() {
bail!(AlgebrizerError::NonMatchingVariablesInOrClause)
bail!(AlgebrizerErrorKind::NonMatchingVariablesInOrClause)
}
}
Ok(())
@ -58,7 +58,7 @@ pub(crate) fn validate_or_join(or_join: &OrJoin) -> Result<()> {
let var_set: BTreeSet<Variable> = vars.iter().cloned().collect();
for clause in &or_join.clauses {
if !var_set.is_subset(&clause.collect_mentioned_variables()) {
bail!(AlgebrizerError::NonMatchingVariablesInOrClause)
bail!(AlgebrizerErrorKind::NonMatchingVariablesInOrClause)
}
}
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.
let var_set: BTreeSet<Variable> = vars.iter().cloned().collect();
if !var_set.is_subset(&not_join.collect_mentioned_variables()) {
bail!(AlgebrizerError::NonMatchingVariablesInNotClause)
bail!(AlgebrizerErrorKind::NonMatchingVariablesInNotClause)
}
Ok(())
}

View file

@ -24,7 +24,7 @@ use mentat_core::Schema;
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};
@ -297,7 +297,7 @@ fn test_ground_coll_heterogeneous_types() {
let q = r#"[:find ?x :where [?x _ ?v] [(ground [false 8.5]) [?v ...]]]"#;
let schema = prepopulated_schema();
let known = Known::for_schema(&schema);
assert_eq!(bails(known, &q), AlgebrizerError::InvalidGroundConstant);
assert_eq!(bails(known, &q), AlgebrizerErrorKind::InvalidGroundConstant);
}
#[test]
@ -305,7 +305,7 @@ fn test_ground_rel_heterogeneous_types() {
let q = r#"[:find ?x :where [?x _ ?v] [(ground [[false] [5]]) [[?v]]]]"#;
let schema = prepopulated_schema();
let known = Known::for_schema(&schema);
assert_eq!(bails(known, &q), AlgebrizerError::InvalidGroundConstant);
assert_eq!(bails(known, &q), AlgebrizerErrorKind::InvalidGroundConstant);
}
#[test]
@ -315,7 +315,7 @@ fn test_ground_tuple_duplicate_vars() {
let known = Known::for_schema(&schema);
assert_eq!(
bails(known, &q),
AlgebrizerError::InvalidBinding(
AlgebrizerErrorKind::InvalidBinding(
PlainSymbol::plain("ground"),
BindingError::RepeatedBoundVariable
)
@ -329,7 +329,7 @@ fn test_ground_rel_duplicate_vars() {
let known = Known::for_schema(&schema);
assert_eq!(
bails(known, &q),
AlgebrizerError::InvalidBinding(
AlgebrizerErrorKind::InvalidBinding(
PlainSymbol::plain("ground"),
BindingError::RepeatedBoundVariable
)
@ -343,7 +343,7 @@ fn test_ground_nonexistent_variable_invalid() {
let known = Known::for_schema(&schema);
assert_eq!(
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!(
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 query_algebrizer_traits::errors::AlgebrizerError;
use query_algebrizer_traits::errors::AlgebrizerErrorKind;
use mentat_query_algebrizer::{EmptyBecause, Known, QueryInputs};
@ -75,7 +75,7 @@ fn test_instant_predicates_require_instants() {
[(> ?t "2017-06-16T00:56:41.257Z")]]"#;
assert_eq!(
bails(known, query),
AlgebrizerError::InvalidArgumentType(
AlgebrizerErrorKind::InvalidArgumentType(
PlainSymbol::plain(">"),
ValueTypeSet::of_numeric_and_instant_types(),
1
@ -88,7 +88,7 @@ fn test_instant_predicates_require_instants() {
[(> "2017-06-16T00:56:41.257Z", ?t)]]"#;
assert_eq!(
bails(known, query),
AlgebrizerError::InvalidArgumentType(
AlgebrizerErrorKind::InvalidArgumentType(
PlainSymbol::plain(">"),
ValueTypeSet::of_numeric_and_instant_types(),
0

View file

@ -16,7 +16,7 @@ use mentat_query_algebrizer::{ColumnName, ConjoiningClauses, VariableColumn};
use mentat_query_sql::{ColumnOrExpression, Expression, Name, ProjectedColumn};
use errors::{ProjectorError, Result};
use errors::{ProjectorErrorKind, Result};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SimpleAggregationOp {
@ -60,7 +60,7 @@ impl SimpleAggregationOp {
pub fn is_applicable_to_types(&self, possibilities: ValueTypeSet) -> Result<ValueType> {
use self::SimpleAggregationOp::*;
if possibilities.is_empty() {
bail!(ProjectorError::CannotProjectImpossibleBinding(*self))
bail!(ProjectorErrorKind::CannotProjectImpossibleBinding(*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.
Ok(ValueType::Double)
} else {
bail!(ProjectorError::CannotApplyAggregateOperationToTypes(
bail!(ProjectorErrorKind::CannotApplyAggregateOperationToTypes(
*self,
possibilities
))
@ -88,7 +88,7 @@ impl SimpleAggregationOp {
Ok(ValueType::Long)
}
} else {
bail!(ProjectorError::CannotApplyAggregateOperationToTypes(
bail!(ProjectorErrorKind::CannotApplyAggregateOperationToTypes(
*self,
possibilities
))
@ -111,7 +111,7 @@ impl SimpleAggregationOp {
// These types are unordered.
Keyword | Ref | Uuid => {
bail!(ProjectorError::CannotApplyAggregateOperationToTypes(
bail!(ProjectorErrorKind::CannotApplyAggregateOperationToTypes(
*self,
possibilities
))
@ -129,7 +129,7 @@ impl SimpleAggregationOp {
Ok(ValueType::Long)
}
} else {
bail!(ProjectorError::CannotApplyAggregateOperationToTypes(
bail!(ProjectorErrorKind::CannotApplyAggregateOperationToTypes(
*self,
possibilities
))

View file

@ -15,14 +15,60 @@ use rusqlite;
use core_traits::ValueTypeSet;
use db_traits::errors::DbError;
use edn::query::PlainSymbol;
use failure::{ Backtrace, Context, Fail, };
use std::fmt;
use query_pull_traits::errors::PullError;
use aggregates::SimpleAggregationOp;
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)]
pub enum ProjectorError {
pub enum ProjectorErrorKind {
/// We're just not done yet. Message that the feature is recognized but not yet
/// implemented.
#[fail(display = "not yet implemented: {}", _0)]
@ -70,6 +116,24 @@ pub enum ProjectorError {
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 {
fn from(error: rusqlite::Error) -> ProjectorError {
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.
let projection = query_projection(&schema, &algebrized);
assert!(projection.is_err());
use query_projector_traits::errors::ProjectorError;
use query_projector_traits::errors::ProjectorErrorKind;
match projection.err().expect("expected failure") {
ProjectorError::InvalidProjection(s) => {
ProjectorErrorKind::InvalidProjection(s) => {
assert_eq!(s.as_str(), "Warning: used `the` without `min` or `max`.");
}
_ => panic!(),

View file

@ -10,7 +10,7 @@
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.
///
@ -27,7 +27,7 @@ impl BindingTuple for Vec<Binding> {
None => Ok(None),
Some(vec) => {
if expected != vec.len() {
Err(ProjectorError::UnexpectedResultsTupleLength(
Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
expected,
vec.len(),
))
@ -43,13 +43,13 @@ impl BindingTuple for Vec<Binding> {
impl BindingTuple for (Binding,) {
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
if expected != 1 {
return Err(ProjectorError::UnexpectedResultsTupleLength(1, expected));
return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(1, expected));
}
match vec {
None => Ok(None),
Some(vec) => {
if expected != vec.len() {
Err(ProjectorError::UnexpectedResultsTupleLength(
Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
expected,
vec.len(),
))
@ -65,13 +65,13 @@ impl BindingTuple for (Binding,) {
impl BindingTuple for (Binding, Binding) {
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
if expected != 2 {
return Err(ProjectorError::UnexpectedResultsTupleLength(2, expected));
return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(2, expected));
}
match vec {
None => Ok(None),
Some(vec) => {
if expected != vec.len() {
Err(ProjectorError::UnexpectedResultsTupleLength(
Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
expected,
vec.len(),
))
@ -87,13 +87,13 @@ impl BindingTuple for (Binding, Binding) {
impl BindingTuple for (Binding, Binding, Binding) {
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
if expected != 3 {
return Err(ProjectorError::UnexpectedResultsTupleLength(3, expected));
return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(3, expected));
}
match vec {
None => Ok(None),
Some(vec) => {
if expected != vec.len() {
Err(ProjectorError::UnexpectedResultsTupleLength(
Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
expected,
vec.len(),
))
@ -113,13 +113,13 @@ impl BindingTuple for (Binding, Binding, Binding) {
impl BindingTuple for (Binding, Binding, Binding, Binding) {
fn from_binding_vec(expected: usize, vec: Option<Vec<Binding>>) -> Result<Option<Self>> {
if expected != 4 {
return Err(ProjectorError::UnexpectedResultsTupleLength(4, expected));
return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(4, expected));
}
match vec {
None => Ok(None),
Some(vec) => {
if expected != vec.len() {
Err(ProjectorError::UnexpectedResultsTupleLength(
Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
expected,
vec.len(),
))
@ -140,13 +140,13 @@ impl BindingTuple for (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>> {
if expected != 5 {
return Err(ProjectorError::UnexpectedResultsTupleLength(5, expected));
return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(5, expected));
}
match vec {
None => Ok(None),
Some(vec) => {
if expected != vec.len() {
Err(ProjectorError::UnexpectedResultsTupleLength(
Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
expected,
vec.len(),
))
@ -170,13 +170,13 @@ impl BindingTuple for (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>> {
if expected != 6 {
return Err(ProjectorError::UnexpectedResultsTupleLength(6, expected));
return Err(ProjectorErrorKind::UnexpectedResultsTupleLength(6, expected));
}
match vec {
None => Ok(None),
Some(vec) => {
if expected != vec.len() {
Err(ProjectorError::UnexpectedResultsTupleLength(
Err(ProjectorErrorKind::UnexpectedResultsTupleLength(
expected,
vec.len(),
))

View file

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

View file

@ -30,7 +30,7 @@ use query_projector_traits::aggregates::{
projected_column_for_simple_aggregate, SimpleAggregation,
};
use query_projector_traits::errors::{ProjectorError, Result};
use query_projector_traits::errors::{ProjectorErrorKind, Result};
use projectors::Projector;
@ -98,14 +98,14 @@ fn candidate_type_column(
let type_name = VariableColumn::VariableTypeTag(var.clone()).column_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> {
cc.column_bindings
.get(var)
.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)> {
@ -187,13 +187,13 @@ pub(crate) fn project_elements<'a, I: IntoIterator<Item = &'a Element>>(
match e {
&Element::Variable(ref var) => {
if outer_variables.contains(var) {
bail!(ProjectorError::InvalidProjection(format!(
bail!(ProjectorErrorKind::InvalidProjection(format!(
"Duplicate variable {} in query.",
var
)));
}
if corresponded_variables.contains(var) {
bail!(ProjectorError::InvalidProjection(format!(
bail!(ProjectorErrorKind::InvalidProjection(format!(
"Can't project both {} and `(the {})` from a query.",
var, var
)));
@ -201,13 +201,13 @@ pub(crate) fn project_elements<'a, I: IntoIterator<Item = &'a Element>>(
}
&Element::Corresponding(ref var) => {
if outer_variables.contains(var) {
bail!(ProjectorError::InvalidProjection(format!(
bail!(ProjectorErrorKind::InvalidProjection(format!(
"Can't project both {} and `(the {})` from a query.",
var, var
)));
}
if corresponded_variables.contains(var) {
bail!(ProjectorError::InvalidProjection(format!(
bail!(ProjectorErrorKind::InvalidProjection(format!(
"`(the {})` appears twice in query.",
var
)));
@ -344,7 +344,7 @@ pub(crate) fn project_elements<'a, I: IntoIterator<Item = &'a Element>>(
i += 1;
} else {
// TODO: complex aggregates.
bail!(ProjectorError::NotYetImplemented(
bail!(ProjectorErrorKind::NotYetImplemented(
"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()) {
(0, 0) | (_, 0) => {}
(0, _) => {
bail!(ProjectorError::InvalidProjection(
bail!(ProjectorErrorKind::InvalidProjection(
"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!
}
(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();
if !already_inner {
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(
ColumnOrExpression::Column(type_col),

View file

@ -12,10 +12,50 @@ use std; // To refer to std::result::Result.
use db_traits::errors::DbError;
use failure::{ Backtrace, Context, Fail, };
use core_traits::Entid;
use std::fmt;
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)]
pub enum PullError {
#[fail(display = "attribute {:?} has no name", _0)]
@ -28,8 +68,13 @@ pub enum PullError {
DbError(#[cause] DbError),
}
impl From<DbError> for PullError {
fn from(error: DbError) -> PullError {
PullError::DbError(error)
impl From<DbError> for PullErrorKind {
fn from(error: DbError) -> PullErrorKind {
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.
extern crate failure;
#[macro_use]
extern crate failure_derive;
extern crate core_traits;
extern crate db_traits;

View file

@ -77,7 +77,7 @@ use mentat_db::cache;
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>>;
@ -149,7 +149,7 @@ impl Puller {
schema
.get_ident(*i)
.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();
@ -177,7 +177,7 @@ impl Puller {
&PullConcreteAttribute::Ident(ref i) if i.as_ref() == db_id.as_ref() => {
// We only allow :db/id once.
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()));
}

View file

@ -8,8 +8,54 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// 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)]
pub enum SQLError {
pub enum SQLErrorKind {
#[fail(display = "invalid parameter name: {}", _0)]
InvalidParameterName(String),

View file

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

View file

@ -18,14 +18,13 @@ extern crate mentat_core;
extern crate sql_traits;
use std::rc::Rc;
use std::collections::HashMap;
use ordered_float::OrderedFloat;
use core_traits::TypedValue;
use sql_traits::errors::{BuildQueryResult, SQLError};
use sql_traits::errors::{BuildQueryResult, SQLErrorKind};
use mentat_core::{ToMicros, ValueRc};
@ -194,7 +193,7 @@ impl QueryBuilder for SQLiteQueryBuilder {
// Do some validation first.
// This is not free, but it's probably worth it for now.
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())
@ -203,7 +202,7 @@ impl QueryBuilder for SQLiteQueryBuilder {
.skip(self.arg_prefix.len())
.all(char::is_numeric)
{
return Err(SQLError::BindParamCouldBeGenerated(name.to_string()));
return Err(SQLErrorKind::BindParamCouldBeGenerated(name.to_string()));
}
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 public_traits::errors::{MentatError, Result};
use public_traits::errors::{MentatErrorKind, Result};
use mentat_transaction::query::{
lookup_value_for_attribute, lookup_values_for_attribute, q_explain, q_once, q_prepare,
@ -340,7 +340,7 @@ impl Conn {
attribute_entid = metadata
.schema
.attribute_for_ident(&attribute)
.ok_or_else(|| MentatError::UnknownAttribute(attribute.to_string()))?
.ok_or_else(|| MentatErrorKind::UnknownAttribute(attribute.to_string()))?
.1
.into();
}
@ -404,12 +404,16 @@ mod tests {
let t = format!("[[:db/add {} :db.schema/attribute \"tempid\"]]", next + 1);
match conn.transact(&mut sqlite, t.as_str()) {
Err(MentatError::DbError(e)) => {
assert_eq!(
e.kind(),
::db_traits::errors::DbErrorKind::UnallocatedEntid(next + 1)
);
}
Err(e) => {
match e.kind() {
&MentatErrorKind::DbError(ref e) => {
assert_eq!(e.kind(), ::mentat_db::DbErrorKind::UnallocatedEntid(next + 1));
}
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);
match conn.transact(&mut sqlite, t.as_str()) {
Err(MentatError::DbError(e)) => {
// All this, despite this being the ID we were about to allocate!
assert_eq!(
e.kind(),
::db_traits::errors::DbErrorKind::UnallocatedEntid(next)
);
Err(e) => {
match e.kind() {
&MentatErrorKind::DbError(ref e) => {
assert_eq!(e.kind(), ::mentat_db::DbErrorKind::UnallocatedEntid(next + 1));
}
x => {
panic!("expected db error, got {:?}", x);
}
}
}
x => panic!("expected db error, got {:?}", x),
}
@ -642,8 +649,8 @@ mod tests {
// Bad EDN: missing closing ']'.
let report = conn.transact(&mut sqlite, "[[:db/add \"t\" :db/ident :a/keyword]");
match report.expect_err("expected transact to fail for bad edn") {
MentatError::EdnParseError(_) => {}
match report.expect_err("expected transact to fail for bad edn").kind() {
&MentatErrorKind::EdnParseError(_) => { }
x => panic!("expected EDN parse error, got {:?}", x),
}
@ -655,8 +662,8 @@ mod tests {
// Bad transaction data: missing leading :db/add.
let report = conn.transact(&mut sqlite, "[[\"t\" :db/ident :b/keyword]]");
match report.expect_err("expected transact error") {
MentatError::EdnParseError(_) => {}
match report.expect_err("expected transact error").kind() {
&MentatErrorKind::EdnParseError(_) => { }
x => panic!("expected EDN parse error, got {:?}", x),
}
@ -668,12 +675,10 @@ mod tests {
// Bad transaction based on state of store: conflicting upsert.
let report = conn.transact(
&mut sqlite,
"[[:db/add \"u\" :db/ident :a/keyword]
[:db/add \"u\" :db/ident :b/keyword]]",
);
match report.expect_err("expected transact error") {
MentatError::DbError(e) => match e.kind() {
&mut sqlite, "[[:db/add \"u\" :db/ident :a/keyword]
[:db/add \"u\" :db/ident :b/keyword]]");
match report.expect_err("expected transact error").kind() {
&MentatErrorKind::DbError(ref e) => {
::db_traits::errors::DbErrorKind::SchemaConstraintViolation(_) => {}
_ => panic!("expected SchemaConstraintViolation"),
},
@ -705,8 +710,8 @@ mod tests {
CacheDirection::Forward,
CacheAction::Register,
);
match res.expect_err("expected cache to fail") {
MentatError::UnknownAttribute(msg) => assert_eq!(msg, ":foo/bat"),
match res.expect_err("expected cache to fail").kind() {
&MentatErrorKind::UnknownAttribute(ref msg) => assert_eq!(msg, ":foo/bat")
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::{MentatError, Result};
pub use public_traits::errors::{MentatErrorKind, Result};
pub use edn::{FromMicros, FromMillis, ParseError, ToMicros, ToMillis};
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 public_traits::errors::{MentatError, Result};
use public_traits::errors::{MentatErrorKind, Result};
pub struct QueryBuilder<'a> {
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> {
let entid = self
.store
.conn()
.current_schema()
.get_entid(&value)
.ok_or(MentatError::UnknownAttribute(value.to_string()))?;
let entid = self.store.conn().current_schema().get_entid(&value).ok_or_else(||
MentatError::from(MentatErrorKind::UnknownAttribute(value.to_string())))?;
self.values.insert(
Variable::from_valid_name(var),
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,
};
use super::errors::{MentatError, Result};
use super::errors::{MentatErrorKind, Result};
use mentat_transaction::{InProgress, Queryable};
@ -325,17 +325,17 @@ where
{
fn core_type(&self, t: ValueType) -> Result<KnownEntid> {
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> {
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> {
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)
}
}
@ -548,7 +548,7 @@ pub trait VersionedStore: HasVocabularies + HasSchema {
// We have two vocabularies with the same name, same version, and
// different definitions for an attribute. That's a coding error.
// We can't accept this vocabulary.
bail!(MentatError::ConflictingAttributeDefinitions(
bail!(MentatErrorKind::ConflictingAttributeDefinitions(
definition.name.to_string(),
definition.version,
pair.0.to_string(),
@ -604,7 +604,7 @@ pub trait VersionedStore: HasVocabularies + HasSchema {
fn verify_core_schema(&self) -> Result<()> {
if let Some(core) = self.read_vocabulary_named(&DB_SCHEMA_CORE)? {
if core.version != CORE_SCHEMA_VERSION {
bail!(MentatError::UnexpectedCoreSchema(
bail!(MentatErrorKind::UnexpectedCoreSchema(
CORE_SCHEMA_VERSION,
Some(core.version)
));
@ -613,7 +613,7 @@ pub trait VersionedStore: HasVocabularies + HasSchema {
// TODO: check things other than the version.
} else {
// This would be seriously messed up.
bail!(MentatError::UnexpectedCoreSchema(CORE_SCHEMA_VERSION, None));
bail!(MentatErrorKind::UnexpectedCoreSchema(CORE_SCHEMA_VERSION, None));
}
Ok(())
}
@ -694,7 +694,7 @@ impl<'a, 'c> VersionedStore for InProgress<'a, 'c> {
self.install_attributes_for(definition, attributes)
}
VocabularyCheck::PresentButTooNew { newer_version } => {
Err(MentatError::ExistingVocabularyTooNew(
Err(MentatErrorKind::ExistingVocabularyTooNew(
definition.name.to_string(),
newer_version.version,
definition.version,
@ -722,7 +722,7 @@ impl<'a, 'c> VersionedStore for InProgress<'a, 'c> {
out.insert(definition.name.clone(), VocabularyOutcome::Existed);
}
VocabularyCheck::PresentButTooNew { newer_version } => {
bail!(MentatError::ExistingVocabularyTooNew(
bail!(MentatErrorKind::ExistingVocabularyTooNew(
definition.name.to_string(),
newer_version.version,
definition.version
@ -914,7 +914,7 @@ where
attributes: attributes,
}))
}
Some(_) => bail!(MentatError::InvalidVocabularyVersion),
Some(_) => bail!(MentatErrorKind::InvalidVocabularyVersion),
}
} else {
Ok(None)

View file

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

View file

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

View file

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

View file

@ -43,7 +43,7 @@ pub use mentat_query_projector::{
RelResult,
};
use public_traits::errors::{MentatError, Result};
use public_traits::errors::{MentatErrorKind, Result};
pub type QueryExecutionResult = Result<QueryOutput>;
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
// not binding in the `QueryInput`.
if !unbound.is_empty() {
bail!(MentatError::UnboundVariables(
bail!(MentatErrorKind::UnboundVariables(
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> {
schema
.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.
@ -415,7 +415,7 @@ where
if !unbound.is_empty() {
// TODO: Allow binding variables at execution time, not just
// preparation time.
bail!(MentatError::UnboundVariables(
bail!(MentatErrorKind::UnboundVariables(
unbound.into_iter().map(|v| v.to_string()).collect()
));
}