Convert query_projector/ to failure.

This commit is contained in:
Grisha Kruglov 2018-06-04 16:53:31 -04:00 committed by Nick Alexander
parent 061967f268
commit c075434f84
7 changed files with 83 additions and 95 deletions

View file

@ -4,7 +4,8 @@ version = "0.0.1"
workspace = ".." workspace = ".."
[dependencies] [dependencies]
error-chain = { git = "https://github.com/rnewman/error-chain", branch = "rnewman/sync" } failure = "0.1.1"
failure_derive = "0.1.1"
indexmap = "1" indexmap = "1"
[dependencies.rusqlite] [dependencies.rusqlite]

View file

@ -33,7 +33,7 @@ use mentat_query_sql::{
}; };
use errors::{ use errors::{
ErrorKind, ProjectorError,
Result, Result,
}; };
@ -79,7 +79,7 @@ impl SimpleAggregationOp {
pub(crate) fn is_applicable_to_types(&self, possibilities: ValueTypeSet) -> Result<ValueType> { pub(crate) 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!(ErrorKind::CannotProjectImpossibleBinding(*self)) bail!(ProjectorError::CannotProjectImpossibleBinding(*self))
} }
match self { match self {
@ -92,7 +92,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!(ErrorKind::CannotApplyAggregateOperationToTypes(*self, possibilities)) bail!(ProjectorError::CannotApplyAggregateOperationToTypes(*self, possibilities))
} }
}, },
&Sum => { &Sum => {
@ -104,7 +104,7 @@ impl SimpleAggregationOp {
Ok(ValueType::Long) Ok(ValueType::Long)
} }
} else { } else {
bail!(ErrorKind::CannotApplyAggregateOperationToTypes(*self, possibilities)) bail!(ProjectorError::CannotApplyAggregateOperationToTypes(*self, possibilities))
} }
}, },
@ -124,7 +124,7 @@ impl SimpleAggregationOp {
// These types are unordered. // These types are unordered.
Keyword | Ref | Uuid => { Keyword | Ref | Uuid => {
bail!(ErrorKind::CannotApplyAggregateOperationToTypes(*self, possibilities)) bail!(ProjectorError::CannotApplyAggregateOperationToTypes(*self, possibilities))
}, },
} }
} else { } else {
@ -139,7 +139,7 @@ impl SimpleAggregationOp {
Ok(ValueType::Long) Ok(ValueType::Long)
} }
} else { } else {
bail!(ErrorKind::CannotApplyAggregateOperationToTypes(*self, possibilities)) bail!(ProjectorError::CannotApplyAggregateOperationToTypes(*self, possibilities))
} }
} }
}, },

View file

@ -8,72 +8,58 @@
// 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 rusqlite; use std; // To refer to std::result::Result.
use failure::{
Error,
};
use mentat_core::{ use mentat_core::{
ValueTypeSet, ValueTypeSet,
}; };
use mentat_db;
use mentat_query::{ use mentat_query::{
PlainSymbol, PlainSymbol,
}; };
use mentat_query_pull;
use aggregates::{ use aggregates::{
SimpleAggregationOp, SimpleAggregationOp,
}; };
error_chain! { #[macro_export]
types { macro_rules! bail {
Error, ErrorKind, ResultExt, Result; ($e:expr) => (
return Err($e.into());
)
} }
errors { pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Fail)]
pub enum ProjectorError {
/// 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.
NotYetImplemented(t: String) { #[fail(display = "not yet implemented: {}", _0)]
description("not yet implemented") NotYetImplemented(String),
display("not yet implemented: {}", t)
}
CannotProjectImpossibleBinding(op: SimpleAggregationOp) {
description("no possible types for variable in projection list")
display("no possible types for value provided to {:?}", op)
}
CannotApplyAggregateOperationToTypes(op: SimpleAggregationOp, types: ValueTypeSet) {
description("cannot apply projection operation to types")
display("cannot apply projection operation {:?} to types {:?}", op, types)
}
InvalidProjection(t: String) {
description("invalid projection")
display("invalid projection: {}", t)
}
UnboundVariable(var: PlainSymbol) {
description("cannot project unbound variable")
display("cannot project unbound variable {:?}", var)
}
NoTypeAvailableForVariable(var: PlainSymbol) {
description("cannot find type for variable")
display("cannot find type for variable {:?}", var)
}
UnexpectedResultsType(actual: &'static str, expected: &'static str) {
description("unexpected query results type")
display("expected {}, got {}", expected, actual)
}
AmbiguousAggregates(min_max_count: usize, corresponding_count: usize) {
description("ambiguous aggregates")
display("min/max expressions: {} (max 1), corresponding: {}", min_max_count, corresponding_count)
}
}
foreign_links { #[fail(display = "no possible types for value provided to {:?}", _0)]
Rusqlite(rusqlite::Error); CannotProjectImpossibleBinding(SimpleAggregationOp),
}
links { #[fail(display = "cannot apply projection operation {:?} to types {:?}", _0, _1)]
DbError(mentat_db::Error, mentat_db::ErrorKind); CannotApplyAggregateOperationToTypes(SimpleAggregationOp, ValueTypeSet),
PullError(mentat_query_pull::errors::Error, mentat_query_pull::errors::ErrorKind);
} #[fail(display = "invalid projection: {}", _0)]
InvalidProjection(String),
#[fail(display = "cannot project unbound variable {:?}", _0)]
UnboundVariable(PlainSymbol),
#[fail(display = "cannot find type for variable {:?}", _0)]
NoTypeAvailableForVariable(PlainSymbol),
#[fail(display = "expected {}, got {}", _0, _1)]
UnexpectedResultsType(&'static str, &'static str),
#[fail(display = "min/max expressions: {} (max 1), corresponding: {}", _0, _1)]
AmbiguousAggregates(usize, usize),
} }

View file

@ -8,8 +8,10 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
extern crate failure;
#[macro_use] #[macro_use]
extern crate error_chain; extern crate failure_derive;
extern crate indexmap; extern crate indexmap;
extern crate rusqlite; extern crate rusqlite;
@ -67,12 +69,14 @@ use mentat_query_sql::{
Projection, Projection,
}; };
#[macro_use]
pub mod errors;
mod aggregates; mod aggregates;
mod project; mod project;
mod projectors; mod projectors;
mod pull; mod pull;
mod relresult; mod relresult;
pub mod errors;
pub use aggregates::{ pub use aggregates::{
SimpleAggregationOp, SimpleAggregationOp,
@ -109,7 +113,7 @@ pub use relresult::{
}; };
use errors::{ use errors::{
ErrorKind, ProjectorError,
Result, Result,
}; };
@ -296,35 +300,35 @@ 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!(ErrorKind::UnexpectedResultsType("coll", "scalar")), QueryResults::Coll(_) => bail!(ProjectorError::UnexpectedResultsType("coll", "scalar")),
QueryResults::Tuple(_) => bail!(ErrorKind::UnexpectedResultsType("tuple", "scalar")), QueryResults::Tuple(_) => bail!(ProjectorError::UnexpectedResultsType("tuple", "scalar")),
QueryResults::Rel(_) => bail!(ErrorKind::UnexpectedResultsType("rel", "scalar")), QueryResults::Rel(_) => bail!(ProjectorError::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(_) => bail!(ErrorKind::UnexpectedResultsType("scalar", "coll")), QueryResults::Scalar(_) => bail!(ProjectorError::UnexpectedResultsType("scalar", "coll")),
QueryResults::Coll(c) => Ok(c), QueryResults::Coll(c) => Ok(c),
QueryResults::Tuple(_) => bail!(ErrorKind::UnexpectedResultsType("tuple", "coll")), QueryResults::Tuple(_) => bail!(ProjectorError::UnexpectedResultsType("tuple", "coll")),
QueryResults::Rel(_) => bail!(ErrorKind::UnexpectedResultsType("rel", "coll")), QueryResults::Rel(_) => bail!(ProjectorError::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(_) => bail!(ErrorKind::UnexpectedResultsType("scalar", "tuple")), QueryResults::Scalar(_) => bail!(ProjectorError::UnexpectedResultsType("scalar", "tuple")),
QueryResults::Coll(_) => bail!(ErrorKind::UnexpectedResultsType("coll", "tuple")), QueryResults::Coll(_) => bail!(ProjectorError::UnexpectedResultsType("coll", "tuple")),
QueryResults::Tuple(t) => Ok(t), QueryResults::Tuple(t) => Ok(t),
QueryResults::Rel(_) => bail!(ErrorKind::UnexpectedResultsType("rel", "tuple")), QueryResults::Rel(_) => bail!(ProjectorError::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(_) => bail!(ErrorKind::UnexpectedResultsType("scalar", "rel")), QueryResults::Scalar(_) => bail!(ProjectorError::UnexpectedResultsType("scalar", "rel")),
QueryResults::Coll(_) => bail!(ErrorKind::UnexpectedResultsType("coll", "rel")), QueryResults::Coll(_) => bail!(ProjectorError::UnexpectedResultsType("coll", "rel")),
QueryResults::Tuple(_) => bail!(ErrorKind::UnexpectedResultsType("tuple", "rel")), QueryResults::Tuple(_) => bail!(ProjectorError::UnexpectedResultsType("tuple", "rel")),
QueryResults::Rel(r) => Ok(r), QueryResults::Rel(r) => Ok(r),
} }
} }

View file

@ -55,7 +55,7 @@ use aggregates::{
}; };
use errors::{ use errors::{
ErrorKind, ProjectorError,
Result, Result,
}; };
@ -127,14 +127,14 @@ fn candidate_type_column(cc: &ConjoiningClauses, var: &Variable) -> Result<(Colu
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(|| ErrorKind::UnboundVariable(var.name()).into()) .ok_or_else(|| ProjectorError::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(|| ErrorKind::UnboundVariable(var.name()).into()) .ok_or_else(|| ProjectorError::UnboundVariable(var.name()).into())
} }
fn candidate_column(cc: &ConjoiningClauses, var: &Variable) -> Result<(ColumnOrExpression, Name)> { fn candidate_column(cc: &ConjoiningClauses, var: &Variable) -> Result<(ColumnOrExpression, Name)> {
@ -211,18 +211,18 @@ 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!(ErrorKind::InvalidProjection(format!("Duplicate variable {} in query.", var))); bail!(ProjectorError::InvalidProjection(format!("Duplicate variable {} in query.", var)));
} }
if corresponded_variables.contains(var) { if corresponded_variables.contains(var) {
bail!(ErrorKind::InvalidProjection(format!("Can't project both {} and `(the {})` from a query.", var, var))); bail!(ProjectorError::InvalidProjection(format!("Can't project both {} and `(the {})` from a query.", var, var)));
} }
}, },
&Element::Corresponding(ref var) => { &Element::Corresponding(ref var) => {
if outer_variables.contains(var) { if outer_variables.contains(var) {
bail!(ErrorKind::InvalidProjection(format!("Can't project both {} and `(the {})` from a query.", var, var))); bail!(ProjectorError::InvalidProjection(format!("Can't project both {} and `(the {})` from a query.", var, var)));
} }
if corresponded_variables.contains(var) { if corresponded_variables.contains(var) {
bail!(ErrorKind::InvalidProjection(format!("`(the {})` appears twice in query.", var))); bail!(ProjectorError::InvalidProjection(format!("`(the {})` appears twice in query.", var)));
} }
}, },
&Element::Aggregate(_) => { &Element::Aggregate(_) => {
@ -346,7 +346,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!(ErrorKind::NotYetImplemented("complex aggregates".into())); bail!(ProjectorError::NotYetImplemented("complex aggregates".into()));
} }
}, },
} }
@ -355,13 +355,13 @@ 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!(ErrorKind::InvalidProjection("Warning: used `the` without `min` or `max`.".to_string())); bail!(ProjectorError::InvalidProjection("Warning: used `the` without `min` or `max`.".to_string()));
}, },
(1, _) => { (1, _) => {
// This is the success case! // This is the success case!
}, },
(n, c) => { (n, c) => {
bail!(ErrorKind::AmbiguousAggregates(n, c)); bail!(ProjectorError::AmbiguousAggregates(n, c));
}, },
} }
@ -465,7 +465,7 @@ pub(crate) fn project_elements<'a, I: IntoIterator<Item = &'a Element>>(
.extracted_types .extracted_types
.get(&var) .get(&var)
.cloned() .cloned()
.ok_or_else(|| ErrorKind::NoTypeAvailableForVariable(var.name().clone()))?; .ok_or_else(|| ProjectorError::NoTypeAvailableForVariable(var.name().clone()))?;
inner_projection.push(ProjectedColumn(ColumnOrExpression::Column(type_col), type_name.clone())); inner_projection.push(ProjectedColumn(ColumnOrExpression::Column(type_col), type_name.clone()));
} }
if group { if group {

View file

@ -30,9 +30,7 @@ use mentat_query_pull::{
Puller, Puller,
}; };
use errors::{ use errors::Result;
Result,
};
use super::{ use super::{
Index, Index,

View file

@ -99,11 +99,10 @@ fn test_the_without_max_or_min() {
let projection = query_projection(&schema, &algebrized); let projection = query_projection(&schema, &algebrized);
assert!(projection.is_err()); assert!(projection.is_err());
use ::mentat_query_projector::errors::{ use ::mentat_query_projector::errors::{
ErrorKind, ProjectorError,
Error,
}; };
match projection { match projection.err().expect("expected failure").downcast().expect("expected specific error") {
Result::Err(Error(ErrorKind::InvalidProjection(s) , _)) => { ProjectorError::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!(),