Convert query_projector/ to failure.
This commit is contained in:
parent
061967f268
commit
c075434f84
7 changed files with 83 additions and 95 deletions
|
@ -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]
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -30,9 +30,7 @@ use mentat_query_pull::{
|
||||||
Puller,
|
Puller,
|
||||||
};
|
};
|
||||||
|
|
||||||
use errors::{
|
use errors::Result;
|
||||||
Result,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
Index,
|
Index,
|
||||||
|
|
|
@ -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!(),
|
||||||
|
|
Loading…
Reference in a new issue