From 326fe881a0f7932bb8fe19225a7a06f375b18cea Mon Sep 17 00:00:00 2001 From: Grisha Kruglov Date: Thu, 31 May 2018 22:31:21 -0400 Subject: [PATCH] Convert query-algebrizer/ to failure. --- query-algebrizer/Cargo.toml | 3 +- query-algebrizer/src/clauses/convert.rs | 12 +- query-algebrizer/src/clauses/fulltext.rs | 44 +++--- query-algebrizer/src/clauses/ground.rs | 27 ++-- query-algebrizer/src/clauses/inputs.rs | 4 +- query-algebrizer/src/clauses/mod.rs | 5 +- query-algebrizer/src/clauses/not.rs | 14 +- query-algebrizer/src/clauses/predicate.rs | 14 +- query-algebrizer/src/clauses/resolve.rs | 23 ++- query-algebrizer/src/clauses/tx_log_api.rs | 27 ++-- query-algebrizer/src/clauses/where_fn.rs | 4 +- query-algebrizer/src/errors.rs | 174 +++++++++++---------- query-algebrizer/src/lib.rs | 22 +-- query-algebrizer/src/validate.rs | 8 +- query-algebrizer/tests/ground.rs | 38 +++-- query-algebrizer/tests/predicate.rs | 10 +- query-algebrizer/tests/utils/mod.rs | 4 +- 17 files changed, 222 insertions(+), 211 deletions(-) diff --git a/query-algebrizer/Cargo.toml b/query-algebrizer/Cargo.toml index d544a29d..5d44143e 100644 --- a/query-algebrizer/Cargo.toml +++ b/query-algebrizer/Cargo.toml @@ -4,7 +4,8 @@ version = "0.0.1" workspace = ".." [dependencies] -error-chain = { git = "https://github.com/rnewman/error-chain", branch = "rnewman/sync" } +failure = "0.1.1" +failure_derive = "0.1.1" [dependencies.mentat_core] path = "../core" diff --git a/query-algebrizer/src/clauses/convert.rs b/query-algebrizer/src/clauses/convert.rs index 9c9c1ab1..f4a1ad93 100644 --- a/query-algebrizer/src/clauses/convert.rs +++ b/query-algebrizer/src/clauses/convert.rs @@ -28,7 +28,7 @@ use clauses::{ }; use errors::{ - ErrorKind, + AlgebrizerError, Result, }; @@ -80,12 +80,12 @@ impl ValueTypes for FnArg { &FnArg::Constant(NonIntegerConstant::BigInteger(_)) => { // Not yet implemented. - bail!(ErrorKind::UnsupportedArgument) + bail!(AlgebrizerError::UnsupportedArgument) }, // These don't make sense here. TODO: split FnArg into scalar and non-scalar… &FnArg::Vector(_) | - &FnArg::SrcVar(_) => bail!(ErrorKind::UnsupportedArgument), + &FnArg::SrcVar(_) => bail!(AlgebrizerError::UnsupportedArgument), // These are all straightforward. &FnArg::Constant(NonIntegerConstant::Boolean(_)) => ValueTypeSet::of_one(ValueType::Boolean), @@ -196,7 +196,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!(ErrorKind::UnboundVariable((*in_var.0).clone())); + bail!(AlgebrizerError::UnboundVariable((*in_var.0).clone())) } match self.bound_value(&in_var) { // The type is already known if it's a bound variable…. @@ -205,7 +205,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!(ErrorKind::UnboundVariable((*in_var.0).clone())) + bail!(AlgebrizerError::UnboundVariable((*in_var.0).clone())) }, } }, @@ -215,7 +215,7 @@ impl ConjoiningClauses { // These don't make sense here. FnArg::Vector(_) | - FnArg::SrcVar(_) => bail!(ErrorKind::InvalidGroundConstant), + FnArg::SrcVar(_) => bail!(AlgebrizerError::InvalidGroundConstant), // These are all straightforward. FnArg::Constant(NonIntegerConstant::Boolean(x)) => { diff --git a/query-algebrizer/src/clauses/fulltext.rs b/query-algebrizer/src/clauses/fulltext.rs index 1fbae1f2..5e97fb52 100644 --- a/query-algebrizer/src/clauses/fulltext.rs +++ b/query-algebrizer/src/clauses/fulltext.rs @@ -30,8 +30,9 @@ use clauses::{ }; use errors::{ + AlgebrizerError, BindingError, - ErrorKind, + InvalidBinding, Result, }; @@ -53,17 +54,17 @@ 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!(ErrorKind::InvalidNumberOfArguments(where_fn.operator.clone(), where_fn.args.len(), 3)); + bail!(AlgebrizerError::InvalidNumberOfArguments(where_fn.operator.clone(), where_fn.args.len(), 3)); } if where_fn.binding.is_empty() { // The binding must introduce at least one bound variable. - bail!(ErrorKind::InvalidBinding(where_fn.operator.clone(), BindingError::NoBoundVariable)); + bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::NoBoundVariable)); } if !where_fn.binding.is_valid() { // The binding must not duplicate bound variables. - bail!(ErrorKind::InvalidBinding(where_fn.operator.clone(), BindingError::RepeatedBoundVariable)); + bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::RepeatedBoundVariable)); } // We should have exactly four bindings. Destructure them now. @@ -71,17 +72,18 @@ impl ConjoiningClauses { Binding::BindRel(bindings) => { let bindings_count = bindings.len(); if bindings_count < 1 || bindings_count > 4 { - bail!(ErrorKind::InvalidBinding(where_fn.operator.clone(), - BindingError::InvalidNumberOfBindings { - number: bindings.len(), - expected: 4, - })); + bail!(InvalidBinding::new(where_fn.operator.clone(), + BindingError::InvalidNumberOfBindings { + number: bindings.len(), + expected: 4, + }) + ); } bindings }, Binding::BindScalar(_) | Binding::BindTuple(_) | - Binding::BindColl(_) => bail!(ErrorKind::InvalidBinding(where_fn.operator.clone(), BindingError::ExpectedBindRel)), + Binding::BindColl(_) => bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::ExpectedBindRel)), }; let mut bindings = bindings.into_iter(); let b_entity = bindings.next().unwrap(); @@ -94,7 +96,7 @@ impl ConjoiningClauses { // TODO: process source variables. match args.next().unwrap() { FnArg::SrcVar(SrcVar::DefaultSrc) => {}, - _ => bail!(ErrorKind::InvalidArgument(where_fn.operator.clone(), "source variable", 0)), + _ => bail!(AlgebrizerError::InvalidArgument(where_fn.operator.clone(), "source variable", 0)), } let schema = known.schema; @@ -114,10 +116,10 @@ impl ConjoiningClauses { match self.bound_value(&v) { Some(TypedValue::Ref(entid)) => Some(entid), Some(tv) => { - bail!(ErrorKind::InputTypeDisagreement(v.name().clone(), ValueType::Ref, tv.value_type())); + bail!(AlgebrizerError::InputTypeDisagreement(v.name().clone(), ValueType::Ref, tv.value_type())) }, None => { - bail!(ErrorKind::UnboundVariable((*v.0).clone())); + bail!(AlgebrizerError::UnboundVariable((*v.0).clone())) } } }, @@ -127,10 +129,10 @@ 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(ErrorKind::InvalidArgument(where_fn.operator.clone(), "attribute", 1))?; + let a = a.ok_or(AlgebrizerError::InvalidArgument(where_fn.operator.clone(), "attribute", 1))?; let attribute = schema.attribute_for_entid(a) .cloned() - .ok_or(ErrorKind::InvalidArgument(where_fn.operator.clone(), + .ok_or(AlgebrizerError::InvalidArgument(where_fn.operator.clone(), "attribute", 1))?; if !attribute.fulltext { @@ -169,18 +171,18 @@ impl ConjoiningClauses { FnArg::Variable(in_var) => { match self.bound_value(&in_var) { Some(t @ TypedValue::String(_)) => Either::Left(t), - Some(_) => bail!(ErrorKind::InvalidArgument(where_fn.operator.clone(), "string", 2)), + Some(_) => bail!(AlgebrizerError::InvalidArgument(where_fn.operator.clone(), "string", 2)), None => { // 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!(ErrorKind::InvalidArgument(where_fn.operator.clone(), "string", 2)); + bail!(AlgebrizerError::InvalidArgument(where_fn.operator.clone(), "string", 2)) } if self.input_variables.contains(&in_var) { // Sorry, we haven't implemented late binding. // TODO: implement this. - bail!(ErrorKind::UnboundVariable((*in_var.0).clone())); + bail!(AlgebrizerError::UnboundVariable((*in_var.0).clone())) } else { // It must be bound earlier in the query. We already established that // it must be a string column. @@ -189,13 +191,13 @@ impl ConjoiningClauses { .and_then(|bindings| bindings.get(0).cloned()) { Either::Right(binding) } else { - bail!(ErrorKind::UnboundVariable((*in_var.0).clone())); + bail!(AlgebrizerError::UnboundVariable((*in_var.0).clone())) } } }, } }, - _ => bail!(ErrorKind::InvalidArgument(where_fn.operator.clone(), "string", 2)), + _ => bail!(AlgebrizerError::InvalidArgument(where_fn.operator.clone(), "string", 2)), }; let qv = match search { @@ -244,7 +246,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!(ErrorKind::InvalidBinding(var.name(), BindingError::UnexpectedBinding)); + bail!(InvalidBinding::new(var.name(), BindingError::UnexpectedBinding)); } // We bind the value ourselves. This handily takes care of substituting into existing uses. diff --git a/query-algebrizer/src/clauses/ground.rs b/query-algebrizer/src/clauses/ground.rs index cedb2e2a..18f68d64 100644 --- a/query-algebrizer/src/clauses/ground.rs +++ b/query-algebrizer/src/clauses/ground.rs @@ -31,8 +31,9 @@ use clauses::{ use clauses::convert::ValueConversion; use errors::{ + AlgebrizerError, BindingError, - ErrorKind, + InvalidBinding, Result, }; @@ -117,19 +118,19 @@ impl ConjoiningClauses { pub(crate) fn apply_ground(&mut self, known: Known, where_fn: WhereFn) -> Result<()> { if where_fn.args.len() != 1 { - bail!(ErrorKind::InvalidNumberOfArguments(where_fn.operator.clone(), where_fn.args.len(), 1)); + bail!(AlgebrizerError::InvalidNumberOfArguments(where_fn.operator.clone(), where_fn.args.len(), 1)); } let mut args = where_fn.args.into_iter(); if where_fn.binding.is_empty() { // The binding must introduce at least one bound variable. - bail!(ErrorKind::InvalidBinding(where_fn.operator.clone(), BindingError::NoBoundVariable)); + bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::NoBoundVariable)); } if !where_fn.binding.is_valid() { // The binding must not duplicate bound variables. - bail!(ErrorKind::InvalidBinding(where_fn.operator.clone(), BindingError::RepeatedBoundVariable)); + bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::RepeatedBoundVariable)); } let schema = known.schema; @@ -145,7 +146,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!(ErrorKind::GroundBindingsMismatch); + bail!(AlgebrizerError::GroundBindingsMismatch) } for (place, arg) in places.into_iter().zip(children.into_iter()) { self.apply_ground_place(schema, place, arg)? // TODO: short-circuit on impossible. @@ -159,7 +160,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!(ErrorKind::InvalidGroundConstant); + bail!(AlgebrizerError::InvalidGroundConstant) } // Turn a collection of arguments into a Vec of `TypedValue`s of the same type. @@ -177,7 +178,7 @@ impl ConjoiningClauses { if accumulated_types.insert(tv.value_type()) && !accumulated_types.is_unit() { // Values not all of the same type. - Some(Err(ErrorKind::InvalidGroundConstant.into())) + Some(Err(AlgebrizerError::InvalidGroundConstant.into())) } else { Some(Ok(tv)) } @@ -208,7 +209,7 @@ impl ConjoiningClauses { (Binding::BindRel(places), FnArg::Vector(rows)) => { if rows.is_empty() { - bail!(ErrorKind::InvalidGroundConstant); + bail!(AlgebrizerError::InvalidGroundConstant) } // Grab the known types to which these args must conform, and track @@ -229,7 +230,7 @@ impl ConjoiningClauses { if expected_width == 0 { // They can't all be placeholders. - bail!(ErrorKind::InvalidGroundConstant); + bail!(AlgebrizerError::InvalidGroundConstant) } // Accumulate values into `matrix` and types into `a_t_f_c`. @@ -245,7 +246,7 @@ impl ConjoiningClauses { FnArg::Vector(cols) => { // Make sure that every row is the same length. if cols.len() != full_width { - bail!(ErrorKind::InvalidGroundConstant); + bail!(AlgebrizerError::InvalidGroundConstant) } // TODO: don't accumulate twice. @@ -280,13 +281,13 @@ impl ConjoiningClauses { let inserted = acc.insert(val.value_type()); if inserted && !acc.is_unit() { // Heterogeneous types. - bail!(ErrorKind::InvalidGroundConstant); + bail!(AlgebrizerError::InvalidGroundConstant) } matrix.push(val); } }, - _ => bail!(ErrorKind::InvalidGroundConstant), + _ => bail!(AlgebrizerError::InvalidGroundConstant), } } @@ -312,7 +313,7 @@ impl ConjoiningClauses { self.collect_named_bindings(schema, names, types, matrix); Ok(()) }, - (_, _) => bail!(ErrorKind::InvalidGroundConstant), + (_, _) => bail!(AlgebrizerError::InvalidGroundConstant), } } } diff --git a/query-algebrizer/src/clauses/inputs.rs b/query-algebrizer/src/clauses/inputs.rs index 6a4c73af..35c4371d 100644 --- a/query-algebrizer/src/clauses/inputs.rs +++ b/query-algebrizer/src/clauses/inputs.rs @@ -20,7 +20,7 @@ use mentat_query::{ }; use errors::{ - ErrorKind, + AlgebrizerError, Result, }; @@ -72,7 +72,7 @@ impl QueryInputs { let old = types.insert(var.clone(), t); if let Some(old) = old { if old != t { - bail!(ErrorKind::InputTypeDisagreement(var.name(), old, t)); + bail!(AlgebrizerError::InputTypeDisagreement(var.name(), old, t)); } } } diff --git a/query-algebrizer/src/clauses/mod.rs b/query-algebrizer/src/clauses/mod.rs index 29c840bf..2fca66b0 100644 --- a/query-algebrizer/src/clauses/mod.rs +++ b/query-algebrizer/src/clauses/mod.rs @@ -53,8 +53,7 @@ use mentat_query::{ }; use errors::{ - Error, - ErrorKind, + AlgebrizerError, Result, }; @@ -1014,7 +1013,7 @@ impl ConjoiningClauses { let qa = self.extracted_types .get(&var) - .ok_or_else(|| Error::from_kind(ErrorKind::UnboundVariable(var.name())))?; + .ok_or_else(|| AlgebrizerError::UnboundVariable(var.name()))?; self.wheres.add_intersection(ColumnConstraint::HasTypes { value: qa.0.clone(), value_types: types, diff --git a/query-algebrizer/src/clauses/not.rs b/query-algebrizer/src/clauses/not.rs index 299c62ec..05b88330 100644 --- a/query-algebrizer/src/clauses/not.rs +++ b/query-algebrizer/src/clauses/not.rs @@ -17,7 +17,7 @@ use mentat_query::{ use clauses::ConjoiningClauses; use errors::{ - ErrorKind, + AlgebrizerError, Result, }; @@ -45,7 +45,7 @@ impl ConjoiningClauses { let col = self.column_bindings.get(&v).unwrap()[0].clone(); template.column_bindings.insert(v.clone(), vec![col]); } else { - bail!(ErrorKind::UnboundVariable(v.name())); + bail!(AlgebrizerError::UnboundVariable(v.name())); } } @@ -111,8 +111,7 @@ mod testing { }; use errors::{ - Error, - ErrorKind, + AlgebrizerError, }; use types::{ @@ -553,10 +552,9 @@ mod testing { :in ?y :where (not [?x :foo/knows ?y])]"#; let parsed = parse_find_string(query).expect("parse failed"); - let err = algebrize(known, parsed).err(); - assert!(err.is_some()); - match err.unwrap() { - Error(ErrorKind::UnboundVariable(var), _) => { assert_eq!(var, PlainSymbol("?x".to_string())); }, + let err = algebrize(known, parsed).expect_err("algebrization should have failed"); + match err.downcast().expect("expected AlgebrizerError") { + AlgebrizerError::UnboundVariable(var) => { assert_eq!(var, PlainSymbol("?x".to_string())); }, x => panic!("expected Unbound Variable error, got {:?}", x), } } diff --git a/query-algebrizer/src/clauses/predicate.rs b/query-algebrizer/src/clauses/predicate.rs index add9eb8c..e58ecf7f 100644 --- a/query-algebrizer/src/clauses/predicate.rs +++ b/query-algebrizer/src/clauses/predicate.rs @@ -26,8 +26,8 @@ use clauses::ConjoiningClauses; use clauses::convert::ValueTypes; use errors::{ + AlgebrizerError, Result, - ErrorKind, }; use types::{ @@ -53,7 +53,7 @@ impl ConjoiningClauses { if let Some(op) = Inequality::from_datalog_operator(predicate.operator.0.as_str()) { self.apply_inequality(known, op, predicate) } else { - bail!(ErrorKind::UnknownFunction(predicate.operator.clone())) + bail!(AlgebrizerError::UnknownFunction(predicate.operator.clone())) } } @@ -69,7 +69,7 @@ impl ConjoiningClauses { pub(crate) fn apply_type_anno(&mut self, anno: &TypeAnnotation) -> Result<()> { match ValueType::from_keyword(&anno.value_type) { Some(value_type) => self.add_type_requirement(anno.variable.clone(), ValueTypeSet::of_one(value_type)), - None => bail!(ErrorKind::InvalidArgumentType(PlainSymbol::plain("type"), ValueTypeSet::any(), 2)), + None => bail!(AlgebrizerError::InvalidArgumentType(PlainSymbol::plain("type"), ValueTypeSet::any(), 2)), } Ok(()) } @@ -80,7 +80,7 @@ impl ConjoiningClauses { /// - Accumulates an `Inequality` constraint into the `wheres` list. pub(crate) fn apply_inequality(&mut self, known: Known, comparison: Inequality, predicate: Predicate) -> Result<()> { if predicate.args.len() != 2 { - bail!(ErrorKind::InvalidNumberOfArguments(predicate.operator.clone(), predicate.args.len(), 2)); + bail!(AlgebrizerError::InvalidNumberOfArguments(predicate.operator.clone(), predicate.args.len(), 2)); } // Go from arguments -- parser output -- to columns or values. @@ -97,13 +97,13 @@ impl ConjoiningClauses { let mut left_types = self.potential_types(known.schema, &left)? .intersection(&supported_types); if left_types.is_empty() { - bail!(ErrorKind::InvalidArgumentType(predicate.operator.clone(), supported_types, 0)); + bail!(AlgebrizerError::InvalidArgumentType(predicate.operator.clone(), supported_types, 0)); } let mut right_types = self.potential_types(known.schema, &right)? .intersection(&supported_types); if right_types.is_empty() { - bail!(ErrorKind::InvalidArgumentType(predicate.operator.clone(), supported_types, 1)); + bail!(AlgebrizerError::InvalidArgumentType(predicate.operator.clone(), supported_types, 1)); } // We would like to allow longs to compare to doubles. @@ -150,7 +150,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!(ErrorKind::InvalidArgumentType(predicate.operator.clone(), supported_types, 0)); + bail!(AlgebrizerError::InvalidArgumentType(predicate.operator.clone(), supported_types, 0)); } // These arguments must be variables or instant/numeric constants. diff --git a/query-algebrizer/src/clauses/resolve.rs b/query-algebrizer/src/clauses/resolve.rs index 8384a01d..87a18cf3 100644 --- a/query-algebrizer/src/clauses/resolve.rs +++ b/query-algebrizer/src/clauses/resolve.rs @@ -24,9 +24,8 @@ use mentat_query::{ use clauses::ConjoiningClauses; use errors::{ + AlgebrizerError, Result, - Error, - ErrorKind, }; use types::{ @@ -50,14 +49,14 @@ impl ConjoiningClauses { if v.value_type().is_numeric() { Ok(QueryValue::TypedValue(v)) } else { - bail!(ErrorKind::InputTypeDisagreement(var.name().clone(), ValueType::Long, v.value_type())); + bail!(AlgebrizerError::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(|| Error::from_kind(ErrorKind::UnboundVariable(var.name()))) + .ok_or_else(|| AlgebrizerError::UnboundVariable(var.name()).into()) } }, // Can't be an entid. @@ -71,7 +70,7 @@ impl ConjoiningClauses { Constant(NonIntegerConstant::BigInteger(_)) | Vector(_) => { self.mark_known_empty(EmptyBecause::NonNumericArgument); - bail!(ErrorKind::InvalidArgument(function.clone(), "numeric", position)); + bail!(AlgebrizerError::InvalidArgument(function.clone(), "numeric", position)) }, Constant(NonIntegerConstant::Float(f)) => Ok(QueryValue::TypedValue(TypedValue::Double(f))), } @@ -84,13 +83,13 @@ impl ConjoiningClauses { FnArg::Variable(var) => { match self.bound_value(&var) { Some(TypedValue::Instant(v)) => Ok(QueryValue::TypedValue(TypedValue::Instant(v))), - Some(v) => bail!(ErrorKind::InputTypeDisagreement(var.name().clone(), ValueType::Instant, v.value_type())), + Some(v) => bail!(AlgebrizerError::InputTypeDisagreement(var.name().clone(), ValueType::Instant, v.value_type())), None => { self.constrain_var_to_type(var.clone(), ValueType::Instant); self.column_bindings .get(&var) .and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone()))) - .ok_or_else(|| Error::from_kind(ErrorKind::UnboundVariable(var.name()))) + .ok_or_else(|| AlgebrizerError::UnboundVariable(var.name()).into()) }, } }, @@ -109,7 +108,7 @@ impl ConjoiningClauses { Constant(NonIntegerConstant::BigInteger(_)) | Vector(_) => { self.mark_known_empty(EmptyBecause::NonInstantArgument); - bail!(ErrorKind::InvalidArgumentType(function.clone(), ValueType::Instant.into(), position)); + bail!(AlgebrizerError::InvalidArgumentType(function.clone(), ValueType::Instant.into(), position)) }, } } @@ -128,14 +127,14 @@ impl ConjoiningClauses { self.column_bindings .get(&var) .and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone()))) - .ok_or_else(|| Error::from_kind(ErrorKind::UnboundVariable(var.name()))) + .ok_or_else(|| AlgebrizerError::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(|| Error::from_kind(ErrorKind::UnrecognizedIdent(i.to_string()))) + .ok_or_else(|| AlgebrizerError::UnrecognizedIdent(i.to_string()).into()) }, Constant(NonIntegerConstant::Boolean(_)) | Constant(NonIntegerConstant::Float(_)) | @@ -146,7 +145,7 @@ impl ConjoiningClauses { SrcVar(_) | Vector(_) => { self.mark_known_empty(EmptyBecause::NonEntityArgument); - bail!(ErrorKind::InvalidArgumentType(function.clone(), ValueType::Ref.into(), position)); + bail!(AlgebrizerError::InvalidArgumentType(function.clone(), ValueType::Ref.into(), position)) }, } @@ -173,7 +172,7 @@ impl ConjoiningClauses { self.column_bindings .get(&var) .and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone()))) - .ok_or_else(|| Error::from_kind(ErrorKind::UnboundVariable(var.name()))) + .ok_or_else(|| AlgebrizerError::UnboundVariable(var.name()).into()) }, } }, diff --git a/query-algebrizer/src/clauses/tx_log_api.rs b/query-algebrizer/src/clauses/tx_log_api.rs index 2fc7dce8..d7dbb686 100644 --- a/query-algebrizer/src/clauses/tx_log_api.rs +++ b/query-algebrizer/src/clauses/tx_log_api.rs @@ -25,8 +25,9 @@ use clauses::{ }; use errors::{ + AlgebrizerError, BindingError, - ErrorKind, + InvalidBinding, Result, }; @@ -60,17 +61,17 @@ 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!(ErrorKind::InvalidNumberOfArguments(where_fn.operator.clone(), where_fn.args.len(), 3)); + bail!(AlgebrizerError::InvalidNumberOfArguments(where_fn.operator.clone(), where_fn.args.len(), 3)); } if where_fn.binding.is_empty() { // The binding must introduce at least one bound variable. - bail!(ErrorKind::InvalidBinding(where_fn.operator.clone(), BindingError::NoBoundVariable)); + bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::NoBoundVariable)); } if !where_fn.binding.is_valid() { // The binding must not duplicate bound variables. - bail!(ErrorKind::InvalidBinding(where_fn.operator.clone(), BindingError::RepeatedBoundVariable)); + bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::RepeatedBoundVariable)); } // We should have exactly one binding. Destructure it now. @@ -78,7 +79,7 @@ impl ConjoiningClauses { Binding::BindRel(bindings) => { let bindings_count = bindings.len(); if bindings_count != 1 { - bail!(ErrorKind::InvalidBinding(where_fn.operator.clone(), + bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::InvalidNumberOfBindings { number: bindings_count, expected: 1, @@ -92,7 +93,7 @@ impl ConjoiningClauses { Binding::BindColl(v) => v, Binding::BindScalar(_) | Binding::BindTuple(_) => { - bail!(ErrorKind::InvalidBinding(where_fn.operator.clone(), BindingError::ExpectedBindRelOrBindColl)) + bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::ExpectedBindRelOrBindColl)) }, }; @@ -101,7 +102,7 @@ impl ConjoiningClauses { // TODO: process source variables. match args.next().unwrap() { FnArg::SrcVar(SrcVar::DefaultSrc) => {}, - _ => bail!(ErrorKind::InvalidArgument(where_fn.operator.clone(), "source variable", 0)), + _ => bail!(AlgebrizerError::InvalidArgument(where_fn.operator.clone(), "source variable", 0)), } let tx1 = self.resolve_tx_argument(&known.schema, &where_fn.operator, 1, args.next().unwrap())?; @@ -138,17 +139,17 @@ impl ConjoiningClauses { pub(crate) fn apply_tx_data(&mut self, known: Known, where_fn: WhereFn) -> Result<()> { if where_fn.args.len() != 2 { - bail!(ErrorKind::InvalidNumberOfArguments(where_fn.operator.clone(), where_fn.args.len(), 2)); + bail!(AlgebrizerError::InvalidNumberOfArguments(where_fn.operator.clone(), where_fn.args.len(), 2)); } if where_fn.binding.is_empty() { // The binding must introduce at least one bound variable. - bail!(ErrorKind::InvalidBinding(where_fn.operator.clone(), BindingError::NoBoundVariable)); + bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::NoBoundVariable)); } if !where_fn.binding.is_valid() { // The binding must not duplicate bound variables. - bail!(ErrorKind::InvalidBinding(where_fn.operator.clone(), BindingError::RepeatedBoundVariable)); + bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::RepeatedBoundVariable)); } // We should have at most five bindings. Destructure them now. @@ -156,7 +157,7 @@ impl ConjoiningClauses { Binding::BindRel(bindings) => { let bindings_count = bindings.len(); if bindings_count < 1 || bindings_count > 5 { - bail!(ErrorKind::InvalidBinding(where_fn.operator.clone(), + bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::InvalidNumberOfBindings { number: bindings.len(), expected: 5, @@ -166,7 +167,7 @@ impl ConjoiningClauses { }, Binding::BindScalar(_) | Binding::BindTuple(_) | - Binding::BindColl(_) => bail!(ErrorKind::InvalidBinding(where_fn.operator.clone(), BindingError::ExpectedBindRel)), + Binding::BindColl(_) => bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::ExpectedBindRel)), }; let mut bindings = bindings.into_iter(); let b_e = bindings.next().unwrap_or(VariableOrPlaceholder::Placeholder); @@ -180,7 +181,7 @@ impl ConjoiningClauses { // TODO: process source variables. match args.next().unwrap() { FnArg::SrcVar(SrcVar::DefaultSrc) => {}, - _ => bail!(ErrorKind::InvalidArgument(where_fn.operator.clone(), "source variable", 0)), + _ => bail!(AlgebrizerError::InvalidArgument(where_fn.operator.clone(), "source variable", 0)), } let tx = self.resolve_tx_argument(&known.schema, &where_fn.operator, 1, args.next().unwrap())?; diff --git a/query-algebrizer/src/clauses/where_fn.rs b/query-algebrizer/src/clauses/where_fn.rs index 7cf81188..845a6a64 100644 --- a/query-algebrizer/src/clauses/where_fn.rs +++ b/query-algebrizer/src/clauses/where_fn.rs @@ -17,7 +17,7 @@ use clauses::{ }; use errors::{ - ErrorKind, + AlgebrizerError, Result, }; @@ -39,7 +39,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!(ErrorKind::UnknownFunction(where_fn.operator.clone())), + _ => bail!(AlgebrizerError::UnknownFunction(where_fn.operator.clone())), } } } diff --git a/query-algebrizer/src/errors.rs b/query-algebrizer/src/errors.rs index 6e2e1154..bba74686 100644 --- a/query-algebrizer/src/errors.rs +++ b/query-algebrizer/src/errors.rs @@ -10,8 +10,18 @@ extern crate mentat_query; +use std; // To refer to std::result::Result. +use std::fmt; +use std::fmt::Display; + +use failure::{ + Backtrace, + Context, + Error, + Fail, +}; + use mentat_core::{ - EdnParseError, ValueType, ValueTypeSet, }; @@ -20,7 +30,53 @@ use self::mentat_query::{ PlainSymbol, }; -#[derive(Clone, Debug, Eq, PartialEq)] +pub type Result = std::result::Result; + +#[macro_export] +macro_rules! bail { + ($e:expr) => ( + return Err($e.into()); + ) +} + +#[derive(Debug)] +pub struct InvalidBinding { + pub function: PlainSymbol, + pub inner: Context +} + +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 { NoBoundVariable, UnexpectedBinding, @@ -40,98 +96,52 @@ pub enum BindingError { InvalidNumberOfBindings { number: usize, expected: usize }, } -error_chain! { - types { - Error, ErrorKind, ResultExt, Result; - } +#[derive(Debug, Fail)] +pub enum AlgebrizerError { + #[fail(display = "{} var {} is duplicated", _0, _1)] + DuplicateVariableError(PlainSymbol, &'static str), - foreign_links { - EdnParseError(EdnParseError); - } + #[fail(display = "unexpected FnArg")] + UnsupportedArgument, - errors { - UnsupportedArgument { - description("unexpected FnArg") - display("unexpected FnArg") - } + #[fail(display = "value of type {} provided for var {}, expected {}", _0, _1, _2)] + InputTypeDisagreement(PlainSymbol, ValueType, ValueType), - InputTypeDisagreement(var: PlainSymbol, declared: ValueType, provided: ValueType) { - description("input type disagreement") - display("value of type {} provided for var {}, expected {}", provided, var, declared) - } + #[fail(display = "invalid number of arguments to {}: expected {}, got {}.", _0, _1, _2)] + InvalidNumberOfArguments(PlainSymbol, usize, usize), - UnrecognizedIdent(ident: String) { - description("no entid found for ident") - display("no entid found for ident: {}", ident) - } + #[fail(display = "invalid argument to {}: expected {} in position {}.", _0, _1, _2)] + InvalidArgument(PlainSymbol, &'static str, usize), - UnknownFunction(name: PlainSymbol) { - description("no such function") - display("no function named {}", name) - } + #[fail(display = "invalid argument to {}: expected one of {:?} in position {}.", _0, _1, _2)] + InvalidArgumentType(PlainSymbol, ValueTypeSet, usize), - InvalidNumberOfArguments(function: PlainSymbol, number: usize, expected: usize) { - description("invalid number of arguments") - display("invalid number of arguments to {}: expected {}, got {}.", function, expected, number) - } + // TODO: flesh this out. + #[fail(display = "invalid expression in ground constant")] + InvalidGroundConstant, - UnboundVariable(name: PlainSymbol) { - description("unbound variable in order clause or function call") - display("unbound variable: {}", name) - } + #[fail(display = "invalid limit {} of type {}: expected natural number.", _0, _1)] + InvalidLimit(String, ValueType), - InvalidBinding(function: PlainSymbol, binding_error: BindingError) { - description("invalid binding") - display("invalid binding for {}: {:?}.", function, binding_error) - } + #[fail(display = "mismatched bindings in ground")] + GroundBindingsMismatch, - GroundBindingsMismatch { - description("mismatched bindings in ground") - display("mismatched bindings in ground") - } + #[fail(display = "no entid found for ident: {}", _0)] + UnrecognizedIdent(String), - InvalidGroundConstant { - // TODO: flesh this out. - description("invalid expression in ground constant") - display("invalid expression in ground constant") - } + #[fail(display = "no function named {}", _0)] + UnknownFunction(PlainSymbol), - InvalidArgument(function: PlainSymbol, expected: &'static str, position: usize) { - description("invalid argument") - display("invalid argument to {}: expected {} in position {}.", function, expected, position) - } + #[fail(display = ":limit var {} not present in :in", _0)] + UnknownLimitVar(PlainSymbol), - InvalidArgumentType(function: PlainSymbol, expected_types: ValueTypeSet, position: usize) { - description("invalid argument") - display("invalid argument to {}: expected one of {:?} in position {}.", function, expected_types, position) - } + #[fail(display = "unbound variable {} in order clause or function call", _0)] + UnboundVariable(PlainSymbol), - InvalidLimit(val: String, kind: ValueType) { - description("invalid limit") - display("invalid limit {} of type {}: expected natural number.", val, kind) - } + // TODO: flesh out. + #[fail(display = "non-matching variables in 'or' clause")] + NonMatchingVariablesInOrClause, - NonMatchingVariablesInOrClause { - // TODO: flesh out. - description("non-matching variables in 'or' clause") - display("non-matching variables in 'or' clause") - } - - NonMatchingVariablesInNotClause { - // TODO: flesh out. - description("non-matching variables in 'not' clause") - display("non-matching variables in 'not' clause") - } - - DuplicateVariableError(name: PlainSymbol, clause: &'static str) { - description("duplicate variables") - display("{} var {} is duplicated", clause, name) - } - - UnknownLimitVar(name: PlainSymbol) { - description(":limit var not present in :in") - display(":limit var {} not present in :in", name) - } - } + #[fail(display = "non-matching variables in 'not' clause")] + NonMatchingVariablesInNotClause, } - diff --git a/query-algebrizer/src/lib.rs b/query-algebrizer/src/lib.rs index 90704b7a..0a137110 100644 --- a/query-algebrizer/src/lib.rs +++ b/query-algebrizer/src/lib.rs @@ -8,10 +8,9 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#![recursion_limit="128"] +extern crate failure; -#[macro_use] -extern crate error_chain; +#[macro_use] extern crate failure_derive; extern crate mentat_core; extern crate mentat_query; @@ -20,6 +19,7 @@ use std::collections::BTreeSet; use std::ops::Sub; use std::rc::Rc; +#[macro_use] mod errors; mod types; mod validate; @@ -48,10 +48,10 @@ use mentat_query::{ }; pub use errors::{ + AlgebrizerError, BindingError, - Error, - ErrorKind, Result, + InvalidBinding, }; pub use clauses::{ @@ -216,7 +216,7 @@ fn validate_and_simplify_order(cc: &ConjoiningClauses, order: Option> // Fail if the var isn't bound by the query. if !cc.column_bindings.contains_key(&var) { - bail!(ErrorKind::UnboundVariable(var.name())); + bail!(AlgebrizerError::UnboundVariable(var.name())) } // Otherwise, determine if we also need to order by type… @@ -242,14 +242,14 @@ fn simplify_limit(mut query: AlgebraicQuery) -> Result { Some(TypedValue::Long(n)) => { if n <= 0 { // User-specified limits should always be natural numbers (> 0). - bail!(ErrorKind::InvalidLimit(n.to_string(), ValueType::Long)); + bail!(AlgebrizerError::InvalidLimit(n.to_string(), ValueType::Long)) } else { Some(Limit::Fixed(n as u64)) } }, Some(val) => { // Same. - bail!(ErrorKind::InvalidLimit(format!("{:?}", val), val.value_type())); + bail!(AlgebrizerError::InvalidLimit(format!("{:?}", val), val.value_type())) }, None => { // We know that the limit variable is mentioned in `:in`. @@ -357,7 +357,7 @@ impl FindQuery { for var in parsed.in_vars.into_iter() { if !set.insert(var.clone()) { - bail!(ErrorKind::DuplicateVariableError(var.name(), ":in")); + bail!(AlgebrizerError::DuplicateVariableError(var.name(), ":in")); } } @@ -369,7 +369,7 @@ impl FindQuery { for var in parsed.with.into_iter() { if !set.insert(var.clone()) { - bail!(ErrorKind::DuplicateVariableError(var.name(), ":with")); + bail!(AlgebrizerError::DuplicateVariableError(var.name(), ":with")); } } @@ -379,7 +379,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!(ErrorKind::UnknownLimitVar(v.name())); + bail!(AlgebrizerError::UnknownLimitVar(v.name())); } } diff --git a/query-algebrizer/src/validate.rs b/query-algebrizer/src/validate.rs index 5bac7fde..1dba97fb 100644 --- a/query-algebrizer/src/validate.rs +++ b/query-algebrizer/src/validate.rs @@ -19,7 +19,7 @@ use mentat_query::{ }; use errors::{ - ErrorKind, + AlgebrizerError, Result, }; @@ -56,7 +56,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!(ErrorKind::NonMatchingVariablesInOrClause); + bail!(AlgebrizerError::NonMatchingVariablesInOrClause) } } Ok(()) @@ -67,7 +67,7 @@ pub(crate) fn validate_or_join(or_join: &OrJoin) -> Result<()> { let var_set: BTreeSet = vars.iter().cloned().collect(); for clause in &or_join.clauses { if !var_set.is_subset(&clause.collect_mentioned_variables()) { - bail!(ErrorKind::NonMatchingVariablesInOrClause); + bail!(AlgebrizerError::NonMatchingVariablesInOrClause) } } Ok(()) @@ -85,7 +85,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 = vars.iter().cloned().collect(); if !var_set.is_subset(¬_join.collect_mentioned_variables()) { - bail!(ErrorKind::NonMatchingVariablesInNotClause); + bail!(AlgebrizerError::NonMatchingVariablesInNotClause) } Ok(()) }, diff --git a/query-algebrizer/tests/ground.rs b/query-algebrizer/tests/ground.rs index b7e8341f..d3e74faf 100644 --- a/query-algebrizer/tests/ground.rs +++ b/query-algebrizer/tests/ground.rs @@ -30,10 +30,10 @@ use mentat_query::{ }; use mentat_query_algebrizer::{ + AlgebrizerError, BindingError, ComputedTable, - Error, - ErrorKind, + InvalidBinding, Known, QueryInputs, }; @@ -256,8 +256,8 @@ fn test_ground_coll_heterogeneous_types() { let schema = prepopulated_schema(); let known = Known::for_schema(&schema); let e = bails(known, &q); - match e { - Error(ErrorKind::InvalidGroundConstant, _) => { + match e.downcast().expect("proper error") { + AlgebrizerError::InvalidGroundConstant => { }, _ => { panic!(); @@ -271,8 +271,8 @@ fn test_ground_rel_heterogeneous_types() { let schema = prepopulated_schema(); let known = Known::for_schema(&schema); let e = bails(known, &q); - match e { - Error(ErrorKind::InvalidGroundConstant, _) => { + match e.downcast().expect("proper error") { + AlgebrizerError::InvalidGroundConstant => { }, _ => { panic!(); @@ -285,11 +285,10 @@ fn test_ground_tuple_duplicate_vars() { let q = r#"[:find ?x :where [?x :foo/age ?v] [(ground [8 10]) [?x ?x]]]"#; let schema = prepopulated_schema(); let known = Known::for_schema(&schema); - let e = bails(known, &q); - match e { - Error(ErrorKind::InvalidBinding(v, e), _) => { - assert_eq!(v, PlainSymbol::plain("ground")); - assert_eq!(e, BindingError::RepeatedBoundVariable); + let e: InvalidBinding = bails(known, &q).downcast().expect("proper error"); + assert_eq!(e.function, PlainSymbol::plain("ground")); + match e.inner.get_context() { + &BindingError::RepeatedBoundVariable => { }, _ => { panic!(); @@ -302,11 +301,10 @@ fn test_ground_rel_duplicate_vars() { let q = r#"[:find ?x :where [?x :foo/age ?v] [(ground [[8 10]]) [[?x ?x]]]]"#; let schema = prepopulated_schema(); let known = Known::for_schema(&schema); - let e = bails(known, &q); - match e { - Error(ErrorKind::InvalidBinding(v, e), _) => { - assert_eq!(v, PlainSymbol::plain("ground")); - assert_eq!(e, BindingError::RepeatedBoundVariable); + let e: InvalidBinding = bails(known, &q).downcast().expect("expected InvalidBinding"); + assert_eq!(e.function, PlainSymbol::plain("ground")); + match e.inner.get_context() { + &BindingError::RepeatedBoundVariable => { }, _ => { panic!(); @@ -319,9 +317,9 @@ fn test_ground_nonexistent_variable_invalid() { let q = r#"[:find ?x ?e :where [?e _ ?x] (not [(ground 17) ?v])]"#; let schema = prepopulated_schema(); let known = Known::for_schema(&schema); - let e = bails(known, &q); + let e = bails(known, &q).downcast().expect("proper error"); match e { - Error(ErrorKind::UnboundVariable(PlainSymbol(v)), _) => { + AlgebrizerError::UnboundVariable(PlainSymbol(v)) => { assert_eq!(v, "?v".to_string()); }, _ => { @@ -343,9 +341,9 @@ fn test_unbound_input_variable_invalid() { let i = QueryInputs::new(types, BTreeMap::default()).expect("valid QueryInputs"); - let e = bails_with_inputs(known, &q, i); + let e = bails_with_inputs(known, &q, i).downcast().expect("proper error"); match e { - Error(ErrorKind::UnboundVariable(v), _) => { + AlgebrizerError::UnboundVariable(v) => { assert_eq!(v.0, "?x"); }, _ => { diff --git a/query-algebrizer/tests/predicate.rs b/query-algebrizer/tests/predicate.rs index 6aa0d929..7a2e4591 100644 --- a/query-algebrizer/tests/predicate.rs +++ b/query-algebrizer/tests/predicate.rs @@ -31,8 +31,8 @@ use mentat_query::{ }; use mentat_query_algebrizer::{ + AlgebrizerError, EmptyBecause, - ErrorKind, Known, QueryInputs, }; @@ -78,8 +78,8 @@ fn test_instant_predicates_require_instants() { :where [?e :foo/date ?t] [(> ?t "2017-06-16T00:56:41.257Z")]]"#; - match bails(known, query).0 { - ErrorKind::InvalidArgumentType(op, why, idx) => { + match bails(known, query).downcast().expect("proper cause") { + AlgebrizerError::InvalidArgumentType(op, why, idx) => { assert_eq!(op, PlainSymbol::plain(">")); assert_eq!(why, ValueTypeSet::of_numeric_and_instant_types()); assert_eq!(idx, 1); @@ -91,8 +91,8 @@ fn test_instant_predicates_require_instants() { :where [?e :foo/date ?t] [(> "2017-06-16T00:56:41.257Z", ?t)]]"#; - match bails(known, query).0 { - ErrorKind::InvalidArgumentType(op, why, idx) => { + match bails(known, query).downcast().expect("proper cause") { + AlgebrizerError::InvalidArgumentType(op, why, idx) => { assert_eq!(op, PlainSymbol::plain(">")); assert_eq!(why, ValueTypeSet::of_numeric_and_instant_types()); assert_eq!(idx, 0); // We get this right. diff --git a/query-algebrizer/tests/utils/mod.rs b/query-algebrizer/tests/utils/mod.rs index 9ca8185d..88bae48c 100644 --- a/query-algebrizer/tests/utils/mod.rs +++ b/query-algebrizer/tests/utils/mod.rs @@ -13,6 +13,9 @@ // this module will get warnings otherwise). #![allow(dead_code)] +extern crate failure; +use self::failure::Error; + use mentat_core::{ Attribute, Entid, @@ -26,7 +29,6 @@ use mentat_query::{ use mentat_query_algebrizer::{ ConjoiningClauses, - Error, Known, QueryInputs, algebrize,