diff --git a/Cargo.toml b/Cargo.toml index 77074dc3..6d06f907 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Nicolas Grislain "] name = "qrlew" -version = "0.4.11" +version = "0.4.12" edition = "2021" description = "Sarus Qrlew Engine" documentation = "https://docs.rs/qrlew" @@ -27,7 +27,7 @@ chrono = { version = "0.4", features = ["serde"] } sqlparser = "0.39.0" dot = "0.1" base64 = "0.21" -rusqlite = { version = "0.29", features = ["chrono"], optional = true } +rusqlite = { version = "0.30", features = ["chrono"], optional = true } postgres = { version = "0.19", features = ["with-chrono-0_4"] } r2d2 = "0.8" r2d2_postgres = "0.18" diff --git a/src/protection/mod.rs b/src/protection/mod.rs index 018c80ab..4b1335f7 100644 --- a/src/protection/mod.rs +++ b/src/protection/mod.rs @@ -581,31 +581,31 @@ mod tests { // assert!(relation.schema()[0].name() != "peid"); } - // #[test] - // fn test_table_protection_from_field_paths() { - // let database = postgresql::test_database(); - // let relations = database.relations(); - // let table = relations - // .get(&["item_table".into()]) - // .unwrap() - // .as_ref() - // .clone(); - // let protection = Protection::from(( - // &relations, - // vec![( - // "item_table", - // vec![("order_id", "order_table", "id")], - // "date", - // )], - // Strategy::Soft, - // )); - // // Table - // let table = protection.table(table.try_into().unwrap()).unwrap(); - // table.display_dot().unwrap(); - // println!("Schema protected = {}", table.schema()); - // println!("Query protected = {}", ast::Query::from(&*table)); - // assert_eq!(table.schema()[0].name(), ProtectedEntity::protected_entity_id()) - // } + #[test] + fn test_table_protection_from_field_paths() { + let database = postgresql::test_database(); + let relations = database.relations(); + let table = relations + .get(&["item_table".into()]) + .unwrap() + .as_ref() + .clone(); + let protection = Protection::from(( + &relations, + vec![( + "item_table", + vec![("order_id", "order_table", "id")], + "date", + )], + Strategy::Soft, + )); + // Table + let table = protection.table(&table.try_into().unwrap()).unwrap(); + table.display_dot().unwrap(); + println!("Schema protected = {}", table.schema()); + println!("Query protected = {}", ast::Query::from(&*table)); + assert_eq!(table.schema()[0].name(), ProtectedEntity::protected_entity_id()) + } #[test] fn test_join_protection() { diff --git a/src/rewriting/mod.rs b/src/rewriting/mod.rs index 1d025c00..165fd7f6 100644 --- a/src/rewriting/mod.rs +++ b/src/rewriting/mod.rs @@ -26,8 +26,8 @@ use crate::{ }; use rewriting_rule::{ - BaseRewriter, BaseRewritingRulesEliminator, BaseRewritingRulesSelector, - BaseRewritingRulesSetter, BaseScore, + Rewriter, RewritingRulesEliminator, RewritingRulesSelector, + RewritingRulesSetter, Score, }; #[derive(Debug)] @@ -73,20 +73,21 @@ impl Relation { protected_entity: ProtectedEntity, budget: Budget, ) -> Result { - let relation_with_rules = self.set_rewriting_rules(BaseRewritingRulesSetter::new( + let relation_with_rules = self.set_rewriting_rules(RewritingRulesSetter::new( + relations, synthetic_data, protected_entity, budget, )); let relation_with_rules = - relation_with_rules.map_rewriting_rules(BaseRewritingRulesEliminator); + relation_with_rules.map_rewriting_rules(RewritingRulesEliminator); relation_with_rules - .select_rewriting_rules(BaseRewritingRulesSelector) + .select_rewriting_rules(RewritingRulesSelector) .into_iter() .filter_map(|rwrr| match rwrr.attributes().output() { Property::Public | Property::ProtectedEntityPreserving => Some(( - rwrr.rewrite(BaseRewriter::new(relations)), - rwrr.accept(BaseScore), + rwrr.rewrite(Rewriter::new(relations)), + rwrr.accept(Score), )), property => None, }) @@ -102,20 +103,21 @@ impl Relation { protected_entity: ProtectedEntity, budget: Budget, ) -> Result { - let relation_with_rules = self.set_rewriting_rules(BaseRewritingRulesSetter::new( + let relation_with_rules = self.set_rewriting_rules(RewritingRulesSetter::new( + relations, synthetic_data, protected_entity, budget, )); let relation_with_rules = - relation_with_rules.map_rewriting_rules(BaseRewritingRulesEliminator); + relation_with_rules.map_rewriting_rules(RewritingRulesEliminator); relation_with_rules - .select_rewriting_rules(BaseRewritingRulesSelector) + .select_rewriting_rules(RewritingRulesSelector) .into_iter() .filter_map(|rwrr| match rwrr.attributes().output() { Property::Public | Property::Published | Property::DifferentiallyPrivate => Some(( - rwrr.rewrite(BaseRewriter::new(relations)), - rwrr.accept(BaseScore), + rwrr.rewrite(Rewriter::new(relations)), + rwrr.accept(Score), )), property => None, }) diff --git a/src/rewriting/rewriting_rule.rs b/src/rewriting/rewriting_rule.rs index d6a3346b..f5cd7623 100644 --- a/src/rewriting/rewriting_rule.rs +++ b/src/rewriting/rewriting_rule.rs @@ -575,20 +575,22 @@ impl<'a> RelationWithRewritingRule<'a> { // # Implement various rewriting rules visitors /// A basic rewriting rule setter -pub struct BaseRewritingRulesSetter { +pub struct RewritingRulesSetter<'a> { + relations: &'a Hierarchy>, synthetic_data: SyntheticData, protected_entity: ProtectedEntity, budget: Budget, } -// TODO implement this properly -impl BaseRewritingRulesSetter { +impl<'a> RewritingRulesSetter<'a> { pub fn new( + relations: &'a Hierarchy>, synthetic_data: SyntheticData, protected_entity: ProtectedEntity, budget: Budget, - ) -> BaseRewritingRulesSetter { - BaseRewritingRulesSetter { + ) -> RewritingRulesSetter { + RewritingRulesSetter { + relations, synthetic_data, protected_entity, budget, @@ -596,21 +598,29 @@ impl BaseRewritingRulesSetter { } } -impl<'a> SetRewritingRulesVisitor<'a> for BaseRewritingRulesSetter { +impl<'a> SetRewritingRulesVisitor<'a> for RewritingRulesSetter<'a> { fn table(&self, table: &'a Table) -> Vec { - vec![ - RewritingRule::new(vec![], Property::Private, Parameters::None), - RewritingRule::new( - vec![], - Property::SyntheticData, - Parameters::SyntheticData(self.synthetic_data.clone()), - ), - RewritingRule::new( - vec![], - Property::ProtectedEntityPreserving, - Parameters::ProtectedEntity(self.protected_entity.clone()), - ), - ] + if self.protected_entity.iter() + .find(|(name, _field_path)| table.name() == self.relations[name.as_str()].name()) + .is_some() { + vec![ + RewritingRule::new(vec![], Property::Private, Parameters::None), + RewritingRule::new( + vec![], + Property::SyntheticData, + Parameters::SyntheticData(self.synthetic_data.clone()), + ), + RewritingRule::new( + vec![], + Property::ProtectedEntityPreserving, + Parameters::ProtectedEntity(self.protected_entity.clone()), + ), + ] + } else { + vec![ + RewritingRule::new(vec![], Property::Public, Parameters::None), + ] + } } fn map(&self, map: &'a Map, input: Arc>) -> Vec { @@ -651,7 +661,6 @@ impl<'a> SetRewritingRulesVisitor<'a> for BaseRewritingRulesSetter { Property::Published, Parameters::None, ), - RewritingRule::new(vec![Property::Public], Property::Public, Parameters::None), RewritingRule::new( vec![Property::ProtectedEntityPreserving], Property::DifferentiallyPrivate, @@ -775,9 +784,9 @@ impl<'a> SetRewritingRulesVisitor<'a> for BaseRewritingRulesSetter { } /// A basic rewriting rule eliminator -pub struct BaseRewritingRulesEliminator; // TODO implement this properly +pub struct RewritingRulesEliminator; -impl<'a> MapRewritingRulesVisitor<'a> for BaseRewritingRulesEliminator { +impl<'a> MapRewritingRulesVisitor<'a> for RewritingRulesEliminator { fn table(&self, table: &'a Table, rewriting_rules: &'a [RewritingRule]) -> Vec { rewriting_rules.into_iter().cloned().collect() } @@ -882,9 +891,9 @@ impl<'a> MapRewritingRulesVisitor<'a> for BaseRewritingRulesEliminator { } /// A basic rewriting rule selector -pub struct BaseRewritingRulesSelector; // TODO implement this properly +pub struct RewritingRulesSelector; -impl<'a> SelectRewritingRuleVisitor<'a> for BaseRewritingRulesSelector { +impl<'a> SelectRewritingRuleVisitor<'a> for RewritingRulesSelector { fn table(&self, table: &'a Table, rewriting_rules: &'a [RewritingRule]) -> Vec { rewriting_rules.into_iter().cloned().collect() } @@ -959,9 +968,9 @@ impl<'a> SelectRewritingRuleVisitor<'a> for BaseRewritingRulesSelector { } /// Compute the number of DP ops -pub struct BaseBudgetDispatcher; +pub struct BudgetDispatcher; -impl<'a> Visitor<'a, RelationWithRewritingRule<'a>, usize> for BaseBudgetDispatcher { +impl<'a> Visitor<'a, RelationWithRewritingRule<'a>, usize> for BudgetDispatcher { fn visit( &self, acceptor: &'a RelationWithRewritingRule<'a>, @@ -978,9 +987,9 @@ impl<'a> Visitor<'a, RelationWithRewritingRule<'a>, usize> for BaseBudgetDispatc } /// Compute the score -pub struct BaseScore; +pub struct Score; -impl<'a> Visitor<'a, RelationWithRewritingRule<'a>, f64> for BaseScore { +impl<'a> Visitor<'a, RelationWithRewritingRule<'a>, f64> for Score { fn visit( &self, acceptor: &'a RelationWithRewritingRule<'a>, @@ -1000,15 +1009,15 @@ impl<'a> Visitor<'a, RelationWithRewritingRule<'a>, f64> for BaseScore { } } -pub struct BaseRewriter<'a>(&'a Hierarchy>); // TODO implement this properly +pub struct Rewriter<'a>(&'a Hierarchy>); // TODO implement this properly -impl<'a> BaseRewriter<'a> { - pub fn new(relations: &'a Hierarchy>) -> BaseRewriter<'a> { - BaseRewriter(relations) +impl<'a> Rewriter<'a> { + pub fn new(relations: &'a Hierarchy>) -> Rewriter<'a> { + Rewriter(relations) } } -impl<'a> RewriteVisitor<'a> for BaseRewriter<'a> { +impl<'a> RewriteVisitor<'a> for Rewriter<'a> { fn table( &self, table: &'a Table, @@ -1282,21 +1291,22 @@ mod tests { let relation = Relation::try_from(query.with(&relations)).unwrap(); relation.display_dot().unwrap(); // Add rewritting rules - let relation_with_rules = relation.set_rewriting_rules(BaseRewritingRulesSetter::new( + let relation_with_rules = relation.set_rewriting_rules(RewritingRulesSetter::new( + &relations, synthetic_data, protected_entity, budget, )); relation_with_rules.display_dot().unwrap(); let relation_with_rules = - relation_with_rules.map_rewriting_rules(BaseRewritingRulesEliminator); + relation_with_rules.map_rewriting_rules(RewritingRulesEliminator); relation_with_rules.display_dot().unwrap(); - for rwrr in relation_with_rules.select_rewriting_rules(BaseRewritingRulesSelector) { + for rwrr in relation_with_rules.select_rewriting_rules(RewritingRulesSelector) { rwrr.display_dot().unwrap(); - let num_dp = rwrr.accept(BaseBudgetDispatcher); + let num_dp = rwrr.accept(BudgetDispatcher); println!("DEBUG SPLIT BUDGET IN {}", num_dp); - println!("DEBUG SCORE {}", rwrr.accept(BaseScore)); - let relation_with_private_query = rwrr.rewrite(BaseRewriter(&relations)); + println!("DEBUG SCORE {}", rwrr.accept(Score)); + let relation_with_private_query = rwrr.rewrite(Rewriter(&relations)); println!( "PrivateQuery: {:?}", relation_with_private_query.private_query() @@ -1344,21 +1354,22 @@ mod tests { let relation = Relation::try_from(query.with(&relations)).unwrap(); relation.display_dot().unwrap(); // Add rewritting rules - let relation_with_rules = relation.set_rewriting_rules(BaseRewritingRulesSetter::new( + let relation_with_rules = relation.set_rewriting_rules(RewritingRulesSetter::new( + &relations, synthetic_data, protected_entity, budget, )); relation_with_rules.display_dot().unwrap(); let relation_with_rules = - relation_with_rules.map_rewriting_rules(BaseRewritingRulesEliminator); + relation_with_rules.map_rewriting_rules(RewritingRulesEliminator); relation_with_rules.display_dot().unwrap(); - for rwrr in relation_with_rules.select_rewriting_rules(BaseRewritingRulesSelector) { + for rwrr in relation_with_rules.select_rewriting_rules(RewritingRulesSelector) { rwrr.display_dot().unwrap(); - let num_dp = rwrr.accept(BaseBudgetDispatcher); + let num_dp = rwrr.accept(BudgetDispatcher); println!("DEBUG SPLIT BUDGET IN {}", num_dp); - println!("DEBUG SCORE {}", rwrr.accept(BaseScore)); - let relation_with_private_query = rwrr.rewrite(BaseRewriter(&relations)); + println!("DEBUG SCORE {}", rwrr.accept(Score)); + let relation_with_private_query = rwrr.rewrite(Rewriter(&relations)); println!( "PrivateQuery: {:?}", relation_with_private_query.private_query() @@ -1403,21 +1414,22 @@ mod tests { let relation = Relation::try_from(query.with(&relations)).unwrap(); relation.display_dot().unwrap(); // Add rewritting rules - let relation_with_rules = relation.set_rewriting_rules(BaseRewritingRulesSetter::new( + let relation_with_rules = relation.set_rewriting_rules(RewritingRulesSetter::new( + &relations, synthetic_data, protected_entity, budget, )); relation_with_rules.display_dot().unwrap(); let relation_with_rules = - relation_with_rules.map_rewriting_rules(BaseRewritingRulesEliminator); + relation_with_rules.map_rewriting_rules(RewritingRulesEliminator); relation_with_rules.display_dot().unwrap(); - for rwrr in relation_with_rules.select_rewriting_rules(BaseRewritingRulesSelector) { + for rwrr in relation_with_rules.select_rewriting_rules(RewritingRulesSelector) { rwrr.display_dot().unwrap(); - let num_dp = rwrr.accept(BaseBudgetDispatcher); + let num_dp = rwrr.accept(BudgetDispatcher); println!("DEBUG SPLIT BUDGET IN {}", num_dp); - println!("DEBUG SCORE {}", rwrr.accept(BaseScore)); - let relation_with_private_query = rwrr.rewrite(BaseRewriter(&relations)); + println!("DEBUG SCORE {}", rwrr.accept(Score)); + let relation_with_private_query = rwrr.rewrite(Rewriter(&relations)); println!( "PrivateQuery: {:?}", relation_with_private_query.private_query()