Skip to content

Commit

Permalink
ok tests
Browse files Browse the repository at this point in the history
  • Loading branch information
andicuko committed Mar 4, 2024
1 parent fb64595 commit 7ba2477
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 50 deletions.
40 changes: 10 additions & 30 deletions src/dialect_translation/postgresql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,7 @@ mod tests {

use super::*;
use crate::{
builder::{Ready, With},
data_type::{DataType, Value as _},
display::Dot,
expr::Expr,
namer,
relation::{schema::Schema, Relation, TableBuilder},
sql::{parse, relation::QueryWithRelations},
builder::{Ready, With}, data_type::{DataType, Value as _}, display::Dot, expr::Expr, io::{postgresql, Database as _}, namer, relation::{schema::Schema, Relation, TableBuilder}, sql::{parse, relation::QueryWithRelations}
};
use std::sync::Arc;

Expand Down Expand Up @@ -154,36 +148,22 @@ mod tests {

#[test]
fn test_table_special() -> Result<()> {
let table: Relation = TableBuilder::new()
.path(["MY SPECIAL TABLE"])
.name("my_table")
.size(100)
.schema(
Schema::empty()
.with(("Id", DataType::integer_interval(0, 1000)))
.with(("Na.Me", DataType::text()))
.with(("inc&ome", DataType::float_interval(100.0, 200000.0)))
.with(("normal_col", DataType::text())),
)
.build();
let relations = Hierarchy::from([(["schema", "MY SPECIAL TABLE"], Arc::new(table))]);
let mut database = postgresql::test_database();
let relations = database.relations();
let query_str = r#"SELECT "Id", NORMAL_COL, "Na.Me" FROM "MY SPECIAL TABLE" ORDER BY "Id" "#;
let translator = PostgreSqlTranslator;
let query = parse_with_dialect(query_str, translator.dialect())?;
let query_with_relation = QueryWithRelations::new(&query, &relations);
let relation = Relation::try_from((query_with_relation, translator))?;
println!("\n {} \n", relation);
let rel_with_traslator = RelationWithTranslator(&relation, translator);
let retranslated = ast::Query::from(rel_with_traslator);
print!("{}", retranslated);
let translated = r#"
WITH "map_mou5" ("Id","normal_col","Na.Me") AS (
SELECT "Id" AS "Id", "normal_col" AS "normal_col", "Na.Me" AS "Na.Me" FROM "MY SPECIAL TABLE"
), "map_0swv"("Id","normal_col","Na.Me") AS (
SELECT "Id" AS "Id", "normal_col" AS "normal_col", "Na.Me" AS "Na.Me" FROM "map_mou5" ORDER BY "Id" ASC
) SELECT * FROM "map_0swv"
"#;
// assert_same_query_str(&retranslated.to_string(), translated);
let translated = ast::Query::from(rel_with_traslator);
print!("{}", translated);
_ = database
.query(translated.to_string().as_str())
.unwrap()
.iter()
.map(ToString::to_string);
Ok(())
}
}
54 changes: 54 additions & 0 deletions src/hierarchy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,25 @@ impl<T: Clone> Hierarchy<T> {
.filter_map(|(p, o)| Some((p.clone(), f(o)?)))
.collect()
}

/// It checks whether the path without the head is ambiguous or not.
/// It returns the full paths if the suffix is ambiguous.
pub fn ambiguous_subpaths(&self) -> Vec<Vec<String>> {
self.iter()
.filter_map(|(qualified_key, _)| {
let headless_path = if qualified_key.len() > 1 {
&qualified_key[1..]
} else {
&qualified_key[..]
};
if let Some(_) = self.get(&headless_path) {
None
} else {
Some(qualified_key.clone())
}
})
.collect()
}
}

impl<P: Path> Hierarchy<P> {
Expand Down Expand Up @@ -468,4 +487,39 @@ mod tests {
))
);
}

#[test]
fn test_ambiguous_paths() {
let values = Hierarchy::from([
(vec!["a", "b", "c"], 1),
(vec!["a", "b", "d"], 2),
(vec!["a", "c"], 3),
(vec!["a", "e"], 4),
(vec!["a", "e", "f"], 5),
(vec!["b", "c"], 6),
]);
let ambiguous = values.ambiguous_subpaths();
assert_eq!(ambiguous, vec![
vec!["a", "c"],
vec!["b", "c"],
]);

let values = Hierarchy::from([
(vec!["a", "b", "d"], 2),
(vec!["a", "b"], 4),
(vec!["a", "e", "f"], 5),
]);
let ambiguous: Vec<Vec<String>> = values.ambiguous_subpaths();
let empty: Vec<Vec<String>> = vec![];
assert_eq!(ambiguous, empty);

let values = Hierarchy::from([
(vec![], 2),
(vec!["b"], 4),
(vec!["c"], 5),
]);
let ambiguous: Vec<Vec<String>> = values.ambiguous_subpaths();
let empty: Vec<Vec<String>> = vec![];
assert_eq!(ambiguous, empty);
}
}
4 changes: 2 additions & 2 deletions src/relation/rewriting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,14 +234,14 @@ impl Join {
})
.collect::<Vec<_>>();

let fields = coalesced_fields
let all_fields = coalesced_fields
.into_iter()
.chain(remaining_fields.into_iter())
.collect::<Vec<_>>();

Relation::map()
.input(Relation::from(self))
.with_iter(fields)
.with_iter(all_fields)
.build()
}
}
Expand Down
1 change: 1 addition & 0 deletions src/rewriting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ mod tests {
println!("=================================\n{q}");
let query = parse(q).unwrap();
let relation = Relation::try_from(query.with(&relations)).unwrap();
relation.display_dot().unwrap();
let relation_with_dp_event = relation
.rewrite_with_differential_privacy(&relations, synthetic_data.clone(), privacy_unit.clone(), dp_parameters.clone())
.unwrap();
Expand Down
20 changes: 2 additions & 18 deletions src/sql/relation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,12 +270,12 @@ impl<'a, T: QueryToRelationTranslator + Copy + Clone> VisitedQueryRelations<'a,

// fully qualified input names -> fully qualified JOIN names
let all_fully_qualified_columns: Hierarchy<Identifier> = left_columns.with(right_columns);
let ambiguous_cols= ambiguous_columns(&all_fully_qualified_columns);
let ambiguous_cols= all_fully_qualified_columns.ambiguous_subpaths();
// fully qualified JOIN names -> non_ambiguous col names
let non_ambiguous_join_col_names: Hierarchy<String> = all_fully_qualified_columns
.iter()
.filter_map(|(k, v)| {
if ambiguous_cols.contains(&Identifier::from(k.clone()) ) {
if ambiguous_cols.contains(k) {
None
} else {
Some((v.clone(), k.clone().last().unwrap().to_string()))
Expand Down Expand Up @@ -754,22 +754,6 @@ impl<'a, T: QueryToRelationTranslator + Copy + Clone> TryFrom<(QueryWithRelation
}
}

/// It returns a vector of identifiers of ambiguous columns in a hierarchy of columns
/// It uses the properties of the Hierarchy: For ambiguous columns it checks
/// that Hierarchy::get returns None if using only the suffix of the path
pub fn ambiguous_columns(columns: &Hierarchy<Identifier>) -> Vec<Identifier> {
columns
.iter()
.filter_map(|(key, _)| {
if let Some(v) = columns.get(&[key.last().unwrap().as_str().to_string()]) {
None
} else {
Some(key.clone().into())
}
})
.collect()
}

/// A simple SQL query parser with dialect
pub fn parse_with_dialect<D: Dialect>(query: &str, dialect: D) -> Result<ast::Query> {
let mut tokenizer = Tokenizer::new(&dialect, query);
Expand Down

0 comments on commit 7ba2477

Please sign in to comment.