Convert query-algebrizer/ to AlgebrizerError.

This commit is contained in:
Nick Alexander 2018-06-27 11:53:35 -07:00
parent d6569a6a22
commit af005a7669
9 changed files with 57 additions and 143 deletions

View file

@ -32,7 +32,6 @@ use clauses::{
use errors::{ use errors::{
AlgebrizerError, AlgebrizerError,
BindingError, BindingError,
InvalidBinding,
Result, Result,
}; };
@ -59,12 +58,12 @@ impl ConjoiningClauses {
if where_fn.binding.is_empty() { if where_fn.binding.is_empty() {
// The binding must introduce at least one bound variable. // The binding must introduce at least one bound variable.
bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::NoBoundVariable)); bail!(AlgebrizerError::InvalidBinding(where_fn.operator.clone(), BindingError::NoBoundVariable));
} }
if !where_fn.binding.is_valid() { if !where_fn.binding.is_valid() {
// The binding must not duplicate bound variables. // The binding must not duplicate bound variables.
bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::RepeatedBoundVariable)); bail!(AlgebrizerError::InvalidBinding(where_fn.operator.clone(), BindingError::RepeatedBoundVariable));
} }
// We should have exactly four bindings. Destructure them now. // We should have exactly four bindings. Destructure them now.
@ -72,7 +71,7 @@ impl ConjoiningClauses {
Binding::BindRel(bindings) => { Binding::BindRel(bindings) => {
let bindings_count = bindings.len(); let bindings_count = bindings.len();
if bindings_count < 1 || bindings_count > 4 { if bindings_count < 1 || bindings_count > 4 {
bail!(InvalidBinding::new(where_fn.operator.clone(), bail!(AlgebrizerError::InvalidBinding(where_fn.operator.clone(),
BindingError::InvalidNumberOfBindings { BindingError::InvalidNumberOfBindings {
number: bindings.len(), number: bindings.len(),
expected: 4, expected: 4,
@ -83,7 +82,7 @@ impl ConjoiningClauses {
}, },
Binding::BindScalar(_) | Binding::BindScalar(_) |
Binding::BindTuple(_) | Binding::BindTuple(_) |
Binding::BindColl(_) => bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::ExpectedBindRel)), Binding::BindColl(_) => bail!(AlgebrizerError::InvalidBinding(where_fn.operator.clone(), BindingError::ExpectedBindRel)),
}; };
let mut bindings = bindings.into_iter(); let mut bindings = bindings.into_iter();
let b_entity = bindings.next().unwrap(); let b_entity = bindings.next().unwrap();
@ -246,7 +245,7 @@ impl ConjoiningClauses {
// We do not allow the score to be bound. // We do not allow the score to be bound.
if self.value_bindings.contains_key(var) || self.input_variables.contains(var) { if self.value_bindings.contains_key(var) || self.input_variables.contains(var) {
bail!(InvalidBinding::new(var.name(), BindingError::UnexpectedBinding)); bail!(AlgebrizerError::InvalidBinding(var.name(), BindingError::UnexpectedBinding));
} }
// We bind the value ourselves. This handily takes care of substituting into existing uses. // We bind the value ourselves. This handily takes care of substituting into existing uses.

View file

@ -33,7 +33,6 @@ use clauses::convert::ValueConversion;
use errors::{ use errors::{
AlgebrizerError, AlgebrizerError,
BindingError, BindingError,
InvalidBinding,
Result, Result,
}; };
@ -125,12 +124,12 @@ impl ConjoiningClauses {
if where_fn.binding.is_empty() { if where_fn.binding.is_empty() {
// The binding must introduce at least one bound variable. // The binding must introduce at least one bound variable.
bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::NoBoundVariable)); bail!(AlgebrizerError::InvalidBinding(where_fn.operator.clone(), BindingError::NoBoundVariable));
} }
if !where_fn.binding.is_valid() { if !where_fn.binding.is_valid() {
// The binding must not duplicate bound variables. // The binding must not duplicate bound variables.
bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::RepeatedBoundVariable)); bail!(AlgebrizerError::InvalidBinding(where_fn.operator.clone(), BindingError::RepeatedBoundVariable));
} }
let schema = known.schema; let schema = known.schema;

View file

@ -553,7 +553,7 @@ mod testing {
:where (not [?x :foo/knows ?y])]"#; :where (not [?x :foo/knows ?y])]"#;
let parsed = parse_find_string(query).expect("parse failed"); let parsed = parse_find_string(query).expect("parse failed");
let err = algebrize(known, parsed).expect_err("algebrization should have failed"); let err = algebrize(known, parsed).expect_err("algebrization should have failed");
match err.downcast().expect("expected AlgebrizerError") { match err {
AlgebrizerError::UnboundVariable(var) => { assert_eq!(var, PlainSymbol("?x".to_string())); }, AlgebrizerError::UnboundVariable(var) => { assert_eq!(var, PlainSymbol("?x".to_string())); },
x => panic!("expected Unbound Variable error, got {:?}", x), x => panic!("expected Unbound Variable error, got {:?}", x),
} }

View file

@ -27,7 +27,6 @@ use clauses::{
use errors::{ use errors::{
AlgebrizerError, AlgebrizerError,
BindingError, BindingError,
InvalidBinding,
Result, Result,
}; };
@ -66,12 +65,12 @@ impl ConjoiningClauses {
if where_fn.binding.is_empty() { if where_fn.binding.is_empty() {
// The binding must introduce at least one bound variable. // The binding must introduce at least one bound variable.
bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::NoBoundVariable)); bail!(AlgebrizerError::InvalidBinding(where_fn.operator.clone(), BindingError::NoBoundVariable));
} }
if !where_fn.binding.is_valid() { if !where_fn.binding.is_valid() {
// The binding must not duplicate bound variables. // The binding must not duplicate bound variables.
bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::RepeatedBoundVariable)); bail!(AlgebrizerError::InvalidBinding(where_fn.operator.clone(), BindingError::RepeatedBoundVariable));
} }
// We should have exactly one binding. Destructure it now. // We should have exactly one binding. Destructure it now.
@ -79,7 +78,7 @@ impl ConjoiningClauses {
Binding::BindRel(bindings) => { Binding::BindRel(bindings) => {
let bindings_count = bindings.len(); let bindings_count = bindings.len();
if bindings_count != 1 { if bindings_count != 1 {
bail!(InvalidBinding::new(where_fn.operator.clone(), bail!(AlgebrizerError::InvalidBinding(where_fn.operator.clone(),
BindingError::InvalidNumberOfBindings { BindingError::InvalidNumberOfBindings {
number: bindings_count, number: bindings_count,
expected: 1, expected: 1,
@ -93,7 +92,7 @@ impl ConjoiningClauses {
Binding::BindColl(v) => v, Binding::BindColl(v) => v,
Binding::BindScalar(_) | Binding::BindScalar(_) |
Binding::BindTuple(_) => { Binding::BindTuple(_) => {
bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::ExpectedBindRelOrBindColl)) bail!(AlgebrizerError::InvalidBinding(where_fn.operator.clone(), BindingError::ExpectedBindRelOrBindColl))
}, },
}; };
@ -144,12 +143,12 @@ impl ConjoiningClauses {
if where_fn.binding.is_empty() { if where_fn.binding.is_empty() {
// The binding must introduce at least one bound variable. // The binding must introduce at least one bound variable.
bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::NoBoundVariable)); bail!(AlgebrizerError::InvalidBinding(where_fn.operator.clone(), BindingError::NoBoundVariable));
} }
if !where_fn.binding.is_valid() { if !where_fn.binding.is_valid() {
// The binding must not duplicate bound variables. // The binding must not duplicate bound variables.
bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::RepeatedBoundVariable)); bail!(AlgebrizerError::InvalidBinding(where_fn.operator.clone(), BindingError::RepeatedBoundVariable));
} }
// We should have at most five bindings. Destructure them now. // We should have at most five bindings. Destructure them now.
@ -157,7 +156,7 @@ impl ConjoiningClauses {
Binding::BindRel(bindings) => { Binding::BindRel(bindings) => {
let bindings_count = bindings.len(); let bindings_count = bindings.len();
if bindings_count < 1 || bindings_count > 5 { if bindings_count < 1 || bindings_count > 5 {
bail!(InvalidBinding::new(where_fn.operator.clone(), bail!(AlgebrizerError::InvalidBinding(where_fn.operator.clone(),
BindingError::InvalidNumberOfBindings { BindingError::InvalidNumberOfBindings {
number: bindings.len(), number: bindings.len(),
expected: 5, expected: 5,
@ -167,7 +166,7 @@ impl ConjoiningClauses {
}, },
Binding::BindScalar(_) | Binding::BindScalar(_) |
Binding::BindTuple(_) | Binding::BindTuple(_) |
Binding::BindColl(_) => bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::ExpectedBindRel)), Binding::BindColl(_) => bail!(AlgebrizerError::InvalidBinding(where_fn.operator.clone(), BindingError::ExpectedBindRel)),
}; };
let mut bindings = bindings.into_iter(); let mut bindings = bindings.into_iter();
let b_e = bindings.next().unwrap_or(VariableOrPlaceholder::Placeholder); let b_e = bindings.next().unwrap_or(VariableOrPlaceholder::Placeholder);

View file

@ -11,17 +11,9 @@
extern crate mentat_query; extern crate mentat_query;
use std; // To refer to std::result::Result. use std; // To refer to std::result::Result.
use std::fmt;
use std::fmt::Display;
use failure::{
Backtrace,
Context,
Error,
Fail,
};
use mentat_core::{ use mentat_core::{
EdnParseError,
ValueType, ValueType,
ValueTypeSet, ValueTypeSet,
}; };
@ -30,7 +22,7 @@ use self::mentat_query::{
PlainSymbol, PlainSymbol,
}; };
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, AlgebrizerError>;
#[macro_export] #[macro_export]
macro_rules! bail { macro_rules! bail {
@ -39,44 +31,7 @@ macro_rules! bail {
) )
} }
#[derive(Debug)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct InvalidBinding {
pub function: PlainSymbol,
pub inner: Context<BindingError>
}
impl InvalidBinding {
pub fn new(function: PlainSymbol, inner: BindingError) -> InvalidBinding {
InvalidBinding {
function: function,
inner: Context::new(inner)
}
}
}
impl Fail for InvalidBinding {
fn cause(&self) -> Option<&Fail> {
self.inner.cause()
}
fn backtrace(&self) -> Option<&Backtrace> {
self.inner.backtrace()
}
}
impl Display for InvalidBinding {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "invalid binding for {}: {:?}", self.function, self.inner)
}
}
impl Display for BindingError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "BindingError: {:?}", self)
}
}
#[derive(Clone, Debug, Eq, PartialEq, Fail)]
pub enum BindingError { pub enum BindingError {
NoBoundVariable, NoBoundVariable,
UnexpectedBinding, UnexpectedBinding,
@ -96,7 +51,7 @@ pub enum BindingError {
InvalidNumberOfBindings { number: usize, expected: usize }, InvalidNumberOfBindings { number: usize, expected: usize },
} }
#[derive(Debug, Fail)] #[derive(Clone, Debug, Eq, Fail, PartialEq)]
pub enum AlgebrizerError { pub enum AlgebrizerError {
#[fail(display = "{} var {} is duplicated", _0, _1)] #[fail(display = "{} var {} is duplicated", _0, _1)]
DuplicateVariableError(PlainSymbol, &'static str), DuplicateVariableError(PlainSymbol, &'static str),
@ -144,4 +99,16 @@ pub enum AlgebrizerError {
#[fail(display = "non-matching variables in 'not' clause")] #[fail(display = "non-matching variables in 'not' clause")]
NonMatchingVariablesInNotClause, NonMatchingVariablesInNotClause,
#[fail(display = "binding error in {}: {:?}", _0, _1)]
InvalidBinding(PlainSymbol, BindingError),
#[fail(display = "{}", _0)]
EdnParseError(#[cause] EdnParseError),
}
impl From<EdnParseError> for AlgebrizerError {
fn from(error: EdnParseError) -> AlgebrizerError {
AlgebrizerError::EdnParseError(error)
}
} }

View file

@ -51,7 +51,6 @@ pub use errors::{
AlgebrizerError, AlgebrizerError,
BindingError, BindingError,
Result, Result,
InvalidBinding,
}; };
pub use clauses::{ pub use clauses::{

View file

@ -33,7 +33,6 @@ use mentat_query_algebrizer::{
AlgebrizerError, AlgebrizerError,
BindingError, BindingError,
ComputedTable, ComputedTable,
InvalidBinding,
Known, Known,
QueryInputs, QueryInputs,
}; };
@ -255,14 +254,8 @@ fn test_ground_coll_heterogeneous_types() {
let q = r#"[:find ?x :where [?x _ ?v] [(ground [false 8.5]) [?v ...]]]"#; let q = r#"[:find ?x :where [?x _ ?v] [(ground [false 8.5]) [?v ...]]]"#;
let schema = prepopulated_schema(); let schema = prepopulated_schema();
let known = Known::for_schema(&schema); let known = Known::for_schema(&schema);
let e = bails(known, &q); assert_eq!(bails(known, &q),
match e.downcast().expect("proper error") { AlgebrizerError::InvalidGroundConstant);
AlgebrizerError::InvalidGroundConstant => {
},
_ => {
panic!();
},
}
} }
#[test] #[test]
@ -270,14 +263,8 @@ fn test_ground_rel_heterogeneous_types() {
let q = r#"[:find ?x :where [?x _ ?v] [(ground [[false] [5]]) [[?v]]]]"#; let q = r#"[:find ?x :where [?x _ ?v] [(ground [[false] [5]]) [[?v]]]]"#;
let schema = prepopulated_schema(); let schema = prepopulated_schema();
let known = Known::for_schema(&schema); let known = Known::for_schema(&schema);
let e = bails(known, &q); assert_eq!(bails(known, &q),
match e.downcast().expect("proper error") { AlgebrizerError::InvalidGroundConstant);
AlgebrizerError::InvalidGroundConstant => {
},
_ => {
panic!();
},
}
} }
#[test] #[test]
@ -285,15 +272,8 @@ fn test_ground_tuple_duplicate_vars() {
let q = r#"[:find ?x :where [?x :foo/age ?v] [(ground [8 10]) [?x ?x]]]"#; let q = r#"[:find ?x :where [?x :foo/age ?v] [(ground [8 10]) [?x ?x]]]"#;
let schema = prepopulated_schema(); let schema = prepopulated_schema();
let known = Known::for_schema(&schema); let known = Known::for_schema(&schema);
let e: InvalidBinding = bails(known, &q).downcast().expect("proper error"); assert_eq!(bails(known, &q),
assert_eq!(e.function, PlainSymbol::plain("ground")); AlgebrizerError::InvalidBinding(PlainSymbol::plain("ground"), BindingError::RepeatedBoundVariable));
match e.inner.get_context() {
&BindingError::RepeatedBoundVariable => {
},
_ => {
panic!();
},
}
} }
#[test] #[test]
@ -301,15 +281,8 @@ fn test_ground_rel_duplicate_vars() {
let q = r#"[:find ?x :where [?x :foo/age ?v] [(ground [[8 10]]) [[?x ?x]]]]"#; let q = r#"[:find ?x :where [?x :foo/age ?v] [(ground [[8 10]]) [[?x ?x]]]]"#;
let schema = prepopulated_schema(); let schema = prepopulated_schema();
let known = Known::for_schema(&schema); let known = Known::for_schema(&schema);
let e: InvalidBinding = bails(known, &q).downcast().expect("expected InvalidBinding"); assert_eq!(bails(known, &q),
assert_eq!(e.function, PlainSymbol::plain("ground")); AlgebrizerError::InvalidBinding(PlainSymbol::plain("ground"), BindingError::RepeatedBoundVariable));
match e.inner.get_context() {
&BindingError::RepeatedBoundVariable => {
},
_ => {
panic!();
},
}
} }
#[test] #[test]
@ -317,15 +290,8 @@ fn test_ground_nonexistent_variable_invalid() {
let q = r#"[:find ?x ?e :where [?e _ ?x] (not [(ground 17) ?v])]"#; let q = r#"[:find ?x ?e :where [?e _ ?x] (not [(ground 17) ?v])]"#;
let schema = prepopulated_schema(); let schema = prepopulated_schema();
let known = Known::for_schema(&schema); let known = Known::for_schema(&schema);
let e = bails(known, &q).downcast().expect("proper error"); assert_eq!(bails(known, &q),
match e { AlgebrizerError::UnboundVariable(PlainSymbol::plain("?v")));
AlgebrizerError::UnboundVariable(PlainSymbol(v)) => {
assert_eq!(v, "?v".to_string());
},
_ => {
panic!();
},
}
} }
#[test] #[test]
@ -341,13 +307,6 @@ fn test_unbound_input_variable_invalid() {
let i = QueryInputs::new(types, BTreeMap::default()).expect("valid QueryInputs"); let i = QueryInputs::new(types, BTreeMap::default()).expect("valid QueryInputs");
let e = bails_with_inputs(known, &q, i).downcast().expect("proper error"); assert_eq!(bails_with_inputs(known, &q, i),
match e { AlgebrizerError::UnboundVariable(PlainSymbol::plain("?x")));
AlgebrizerError::UnboundVariable(v) => {
assert_eq!(v.0, "?x");
},
_ => {
panic!();
},
}
} }

View file

@ -78,27 +78,21 @@ fn test_instant_predicates_require_instants() {
:where :where
[?e :foo/date ?t] [?e :foo/date ?t]
[(> ?t "2017-06-16T00:56:41.257Z")]]"#; [(> ?t "2017-06-16T00:56:41.257Z")]]"#;
match bails(known, query).downcast().expect("proper cause") { assert_eq!(bails(known, query),
AlgebrizerError::InvalidArgumentType(op, why, idx) => { AlgebrizerError::InvalidArgumentType(
assert_eq!(op, PlainSymbol::plain(">")); PlainSymbol::plain(">"),
assert_eq!(why, ValueTypeSet::of_numeric_and_instant_types()); ValueTypeSet::of_numeric_and_instant_types(),
assert_eq!(idx, 1); 1));
},
_ => panic!("Expected InvalidArgument."),
}
let query = r#"[:find ?e let query = r#"[:find ?e
:where :where
[?e :foo/date ?t] [?e :foo/date ?t]
[(> "2017-06-16T00:56:41.257Z", ?t)]]"#; [(> "2017-06-16T00:56:41.257Z", ?t)]]"#;
match bails(known, query).downcast().expect("proper cause") { assert_eq!(bails(known, query),
AlgebrizerError::InvalidArgumentType(op, why, idx) => { AlgebrizerError::InvalidArgumentType(
assert_eq!(op, PlainSymbol::plain(">")); PlainSymbol::plain(">"),
assert_eq!(why, ValueTypeSet::of_numeric_and_instant_types()); ValueTypeSet::of_numeric_and_instant_types(),
assert_eq!(idx, 0); // We get this right. 0)); // We get this right.
},
_ => panic!("Expected InvalidArgument."),
}
// You can try using a number, which is valid input to a numeric predicate. // You can try using a number, which is valid input to a numeric predicate.
// In this store and query, though, that means we expect `?t` to be both // In this store and query, though, that means we expect `?t` to be both

View file

@ -13,9 +13,6 @@
// this module will get warnings otherwise). // this module will get warnings otherwise).
#![allow(dead_code)] #![allow(dead_code)]
extern crate failure;
use self::failure::Error;
use mentat_core::{ use mentat_core::{
Attribute, Attribute,
Entid, Entid,
@ -28,6 +25,7 @@ use mentat_query::{
}; };
use mentat_query_algebrizer::{ use mentat_query_algebrizer::{
AlgebrizerError,
ConjoiningClauses, ConjoiningClauses,
Known, Known,
QueryInputs, QueryInputs,
@ -83,12 +81,12 @@ impl SchemaBuilder {
} }
} }
pub fn bails(known: Known, input: &str) -> Error { pub fn bails(known: Known, input: &str) -> AlgebrizerError {
let parsed = parse_find_string(input).expect("query input to have parsed"); let parsed = parse_find_string(input).expect("query input to have parsed");
algebrize(known, parsed).expect_err("algebrize to have failed") algebrize(known, parsed).expect_err("algebrize to have failed")
} }
pub fn bails_with_inputs(known: Known, input: &str, inputs: QueryInputs) -> Error { pub fn bails_with_inputs(known: Known, input: &str, inputs: QueryInputs) -> AlgebrizerError {
let parsed = parse_find_string(input).expect("query input to have parsed"); let parsed = parse_find_string(input).expect("query input to have parsed");
algebrize_with_inputs(known, parsed, 0, inputs).expect_err("algebrize to have failed") algebrize_with_inputs(known, parsed, 0, inputs).expect_err("algebrize to have failed")
} }