Convert query-algebrizer/ to failure.
This commit is contained in:
parent
ce3ce1ccbf
commit
326fe881a0
17 changed files with 222 additions and 211 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"
|
||||||
|
|
||||||
[dependencies.mentat_core]
|
[dependencies.mentat_core]
|
||||||
path = "../core"
|
path = "../core"
|
||||||
|
|
|
@ -28,7 +28,7 @@ use clauses::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use errors::{
|
use errors::{
|
||||||
ErrorKind,
|
AlgebrizerError,
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -80,12 +80,12 @@ impl ValueTypes for FnArg {
|
||||||
|
|
||||||
&FnArg::Constant(NonIntegerConstant::BigInteger(_)) => {
|
&FnArg::Constant(NonIntegerConstant::BigInteger(_)) => {
|
||||||
// Not yet implemented.
|
// Not yet implemented.
|
||||||
bail!(ErrorKind::UnsupportedArgument)
|
bail!(AlgebrizerError::UnsupportedArgument)
|
||||||
},
|
},
|
||||||
|
|
||||||
// These don't make sense here. TODO: split FnArg into scalar and non-scalar…
|
// These don't make sense here. TODO: split FnArg into scalar and non-scalar…
|
||||||
&FnArg::Vector(_) |
|
&FnArg::Vector(_) |
|
||||||
&FnArg::SrcVar(_) => bail!(ErrorKind::UnsupportedArgument),
|
&FnArg::SrcVar(_) => bail!(AlgebrizerError::UnsupportedArgument),
|
||||||
|
|
||||||
// These are all straightforward.
|
// These are all straightforward.
|
||||||
&FnArg::Constant(NonIntegerConstant::Boolean(_)) => ValueTypeSet::of_one(ValueType::Boolean),
|
&FnArg::Constant(NonIntegerConstant::Boolean(_)) => ValueTypeSet::of_one(ValueType::Boolean),
|
||||||
|
@ -196,7 +196,7 @@ impl ConjoiningClauses {
|
||||||
FnArg::Variable(in_var) => {
|
FnArg::Variable(in_var) => {
|
||||||
// TODO: technically you could ground an existing variable inside the query….
|
// TODO: technically you could ground an existing variable inside the query….
|
||||||
if !self.input_variables.contains(&in_var) {
|
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) {
|
match self.bound_value(&in_var) {
|
||||||
// The type is already known if it's a bound variable….
|
// 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.
|
// 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
|
// 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.
|
// 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.
|
// These don't make sense here.
|
||||||
FnArg::Vector(_) |
|
FnArg::Vector(_) |
|
||||||
FnArg::SrcVar(_) => bail!(ErrorKind::InvalidGroundConstant),
|
FnArg::SrcVar(_) => bail!(AlgebrizerError::InvalidGroundConstant),
|
||||||
|
|
||||||
// These are all straightforward.
|
// These are all straightforward.
|
||||||
FnArg::Constant(NonIntegerConstant::Boolean(x)) => {
|
FnArg::Constant(NonIntegerConstant::Boolean(x)) => {
|
||||||
|
|
|
@ -30,8 +30,9 @@ use clauses::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use errors::{
|
use errors::{
|
||||||
|
AlgebrizerError,
|
||||||
BindingError,
|
BindingError,
|
||||||
ErrorKind,
|
InvalidBinding,
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,17 +54,17 @@ impl ConjoiningClauses {
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub(crate) fn apply_fulltext(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
|
pub(crate) fn apply_fulltext(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
|
||||||
if where_fn.args.len() != 3 {
|
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() {
|
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!(ErrorKind::InvalidBinding(where_fn.operator.clone(), BindingError::NoBoundVariable));
|
bail!(InvalidBinding::new(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!(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.
|
// We should have exactly four bindings. Destructure them now.
|
||||||
|
@ -71,17 +72,18 @@ 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!(ErrorKind::InvalidBinding(where_fn.operator.clone(),
|
bail!(InvalidBinding::new(where_fn.operator.clone(),
|
||||||
BindingError::InvalidNumberOfBindings {
|
BindingError::InvalidNumberOfBindings {
|
||||||
number: bindings.len(),
|
number: bindings.len(),
|
||||||
expected: 4,
|
expected: 4,
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
bindings
|
bindings
|
||||||
},
|
},
|
||||||
Binding::BindScalar(_) |
|
Binding::BindScalar(_) |
|
||||||
Binding::BindTuple(_) |
|
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 mut bindings = bindings.into_iter();
|
||||||
let b_entity = bindings.next().unwrap();
|
let b_entity = bindings.next().unwrap();
|
||||||
|
@ -94,7 +96,7 @@ impl ConjoiningClauses {
|
||||||
// TODO: process source variables.
|
// TODO: process source variables.
|
||||||
match args.next().unwrap() {
|
match args.next().unwrap() {
|
||||||
FnArg::SrcVar(SrcVar::DefaultSrc) => {},
|
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;
|
let schema = known.schema;
|
||||||
|
@ -114,10 +116,10 @@ impl ConjoiningClauses {
|
||||||
match self.bound_value(&v) {
|
match self.bound_value(&v) {
|
||||||
Some(TypedValue::Ref(entid)) => Some(entid),
|
Some(TypedValue::Ref(entid)) => Some(entid),
|
||||||
Some(tv) => {
|
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 => {
|
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
|
// 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
|
// attribute, is likely enough to be a coding error that we choose to bail instead of
|
||||||
// marking the pattern as known-empty.
|
// 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)
|
let attribute = schema.attribute_for_entid(a)
|
||||||
.cloned()
|
.cloned()
|
||||||
.ok_or(ErrorKind::InvalidArgument(where_fn.operator.clone(),
|
.ok_or(AlgebrizerError::InvalidArgument(where_fn.operator.clone(),
|
||||||
"attribute", 1))?;
|
"attribute", 1))?;
|
||||||
|
|
||||||
if !attribute.fulltext {
|
if !attribute.fulltext {
|
||||||
|
@ -169,18 +171,18 @@ impl ConjoiningClauses {
|
||||||
FnArg::Variable(in_var) => {
|
FnArg::Variable(in_var) => {
|
||||||
match self.bound_value(&in_var) {
|
match self.bound_value(&in_var) {
|
||||||
Some(t @ TypedValue::String(_)) => Either::Left(t),
|
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 => {
|
None => {
|
||||||
// Regardless of whether we'll be providing a string later, or the value
|
// Regardless of whether we'll be providing a string later, or the value
|
||||||
// comes from a column, it must be a string.
|
// comes from a column, it must be a string.
|
||||||
if self.known_type(&in_var) != Some(ValueType::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) {
|
if self.input_variables.contains(&in_var) {
|
||||||
// Sorry, we haven't implemented late binding.
|
// Sorry, we haven't implemented late binding.
|
||||||
// TODO: implement this.
|
// TODO: implement this.
|
||||||
bail!(ErrorKind::UnboundVariable((*in_var.0).clone()));
|
bail!(AlgebrizerError::UnboundVariable((*in_var.0).clone()))
|
||||||
} else {
|
} else {
|
||||||
// It must be bound earlier in the query. We already established that
|
// It must be bound earlier in the query. We already established that
|
||||||
// it must be a string column.
|
// it must be a string column.
|
||||||
|
@ -189,13 +191,13 @@ impl ConjoiningClauses {
|
||||||
.and_then(|bindings| bindings.get(0).cloned()) {
|
.and_then(|bindings| bindings.get(0).cloned()) {
|
||||||
Either::Right(binding)
|
Either::Right(binding)
|
||||||
} else {
|
} 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 {
|
let qv = match search {
|
||||||
|
@ -244,7 +246,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!(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.
|
// We bind the value ourselves. This handily takes care of substituting into existing uses.
|
||||||
|
|
|
@ -31,8 +31,9 @@ use clauses::{
|
||||||
use clauses::convert::ValueConversion;
|
use clauses::convert::ValueConversion;
|
||||||
|
|
||||||
use errors::{
|
use errors::{
|
||||||
|
AlgebrizerError,
|
||||||
BindingError,
|
BindingError,
|
||||||
ErrorKind,
|
InvalidBinding,
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -117,19 +118,19 @@ impl ConjoiningClauses {
|
||||||
|
|
||||||
pub(crate) fn apply_ground(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
|
pub(crate) fn apply_ground(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
|
||||||
if where_fn.args.len() != 1 {
|
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();
|
let mut args = where_fn.args.into_iter();
|
||||||
|
|
||||||
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!(ErrorKind::InvalidBinding(where_fn.operator.clone(), BindingError::NoBoundVariable));
|
bail!(InvalidBinding::new(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!(ErrorKind::InvalidBinding(where_fn.operator.clone(), BindingError::RepeatedBoundVariable));
|
bail!(InvalidBinding::new(where_fn.operator.clone(), BindingError::RepeatedBoundVariable));
|
||||||
}
|
}
|
||||||
|
|
||||||
let schema = known.schema;
|
let schema = known.schema;
|
||||||
|
@ -145,7 +146,7 @@ impl ConjoiningClauses {
|
||||||
// Just the same, but we bind more than one column at a time.
|
// Just the same, but we bind more than one column at a time.
|
||||||
if children.len() != places.len() {
|
if children.len() != places.len() {
|
||||||
// Number of arguments don't match the number of values. TODO: better error message.
|
// 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()) {
|
for (place, arg) in places.into_iter().zip(children.into_iter()) {
|
||||||
self.apply_ground_place(schema, place, arg)? // TODO: short-circuit on impossible.
|
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!
|
// are all in a single structure. That makes it substantially simpler!
|
||||||
(Binding::BindColl(var), FnArg::Vector(children)) => {
|
(Binding::BindColl(var), FnArg::Vector(children)) => {
|
||||||
if children.is_empty() {
|
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.
|
// 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()) &&
|
if accumulated_types.insert(tv.value_type()) &&
|
||||||
!accumulated_types.is_unit() {
|
!accumulated_types.is_unit() {
|
||||||
// Values not all of the same type.
|
// Values not all of the same type.
|
||||||
Some(Err(ErrorKind::InvalidGroundConstant.into()))
|
Some(Err(AlgebrizerError::InvalidGroundConstant.into()))
|
||||||
} else {
|
} else {
|
||||||
Some(Ok(tv))
|
Some(Ok(tv))
|
||||||
}
|
}
|
||||||
|
@ -208,7 +209,7 @@ impl ConjoiningClauses {
|
||||||
|
|
||||||
(Binding::BindRel(places), FnArg::Vector(rows)) => {
|
(Binding::BindRel(places), FnArg::Vector(rows)) => {
|
||||||
if rows.is_empty() {
|
if rows.is_empty() {
|
||||||
bail!(ErrorKind::InvalidGroundConstant);
|
bail!(AlgebrizerError::InvalidGroundConstant)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab the known types to which these args must conform, and track
|
// Grab the known types to which these args must conform, and track
|
||||||
|
@ -229,7 +230,7 @@ impl ConjoiningClauses {
|
||||||
|
|
||||||
if expected_width == 0 {
|
if expected_width == 0 {
|
||||||
// They can't all be placeholders.
|
// They can't all be placeholders.
|
||||||
bail!(ErrorKind::InvalidGroundConstant);
|
bail!(AlgebrizerError::InvalidGroundConstant)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accumulate values into `matrix` and types into `a_t_f_c`.
|
// Accumulate values into `matrix` and types into `a_t_f_c`.
|
||||||
|
@ -245,7 +246,7 @@ impl ConjoiningClauses {
|
||||||
FnArg::Vector(cols) => {
|
FnArg::Vector(cols) => {
|
||||||
// Make sure that every row is the same length.
|
// Make sure that every row is the same length.
|
||||||
if cols.len() != full_width {
|
if cols.len() != full_width {
|
||||||
bail!(ErrorKind::InvalidGroundConstant);
|
bail!(AlgebrizerError::InvalidGroundConstant)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: don't accumulate twice.
|
// TODO: don't accumulate twice.
|
||||||
|
@ -280,13 +281,13 @@ impl ConjoiningClauses {
|
||||||
let inserted = acc.insert(val.value_type());
|
let inserted = acc.insert(val.value_type());
|
||||||
if inserted && !acc.is_unit() {
|
if inserted && !acc.is_unit() {
|
||||||
// Heterogeneous types.
|
// Heterogeneous types.
|
||||||
bail!(ErrorKind::InvalidGroundConstant);
|
bail!(AlgebrizerError::InvalidGroundConstant)
|
||||||
}
|
}
|
||||||
matrix.push(val);
|
matrix.push(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
_ => bail!(ErrorKind::InvalidGroundConstant),
|
_ => bail!(AlgebrizerError::InvalidGroundConstant),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,7 +313,7 @@ impl ConjoiningClauses {
|
||||||
self.collect_named_bindings(schema, names, types, matrix);
|
self.collect_named_bindings(schema, names, types, matrix);
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
(_, _) => bail!(ErrorKind::InvalidGroundConstant),
|
(_, _) => bail!(AlgebrizerError::InvalidGroundConstant),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ use mentat_query::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use errors::{
|
use errors::{
|
||||||
ErrorKind,
|
AlgebrizerError,
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ impl QueryInputs {
|
||||||
let old = types.insert(var.clone(), t);
|
let old = types.insert(var.clone(), t);
|
||||||
if let Some(old) = old {
|
if let Some(old) = old {
|
||||||
if old != t {
|
if old != t {
|
||||||
bail!(ErrorKind::InputTypeDisagreement(var.name(), old, t));
|
bail!(AlgebrizerError::InputTypeDisagreement(var.name(), old, t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,8 +53,7 @@ use mentat_query::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use errors::{
|
use errors::{
|
||||||
Error,
|
AlgebrizerError,
|
||||||
ErrorKind,
|
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1014,7 +1013,7 @@ impl ConjoiningClauses {
|
||||||
|
|
||||||
let qa = self.extracted_types
|
let qa = self.extracted_types
|
||||||
.get(&var)
|
.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 {
|
self.wheres.add_intersection(ColumnConstraint::HasTypes {
|
||||||
value: qa.0.clone(),
|
value: qa.0.clone(),
|
||||||
value_types: types,
|
value_types: types,
|
||||||
|
|
|
@ -17,7 +17,7 @@ use mentat_query::{
|
||||||
use clauses::ConjoiningClauses;
|
use clauses::ConjoiningClauses;
|
||||||
|
|
||||||
use errors::{
|
use errors::{
|
||||||
ErrorKind,
|
AlgebrizerError,
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ impl ConjoiningClauses {
|
||||||
let col = self.column_bindings.get(&v).unwrap()[0].clone();
|
let col = self.column_bindings.get(&v).unwrap()[0].clone();
|
||||||
template.column_bindings.insert(v.clone(), vec![col]);
|
template.column_bindings.insert(v.clone(), vec![col]);
|
||||||
} else {
|
} else {
|
||||||
bail!(ErrorKind::UnboundVariable(v.name()));
|
bail!(AlgebrizerError::UnboundVariable(v.name()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,8 +111,7 @@ mod testing {
|
||||||
};
|
};
|
||||||
|
|
||||||
use errors::{
|
use errors::{
|
||||||
Error,
|
AlgebrizerError,
|
||||||
ErrorKind,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use types::{
|
use types::{
|
||||||
|
@ -553,10 +552,9 @@ mod testing {
|
||||||
:in ?y
|
:in ?y
|
||||||
: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).err();
|
let err = algebrize(known, parsed).expect_err("algebrization should have failed");
|
||||||
assert!(err.is_some());
|
match err.downcast().expect("expected AlgebrizerError") {
|
||||||
match err.unwrap() {
|
AlgebrizerError::UnboundVariable(var) => { assert_eq!(var, PlainSymbol("?x".to_string())); },
|
||||||
Error(ErrorKind::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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,8 @@ use clauses::ConjoiningClauses;
|
||||||
use clauses::convert::ValueTypes;
|
use clauses::convert::ValueTypes;
|
||||||
|
|
||||||
use errors::{
|
use errors::{
|
||||||
|
AlgebrizerError,
|
||||||
Result,
|
Result,
|
||||||
ErrorKind,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use types::{
|
use types::{
|
||||||
|
@ -53,7 +53,7 @@ impl ConjoiningClauses {
|
||||||
if let Some(op) = Inequality::from_datalog_operator(predicate.operator.0.as_str()) {
|
if let Some(op) = Inequality::from_datalog_operator(predicate.operator.0.as_str()) {
|
||||||
self.apply_inequality(known, op, predicate)
|
self.apply_inequality(known, op, predicate)
|
||||||
} else {
|
} 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<()> {
|
pub(crate) fn apply_type_anno(&mut self, anno: &TypeAnnotation) -> Result<()> {
|
||||||
match ValueType::from_keyword(&anno.value_type) {
|
match ValueType::from_keyword(&anno.value_type) {
|
||||||
Some(value_type) => self.add_type_requirement(anno.variable.clone(), ValueTypeSet::of_one(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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ impl ConjoiningClauses {
|
||||||
/// - Accumulates an `Inequality` constraint into the `wheres` list.
|
/// - Accumulates an `Inequality` constraint into the `wheres` list.
|
||||||
pub(crate) fn apply_inequality(&mut self, known: Known, comparison: Inequality, predicate: Predicate) -> Result<()> {
|
pub(crate) fn apply_inequality(&mut self, known: Known, comparison: Inequality, predicate: Predicate) -> Result<()> {
|
||||||
if predicate.args.len() != 2 {
|
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.
|
// 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)?
|
let mut left_types = self.potential_types(known.schema, &left)?
|
||||||
.intersection(&supported_types);
|
.intersection(&supported_types);
|
||||||
if left_types.is_empty() {
|
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)?
|
let mut right_types = self.potential_types(known.schema, &right)?
|
||||||
.intersection(&supported_types);
|
.intersection(&supported_types);
|
||||||
if right_types.is_empty() {
|
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.
|
// 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)?;
|
left_v = self.resolve_ref_argument(known.schema, &predicate.operator, 0, left)?;
|
||||||
right_v = self.resolve_ref_argument(known.schema, &predicate.operator, 1, right)?;
|
right_v = self.resolve_ref_argument(known.schema, &predicate.operator, 1, right)?;
|
||||||
} else {
|
} 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.
|
// These arguments must be variables or instant/numeric constants.
|
||||||
|
|
|
@ -24,9 +24,8 @@ use mentat_query::{
|
||||||
use clauses::ConjoiningClauses;
|
use clauses::ConjoiningClauses;
|
||||||
|
|
||||||
use errors::{
|
use errors::{
|
||||||
|
AlgebrizerError,
|
||||||
Result,
|
Result,
|
||||||
Error,
|
|
||||||
ErrorKind,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use types::{
|
use types::{
|
||||||
|
@ -50,14 +49,14 @@ impl ConjoiningClauses {
|
||||||
if v.value_type().is_numeric() {
|
if v.value_type().is_numeric() {
|
||||||
Ok(QueryValue::TypedValue(v))
|
Ok(QueryValue::TypedValue(v))
|
||||||
} else {
|
} else {
|
||||||
bail!(ErrorKind::InputTypeDisagreement(var.name().clone(), ValueType::Long, v.value_type()));
|
bail!(AlgebrizerError::InputTypeDisagreement(var.name().clone(), ValueType::Long, v.value_type()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.constrain_var_to_numeric(var.clone());
|
self.constrain_var_to_numeric(var.clone());
|
||||||
self.column_bindings
|
self.column_bindings
|
||||||
.get(&var)
|
.get(&var)
|
||||||
.and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone())))
|
.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.
|
// Can't be an entid.
|
||||||
|
@ -71,7 +70,7 @@ impl ConjoiningClauses {
|
||||||
Constant(NonIntegerConstant::BigInteger(_)) |
|
Constant(NonIntegerConstant::BigInteger(_)) |
|
||||||
Vector(_) => {
|
Vector(_) => {
|
||||||
self.mark_known_empty(EmptyBecause::NonNumericArgument);
|
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))),
|
Constant(NonIntegerConstant::Float(f)) => Ok(QueryValue::TypedValue(TypedValue::Double(f))),
|
||||||
}
|
}
|
||||||
|
@ -84,13 +83,13 @@ impl ConjoiningClauses {
|
||||||
FnArg::Variable(var) => {
|
FnArg::Variable(var) => {
|
||||||
match self.bound_value(&var) {
|
match self.bound_value(&var) {
|
||||||
Some(TypedValue::Instant(v)) => Ok(QueryValue::TypedValue(TypedValue::Instant(v))),
|
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 => {
|
None => {
|
||||||
self.constrain_var_to_type(var.clone(), ValueType::Instant);
|
self.constrain_var_to_type(var.clone(), ValueType::Instant);
|
||||||
self.column_bindings
|
self.column_bindings
|
||||||
.get(&var)
|
.get(&var)
|
||||||
.and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone())))
|
.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(_)) |
|
Constant(NonIntegerConstant::BigInteger(_)) |
|
||||||
Vector(_) => {
|
Vector(_) => {
|
||||||
self.mark_known_empty(EmptyBecause::NonInstantArgument);
|
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
|
self.column_bindings
|
||||||
.get(&var)
|
.get(&var)
|
||||||
.and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone())))
|
.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))),
|
EntidOrInteger(i) => Ok(QueryValue::TypedValue(TypedValue::Ref(i))),
|
||||||
IdentOrKeyword(i) => {
|
IdentOrKeyword(i) => {
|
||||||
schema.get_entid(&i)
|
schema.get_entid(&i)
|
||||||
.map(|known_entid| QueryValue::Entid(known_entid.into()))
|
.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::Boolean(_)) |
|
||||||
Constant(NonIntegerConstant::Float(_)) |
|
Constant(NonIntegerConstant::Float(_)) |
|
||||||
|
@ -146,7 +145,7 @@ impl ConjoiningClauses {
|
||||||
SrcVar(_) |
|
SrcVar(_) |
|
||||||
Vector(_) => {
|
Vector(_) => {
|
||||||
self.mark_known_empty(EmptyBecause::NonEntityArgument);
|
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
|
self.column_bindings
|
||||||
.get(&var)
|
.get(&var)
|
||||||
.and_then(|cols| cols.first().map(|col| QueryValue::Column(col.clone())))
|
.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())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -25,8 +25,9 @@ use clauses::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use errors::{
|
use errors::{
|
||||||
|
AlgebrizerError,
|
||||||
BindingError,
|
BindingError,
|
||||||
ErrorKind,
|
InvalidBinding,
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -60,17 +61,17 @@ impl ConjoiningClauses {
|
||||||
// transactions that impact one of the given attributes.
|
// transactions that impact one of the given attributes.
|
||||||
pub(crate) fn apply_tx_ids(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
|
pub(crate) fn apply_tx_ids(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
|
||||||
if where_fn.args.len() != 3 {
|
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() {
|
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!(ErrorKind::InvalidBinding(where_fn.operator.clone(), BindingError::NoBoundVariable));
|
bail!(InvalidBinding::new(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!(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.
|
// We should have exactly one binding. Destructure it now.
|
||||||
|
@ -78,7 +79,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!(ErrorKind::InvalidBinding(where_fn.operator.clone(),
|
bail!(InvalidBinding::new(where_fn.operator.clone(),
|
||||||
BindingError::InvalidNumberOfBindings {
|
BindingError::InvalidNumberOfBindings {
|
||||||
number: bindings_count,
|
number: bindings_count,
|
||||||
expected: 1,
|
expected: 1,
|
||||||
|
@ -92,7 +93,7 @@ impl ConjoiningClauses {
|
||||||
Binding::BindColl(v) => v,
|
Binding::BindColl(v) => v,
|
||||||
Binding::BindScalar(_) |
|
Binding::BindScalar(_) |
|
||||||
Binding::BindTuple(_) => {
|
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.
|
// TODO: process source variables.
|
||||||
match args.next().unwrap() {
|
match args.next().unwrap() {
|
||||||
FnArg::SrcVar(SrcVar::DefaultSrc) => {},
|
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())?;
|
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<()> {
|
pub(crate) fn apply_tx_data(&mut self, known: Known, where_fn: WhereFn) -> Result<()> {
|
||||||
if where_fn.args.len() != 2 {
|
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() {
|
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!(ErrorKind::InvalidBinding(where_fn.operator.clone(), BindingError::NoBoundVariable));
|
bail!(InvalidBinding::new(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!(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.
|
// We should have at most five bindings. Destructure them now.
|
||||||
|
@ -156,7 +157,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!(ErrorKind::InvalidBinding(where_fn.operator.clone(),
|
bail!(InvalidBinding::new(where_fn.operator.clone(),
|
||||||
BindingError::InvalidNumberOfBindings {
|
BindingError::InvalidNumberOfBindings {
|
||||||
number: bindings.len(),
|
number: bindings.len(),
|
||||||
expected: 5,
|
expected: 5,
|
||||||
|
@ -166,7 +167,7 @@ impl ConjoiningClauses {
|
||||||
},
|
},
|
||||||
Binding::BindScalar(_) |
|
Binding::BindScalar(_) |
|
||||||
Binding::BindTuple(_) |
|
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 mut bindings = bindings.into_iter();
|
||||||
let b_e = bindings.next().unwrap_or(VariableOrPlaceholder::Placeholder);
|
let b_e = bindings.next().unwrap_or(VariableOrPlaceholder::Placeholder);
|
||||||
|
@ -180,7 +181,7 @@ impl ConjoiningClauses {
|
||||||
// TODO: process source variables.
|
// TODO: process source variables.
|
||||||
match args.next().unwrap() {
|
match args.next().unwrap() {
|
||||||
FnArg::SrcVar(SrcVar::DefaultSrc) => {},
|
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())?;
|
let tx = self.resolve_tx_argument(&known.schema, &where_fn.operator, 1, args.next().unwrap())?;
|
||||||
|
|
|
@ -17,7 +17,7 @@ use clauses::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use errors::{
|
use errors::{
|
||||||
ErrorKind,
|
AlgebrizerError,
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ impl ConjoiningClauses {
|
||||||
"ground" => self.apply_ground(known, where_fn),
|
"ground" => self.apply_ground(known, where_fn),
|
||||||
"tx-data" => self.apply_tx_data(known, where_fn),
|
"tx-data" => self.apply_tx_data(known, where_fn),
|
||||||
"tx-ids" => self.apply_tx_ids(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())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,18 @@
|
||||||
|
|
||||||
extern crate mentat_query;
|
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::{
|
use mentat_core::{
|
||||||
EdnParseError,
|
|
||||||
ValueType,
|
ValueType,
|
||||||
ValueTypeSet,
|
ValueTypeSet,
|
||||||
};
|
};
|
||||||
|
@ -20,7 +30,53 @@ use self::mentat_query::{
|
||||||
PlainSymbol,
|
PlainSymbol,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! bail {
|
||||||
|
($e:expr) => (
|
||||||
|
return Err($e.into());
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
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,
|
||||||
|
@ -40,98 +96,52 @@ pub enum BindingError {
|
||||||
InvalidNumberOfBindings { number: usize, expected: usize },
|
InvalidNumberOfBindings { number: usize, expected: usize },
|
||||||
}
|
}
|
||||||
|
|
||||||
error_chain! {
|
#[derive(Debug, Fail)]
|
||||||
types {
|
pub enum AlgebrizerError {
|
||||||
Error, ErrorKind, ResultExt, Result;
|
#[fail(display = "{} var {} is duplicated", _0, _1)]
|
||||||
}
|
DuplicateVariableError(PlainSymbol, &'static str),
|
||||||
|
|
||||||
foreign_links {
|
#[fail(display = "unexpected FnArg")]
|
||||||
EdnParseError(EdnParseError);
|
UnsupportedArgument,
|
||||||
}
|
|
||||||
|
|
||||||
errors {
|
#[fail(display = "value of type {} provided for var {}, expected {}", _0, _1, _2)]
|
||||||
UnsupportedArgument {
|
InputTypeDisagreement(PlainSymbol, ValueType, ValueType),
|
||||||
description("unexpected FnArg")
|
|
||||||
display("unexpected FnArg")
|
|
||||||
}
|
|
||||||
|
|
||||||
InputTypeDisagreement(var: PlainSymbol, declared: ValueType, provided: ValueType) {
|
#[fail(display = "invalid number of arguments to {}: expected {}, got {}.", _0, _1, _2)]
|
||||||
description("input type disagreement")
|
InvalidNumberOfArguments(PlainSymbol, usize, usize),
|
||||||
display("value of type {} provided for var {}, expected {}", provided, var, declared)
|
|
||||||
}
|
|
||||||
|
|
||||||
UnrecognizedIdent(ident: String) {
|
#[fail(display = "invalid argument to {}: expected {} in position {}.", _0, _1, _2)]
|
||||||
description("no entid found for ident")
|
InvalidArgument(PlainSymbol, &'static str, usize),
|
||||||
display("no entid found for ident: {}", ident)
|
|
||||||
}
|
|
||||||
|
|
||||||
UnknownFunction(name: PlainSymbol) {
|
#[fail(display = "invalid argument to {}: expected one of {:?} in position {}.", _0, _1, _2)]
|
||||||
description("no such function")
|
InvalidArgumentType(PlainSymbol, ValueTypeSet, usize),
|
||||||
display("no function named {}", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
InvalidNumberOfArguments(function: PlainSymbol, number: usize, expected: usize) {
|
|
||||||
description("invalid number of arguments")
|
|
||||||
display("invalid number of arguments to {}: expected {}, got {}.", function, expected, number)
|
|
||||||
}
|
|
||||||
|
|
||||||
UnboundVariable(name: PlainSymbol) {
|
|
||||||
description("unbound variable in order clause or function call")
|
|
||||||
display("unbound variable: {}", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
InvalidBinding(function: PlainSymbol, binding_error: BindingError) {
|
|
||||||
description("invalid binding")
|
|
||||||
display("invalid binding for {}: {:?}.", function, binding_error)
|
|
||||||
}
|
|
||||||
|
|
||||||
GroundBindingsMismatch {
|
|
||||||
description("mismatched bindings in ground")
|
|
||||||
display("mismatched bindings in ground")
|
|
||||||
}
|
|
||||||
|
|
||||||
InvalidGroundConstant {
|
|
||||||
// TODO: flesh this out.
|
// TODO: flesh this out.
|
||||||
description("invalid expression in ground constant")
|
#[fail(display = "invalid expression in ground constant")]
|
||||||
display("invalid expression in ground constant")
|
InvalidGroundConstant,
|
||||||
}
|
|
||||||
|
|
||||||
InvalidArgument(function: PlainSymbol, expected: &'static str, position: usize) {
|
#[fail(display = "invalid limit {} of type {}: expected natural number.", _0, _1)]
|
||||||
description("invalid argument")
|
InvalidLimit(String, ValueType),
|
||||||
display("invalid argument to {}: expected {} in position {}.", function, expected, position)
|
|
||||||
}
|
|
||||||
|
|
||||||
InvalidArgumentType(function: PlainSymbol, expected_types: ValueTypeSet, position: usize) {
|
#[fail(display = "mismatched bindings in ground")]
|
||||||
description("invalid argument")
|
GroundBindingsMismatch,
|
||||||
display("invalid argument to {}: expected one of {:?} in position {}.", function, expected_types, position)
|
|
||||||
}
|
|
||||||
|
|
||||||
InvalidLimit(val: String, kind: ValueType) {
|
#[fail(display = "no entid found for ident: {}", _0)]
|
||||||
description("invalid limit")
|
UnrecognizedIdent(String),
|
||||||
display("invalid limit {} of type {}: expected natural number.", val, kind)
|
|
||||||
}
|
#[fail(display = "no function named {}", _0)]
|
||||||
|
UnknownFunction(PlainSymbol),
|
||||||
|
|
||||||
|
#[fail(display = ":limit var {} not present in :in", _0)]
|
||||||
|
UnknownLimitVar(PlainSymbol),
|
||||||
|
|
||||||
|
#[fail(display = "unbound variable {} in order clause or function call", _0)]
|
||||||
|
UnboundVariable(PlainSymbol),
|
||||||
|
|
||||||
NonMatchingVariablesInOrClause {
|
|
||||||
// TODO: flesh out.
|
// TODO: flesh out.
|
||||||
description("non-matching variables in 'or' clause")
|
#[fail(display = "non-matching variables in 'or' clause")]
|
||||||
display("non-matching variables in 'or' clause")
|
NonMatchingVariablesInOrClause,
|
||||||
}
|
|
||||||
|
|
||||||
NonMatchingVariablesInNotClause {
|
#[fail(display = "non-matching variables in 'not' clause")]
|
||||||
// TODO: flesh out.
|
NonMatchingVariablesInNotClause,
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,9 @@
|
||||||
// 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.
|
||||||
|
|
||||||
#![recursion_limit="128"]
|
extern crate failure;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use] extern crate failure_derive;
|
||||||
extern crate error_chain;
|
|
||||||
|
|
||||||
extern crate mentat_core;
|
extern crate mentat_core;
|
||||||
extern crate mentat_query;
|
extern crate mentat_query;
|
||||||
|
@ -20,6 +19,7 @@ use std::collections::BTreeSet;
|
||||||
use std::ops::Sub;
|
use std::ops::Sub;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
mod errors;
|
mod errors;
|
||||||
mod types;
|
mod types;
|
||||||
mod validate;
|
mod validate;
|
||||||
|
@ -48,10 +48,10 @@ use mentat_query::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use errors::{
|
pub use errors::{
|
||||||
|
AlgebrizerError,
|
||||||
BindingError,
|
BindingError,
|
||||||
Error,
|
|
||||||
ErrorKind,
|
|
||||||
Result,
|
Result,
|
||||||
|
InvalidBinding,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use clauses::{
|
pub use clauses::{
|
||||||
|
@ -216,7 +216,7 @@ fn validate_and_simplify_order(cc: &ConjoiningClauses, order: Option<Vec<Order>>
|
||||||
|
|
||||||
// Fail if the var isn't bound by the query.
|
// Fail if the var isn't bound by the query.
|
||||||
if !cc.column_bindings.contains_key(&var) {
|
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…
|
// Otherwise, determine if we also need to order by type…
|
||||||
|
@ -242,14 +242,14 @@ fn simplify_limit(mut query: AlgebraicQuery) -> Result<AlgebraicQuery> {
|
||||||
Some(TypedValue::Long(n)) => {
|
Some(TypedValue::Long(n)) => {
|
||||||
if n <= 0 {
|
if n <= 0 {
|
||||||
// User-specified limits should always be natural numbers (> 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 {
|
} else {
|
||||||
Some(Limit::Fixed(n as u64))
|
Some(Limit::Fixed(n as u64))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(val) => {
|
Some(val) => {
|
||||||
// Same.
|
// Same.
|
||||||
bail!(ErrorKind::InvalidLimit(format!("{:?}", val), val.value_type()));
|
bail!(AlgebrizerError::InvalidLimit(format!("{:?}", val), val.value_type()))
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
// We know that the limit variable is mentioned in `:in`.
|
// We know that the limit variable is mentioned in `:in`.
|
||||||
|
@ -357,7 +357,7 @@ impl FindQuery {
|
||||||
|
|
||||||
for var in parsed.in_vars.into_iter() {
|
for var in parsed.in_vars.into_iter() {
|
||||||
if !set.insert(var.clone()) {
|
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() {
|
for var in parsed.with.into_iter() {
|
||||||
if !set.insert(var.clone()) {
|
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`.
|
// Make sure that if we have `:limit ?x`, `?x` appears in `:in`.
|
||||||
if let Limit::Variable(ref v) = parsed.limit {
|
if let Limit::Variable(ref v) = parsed.limit {
|
||||||
if !in_vars.contains(v) {
|
if !in_vars.contains(v) {
|
||||||
bail!(ErrorKind::UnknownLimitVar(v.name()));
|
bail!(AlgebrizerError::UnknownLimitVar(v.name()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ use mentat_query::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use errors::{
|
use errors::{
|
||||||
ErrorKind,
|
AlgebrizerError,
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ pub(crate) fn validate_or_join(or_join: &OrJoin) -> Result<()> {
|
||||||
let template = clauses.next().unwrap().collect_mentioned_variables();
|
let template = clauses.next().unwrap().collect_mentioned_variables();
|
||||||
for clause in clauses {
|
for clause in clauses {
|
||||||
if template != clause.collect_mentioned_variables() {
|
if template != clause.collect_mentioned_variables() {
|
||||||
bail!(ErrorKind::NonMatchingVariablesInOrClause);
|
bail!(AlgebrizerError::NonMatchingVariablesInOrClause)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -67,7 +67,7 @@ pub(crate) fn validate_or_join(or_join: &OrJoin) -> Result<()> {
|
||||||
let var_set: BTreeSet<Variable> = vars.iter().cloned().collect();
|
let var_set: BTreeSet<Variable> = vars.iter().cloned().collect();
|
||||||
for clause in &or_join.clauses {
|
for clause in &or_join.clauses {
|
||||||
if !var_set.is_subset(&clause.collect_mentioned_variables()) {
|
if !var_set.is_subset(&clause.collect_mentioned_variables()) {
|
||||||
bail!(ErrorKind::NonMatchingVariablesInOrClause);
|
bail!(AlgebrizerError::NonMatchingVariablesInOrClause)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
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.
|
// The joined vars must each appear somewhere in the clause's mentioned variables.
|
||||||
let var_set: BTreeSet<Variable> = vars.iter().cloned().collect();
|
let var_set: BTreeSet<Variable> = vars.iter().cloned().collect();
|
||||||
if !var_set.is_subset(¬_join.collect_mentioned_variables()) {
|
if !var_set.is_subset(¬_join.collect_mentioned_variables()) {
|
||||||
bail!(ErrorKind::NonMatchingVariablesInNotClause);
|
bail!(AlgebrizerError::NonMatchingVariablesInNotClause)
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
|
|
|
@ -30,10 +30,10 @@ use mentat_query::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use mentat_query_algebrizer::{
|
use mentat_query_algebrizer::{
|
||||||
|
AlgebrizerError,
|
||||||
BindingError,
|
BindingError,
|
||||||
ComputedTable,
|
ComputedTable,
|
||||||
Error,
|
InvalidBinding,
|
||||||
ErrorKind,
|
|
||||||
Known,
|
Known,
|
||||||
QueryInputs,
|
QueryInputs,
|
||||||
};
|
};
|
||||||
|
@ -256,8 +256,8 @@ fn test_ground_coll_heterogeneous_types() {
|
||||||
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);
|
let e = bails(known, &q);
|
||||||
match e {
|
match e.downcast().expect("proper error") {
|
||||||
Error(ErrorKind::InvalidGroundConstant, _) => {
|
AlgebrizerError::InvalidGroundConstant => {
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
panic!();
|
panic!();
|
||||||
|
@ -271,8 +271,8 @@ fn test_ground_rel_heterogeneous_types() {
|
||||||
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);
|
let e = bails(known, &q);
|
||||||
match e {
|
match e.downcast().expect("proper error") {
|
||||||
Error(ErrorKind::InvalidGroundConstant, _) => {
|
AlgebrizerError::InvalidGroundConstant => {
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
panic!();
|
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 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 = bails(known, &q);
|
let e: InvalidBinding = bails(known, &q).downcast().expect("proper error");
|
||||||
match e {
|
assert_eq!(e.function, PlainSymbol::plain("ground"));
|
||||||
Error(ErrorKind::InvalidBinding(v, e), _) => {
|
match e.inner.get_context() {
|
||||||
assert_eq!(v, PlainSymbol::plain("ground"));
|
&BindingError::RepeatedBoundVariable => {
|
||||||
assert_eq!(e, BindingError::RepeatedBoundVariable);
|
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
panic!();
|
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 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 = bails(known, &q);
|
let e: InvalidBinding = bails(known, &q).downcast().expect("expected InvalidBinding");
|
||||||
match e {
|
assert_eq!(e.function, PlainSymbol::plain("ground"));
|
||||||
Error(ErrorKind::InvalidBinding(v, e), _) => {
|
match e.inner.get_context() {
|
||||||
assert_eq!(v, PlainSymbol::plain("ground"));
|
&BindingError::RepeatedBoundVariable => {
|
||||||
assert_eq!(e, BindingError::RepeatedBoundVariable);
|
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
panic!();
|
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 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);
|
let e = bails(known, &q).downcast().expect("proper error");
|
||||||
match e {
|
match e {
|
||||||
Error(ErrorKind::UnboundVariable(PlainSymbol(v)), _) => {
|
AlgebrizerError::UnboundVariable(PlainSymbol(v)) => {
|
||||||
assert_eq!(v, "?v".to_string());
|
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 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 {
|
match e {
|
||||||
Error(ErrorKind::UnboundVariable(v), _) => {
|
AlgebrizerError::UnboundVariable(v) => {
|
||||||
assert_eq!(v.0, "?x");
|
assert_eq!(v.0, "?x");
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -31,8 +31,8 @@ use mentat_query::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use mentat_query_algebrizer::{
|
use mentat_query_algebrizer::{
|
||||||
|
AlgebrizerError,
|
||||||
EmptyBecause,
|
EmptyBecause,
|
||||||
ErrorKind,
|
|
||||||
Known,
|
Known,
|
||||||
QueryInputs,
|
QueryInputs,
|
||||||
};
|
};
|
||||||
|
@ -78,8 +78,8 @@ 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).0 {
|
match bails(known, query).downcast().expect("proper cause") {
|
||||||
ErrorKind::InvalidArgumentType(op, why, idx) => {
|
AlgebrizerError::InvalidArgumentType(op, why, idx) => {
|
||||||
assert_eq!(op, PlainSymbol::plain(">"));
|
assert_eq!(op, PlainSymbol::plain(">"));
|
||||||
assert_eq!(why, ValueTypeSet::of_numeric_and_instant_types());
|
assert_eq!(why, ValueTypeSet::of_numeric_and_instant_types());
|
||||||
assert_eq!(idx, 1);
|
assert_eq!(idx, 1);
|
||||||
|
@ -91,8 +91,8 @@ fn test_instant_predicates_require_instants() {
|
||||||
: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).0 {
|
match bails(known, query).downcast().expect("proper cause") {
|
||||||
ErrorKind::InvalidArgumentType(op, why, idx) => {
|
AlgebrizerError::InvalidArgumentType(op, why, idx) => {
|
||||||
assert_eq!(op, PlainSymbol::plain(">"));
|
assert_eq!(op, PlainSymbol::plain(">"));
|
||||||
assert_eq!(why, ValueTypeSet::of_numeric_and_instant_types());
|
assert_eq!(why, ValueTypeSet::of_numeric_and_instant_types());
|
||||||
assert_eq!(idx, 0); // We get this right.
|
assert_eq!(idx, 0); // We get this right.
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
// 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,
|
||||||
|
@ -26,7 +29,6 @@ use mentat_query::{
|
||||||
|
|
||||||
use mentat_query_algebrizer::{
|
use mentat_query_algebrizer::{
|
||||||
ConjoiningClauses,
|
ConjoiningClauses,
|
||||||
Error,
|
|
||||||
Known,
|
Known,
|
||||||
QueryInputs,
|
QueryInputs,
|
||||||
algebrize,
|
algebrize,
|
||||||
|
|
Loading…
Reference in a new issue