From 7c3f6f36980e6f96bad2c6ff96c1d0d77fa5ce85 Mon Sep 17 00:00:00 2001 From: Emily Toop Date: Fri, 31 Mar 2017 10:35:40 +0100 Subject: [PATCH] WIP - copy what we did for OR & OR Join --- query-algebrizer/src/cc.rs | 8 +++++-- query-algebrizer/src/errors.rs | 6 +++++ query-algebrizer/src/validate.rs | 33 +++++++++++++++++++++++++++ query/src/lib.rs | 39 ++++++++++++++++++++++++++++++-- 4 files changed, 82 insertions(+), 4 deletions(-) diff --git a/query-algebrizer/src/cc.rs b/query-algebrizer/src/cc.rs index f09ecf4e..7ff3f34b 100644 --- a/query-algebrizer/src/cc.rs +++ b/query-algebrizer/src/cc.rs @@ -498,11 +498,11 @@ impl ConjoiningClauses { match attribute { &PatternNonValuePlace::Ident(ref kw) => schema.attribute_for_ident(kw) - .when_not(|| self.mark_known_empty(EmptyBecause::InvalidAttributeIdent(kw.clone()))) + .(|| self.mark_known_empty(EmptyBecause::InvalidAttributeIdent(kw.clone()))) .and_then(|attribute| self.table_for_attribute_and_value(attribute, value)), &PatternNonValuePlace::Entid(id) => schema.attribute_for_entid(id) - .when_not(|| self.mark_known_empty(EmptyBecause::InvalidAttributeEntid(id))) + .(|| self.mark_known_empty(EmptyBecause::InvalidAttributeEntid(id))) .and_then(|attribute| self.table_for_attribute_and_value(attribute, value)), // TODO: In a prepared context, defer this decision until a second algebrizing phase. // #278. @@ -974,6 +974,10 @@ impl ConjoiningClauses { validate_or_join(&o) // TODO: apply. }, + WhereClause::NotJoin(n) => { + validate_not_join(&n) + // TODO: apply. + }, _ => unimplemented!(), } } diff --git a/query-algebrizer/src/errors.rs b/query-algebrizer/src/errors.rs index 742f54a9..6a59ecec 100644 --- a/query-algebrizer/src/errors.rs +++ b/query-algebrizer/src/errors.rs @@ -46,6 +46,12 @@ error_chain! { 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") + } } } diff --git a/query-algebrizer/src/validate.rs b/query-algebrizer/src/validate.rs index 5fea33c1..9e66242f 100644 --- a/query-algebrizer/src/validate.rs +++ b/query-algebrizer/src/validate.rs @@ -13,6 +13,7 @@ use std::collections::BTreeSet; use mentat_query::{ ContainsVariables, OrJoin, + NotJoin, Variable, WhereClause, UnifyVars, @@ -75,6 +76,37 @@ pub fn validate_or_join(or_join: &OrJoin) -> Result<()> { } } +pub fn validate_not_join(no_join: &NotJoin) -> Result<()> { + // Grab our mentioned variables and ensure that the rules are followed. + match not_join.unify_vars { + UnifyVars::Implicit => { + // Each 'leg' must have the same variable set. + if not_join.clauses.len() < 2 { + Ok(()) + } else { + let mut clauses = not_join.clauses.iter(); + let template = clauses.next().unwrap().collect_mentioned_variables(); + for clause in clauses { + if template != clause.collect_mentioned_variables() { + bail!(ErrorKind::NonMatchingVariablesInOrClause); + } + } + Ok(()) + } + }, + UnifyVars::Explicit(ref vars) => { + // Each leg must use the joined vars. + let var_set: BTreeSet = vars.iter().cloned().collect(); + for clause in ¬_join.clauses { + if !var_set.is_subset(&clause.collect_mentioned_variables()) { + bail!(ErrorKind::NonMatchingVariablesInOrClause); + } + } + Ok(()) + }, + } +} + #[cfg(test)] mod tests { extern crate mentat_core; @@ -93,6 +125,7 @@ mod tests { UnifyVars, Variable, WhereClause, + WhereNotClause, }; use self::mentat_query_parser::parse_find_string; diff --git a/query/src/lib.rs b/query/src/lib.rs index dc3126d8..2a93d453 100644 --- a/query/src/lib.rs +++ b/query/src/lib.rs @@ -508,6 +508,7 @@ pub enum UnifyVars { pub enum OrWhereClause { Clause(WhereClause), And(Vec), + Not(Vec), } #[derive(Clone, Debug, Eq, PartialEq)] @@ -516,11 +517,24 @@ pub struct OrJoin { pub clauses: Vec, } +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum WhereNotClause { + Clause(WhereClause), + And(Vec), + Or(Vec), +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct NotJoin { + pub unify_vars: UnifyVars, + pub clauses: Vec, +} + #[allow(dead_code)] #[derive(Clone, Debug, Eq, PartialEq)] pub enum WhereClause { Not, - NotJoin, + NotJoin(NotJoin), OrJoin(OrJoin), Pred(Predicate), WhereFn, @@ -557,7 +571,7 @@ impl ContainsVariables for WhereClause { &Pred(ref p) => p.accumulate_mentioned_variables(acc), &Pattern(ref p) => p.accumulate_mentioned_variables(acc), &Not => (), - &NotJoin => (), + &NotJoin(ref n) => n.accumulate_mentioned_variables(acc), &WhereFn => (), &RuleExpr => (), } @@ -570,6 +584,7 @@ impl ContainsVariables for OrWhereClause { match self { &And(ref clauses) => for clause in clauses { clause.accumulate_mentioned_variables(acc) }, &Clause(ref clause) => clause.accumulate_mentioned_variables(acc), + &Not(ref clause) => clause.accumulate_mentioned_variables(acc), } } } @@ -582,6 +597,26 @@ impl ContainsVariables for OrJoin { } } + +impl ContainsVariables for WhereNotClause { + fn accumulate_mentioned_variables(&self, acc: &mut BTreeSet) { + use WhereNotClause::*; + match self { + &And(ref clauses) => for clause in clauses { clause.accumulate_mentioned_variables(acc) }, + &Clause(ref clause) => clause.accumulate_mentioned_variables(acc), + &Or(ref clause) => clause.accumulate_mentioned_variables(acc), + } + } +} + +impl ContainsVariables for NotJoin { + fn accumulate_mentioned_variables(&self, acc: &mut BTreeSet) { + for clause in &self.clauses { + clause.accumulate_mentioned_variables(acc); + } + } +} + impl ContainsVariables for Predicate { fn accumulate_mentioned_variables(&self, acc: &mut BTreeSet) { for arg in &self.args {