Part 5: add more tests for complex or.

This commit is contained in:
Richard Newman 2017-04-11 14:44:25 -07:00
parent bca8b7e322
commit 758ab8b476

View file

@ -710,13 +710,23 @@ mod testing {
SourceAlias, SourceAlias,
}; };
use algebrize; use {
algebrize,
algebrize_with_counter,
};
fn alg(schema: &Schema, input: &str) -> ConjoiningClauses { fn alg(schema: &Schema, input: &str) -> ConjoiningClauses {
let parsed = parse_find_string(input).expect("parse failed"); let parsed = parse_find_string(input).expect("parse failed");
algebrize(schema.into(), parsed).expect("algebrize failed").cc algebrize(schema.into(), parsed).expect("algebrize failed").cc
} }
/// Algebrize with a starting counter, so we can compare inner queries by algebrizing a
/// simpler version.
fn alg_c(schema: &Schema, counter: usize, input: &str) -> ConjoiningClauses {
let parsed = parse_find_string(input).expect("parse failed");
algebrize_with_counter(schema.into(), parsed, counter).expect("algebrize failed").cc
}
fn compare_ccs(left: ConjoiningClauses, right: ConjoiningClauses) { fn compare_ccs(left: ConjoiningClauses, right: ConjoiningClauses) {
assert_eq!(left.wheres, right.wheres); assert_eq!(left.wheres, right.wheres);
assert_eq!(left.from, right.from); assert_eq!(left.from, right.from);
@ -927,8 +937,6 @@ mod testing {
// These two are not equivalent: // These two are not equivalent:
// [:find ?x :where [?x :foo/bar ?y] (or-join [?x] [?x :foo/baz ?y])] // [:find ?x :where [?x :foo/bar ?y] (or-join [?x] [?x :foo/baz ?y])]
// [:find ?x :where [?x :foo/bar ?y] [?x :foo/baz ?y]] // [:find ?x :where [?x :foo/bar ?y] [?x :foo/baz ?y]]
// TODO: fixme
/*
#[test] #[test]
fn test_unit_or_join_doesnt_flatten() { fn test_unit_or_join_doesnt_flatten() {
let schema = prepopulated_schema(); let schema = prepopulated_schema();
@ -939,30 +947,27 @@ mod testing {
let vx = Variable::from_valid_name("?x"); let vx = Variable::from_valid_name("?x");
let vy = Variable::from_valid_name("?y"); let vy = Variable::from_valid_name("?y");
let d0 = "datoms00".to_string(); let d0 = "datoms00".to_string();
let d1 = "datoms01".to_string(); let c0 = "c00".to_string();
let c0x = QualifiedAlias::new(c0.clone(), VariableColumn::Variable(vx.clone()));
let d0e = QualifiedAlias::new(d0.clone(), DatomsColumn::Entity); let d0e = QualifiedAlias::new(d0.clone(), DatomsColumn::Entity);
let d0a = QualifiedAlias::new(d0.clone(), DatomsColumn::Attribute); let d0a = QualifiedAlias::new(d0.clone(), DatomsColumn::Attribute);
let d0v = QualifiedAlias::new(d0.clone(), DatomsColumn::Value); let d0v = QualifiedAlias::new(d0.clone(), DatomsColumn::Value);
let d1e = QualifiedAlias::new(d1.clone(), DatomsColumn::Entity);
let d1a = QualifiedAlias::new(d1.clone(), DatomsColumn::Attribute);
let knows = QueryValue::Entid(66); let knows = QueryValue::Entid(66);
let parent = QueryValue::Entid(67);
assert!(!cc.is_known_empty()); assert!(!cc.is_known_empty());
assert_eq!(cc.wheres, ColumnIntersection(vec![ assert_eq!(cc.wheres, ColumnIntersection(vec![
ColumnConstraintOrAlternation::Constraint(ColumnConstraint::Equals(d0a.clone(), knows.clone())), ColumnConstraintOrAlternation::Constraint(ColumnConstraint::Equals(d0a.clone(), knows.clone())),
// The outer pattern joins against the `or` on the entity, but not value -- ?y means // The outer pattern joins against the `or` on the entity, but not value -- ?y means
// different things in each place. // different things in each place.
ColumnConstraintOrAlternation::Constraint(ColumnConstraint::Equals(d0e.clone(), QueryValue::Column(QualifiedAlias::new("c00".to_string(), VariableColumn::Variable(vx.clone()))))), ColumnConstraintOrAlternation::Constraint(ColumnConstraint::Equals(d0e.clone(), QueryValue::Column(c0x.clone()))),
])); ]));
assert_eq!(cc.column_bindings.get(&vx), Some(&vec![d0e, d1e])); assert_eq!(cc.column_bindings.get(&vx), Some(&vec![d0e, c0x]));
// ?y does not have a binding in the `or-join` pattern. // ?y does not have a binding in the `or-join` pattern.
assert_eq!(cc.column_bindings.get(&vy), Some(&vec![d0v])); assert_eq!(cc.column_bindings.get(&vy), Some(&vec![d0v]));
assert_eq!(cc.from, vec![SourceAlias(DatomsTable::Datoms, d0), assert_eq!(cc.from, vec![SourceAlias(DatomsTable::Datoms, d0),
SourceAlias(DatomsTable::Datoms, d1)]); SourceAlias(DatomsTable::Computed(0), c0)]);
} }
*/
// These two are equivalent: // These two are equivalent:
// [:find ?x :where [?x :foo/bar ?y] (or [?x :foo/baz ?y])] // [:find ?x :where [?x :foo/bar ?y] (or [?x :foo/baz ?y])]
@ -1002,8 +1007,6 @@ mod testing {
/// Strictly speaking this can be implemented with a `NOT EXISTS` clause for the second pattern, /// Strictly speaking this can be implemented with a `NOT EXISTS` clause for the second pattern,
/// but that would be a fair amount of analysis work, I think. /// but that would be a fair amount of analysis work, I think.
#[test] #[test]
#[allow(dead_code, unused_variables)]
// TODO: flesh this out.
fn test_alternation_with_and() { fn test_alternation_with_and() {
let schema = prepopulated_schema(); let schema = prepopulated_schema();
let query = r#" let query = r#"
@ -1012,6 +1015,34 @@ mod testing {
[?x :foo/parent "Ámbar"]) [?x :foo/parent "Ámbar"])
[?x :foo/knows "Daphne"])]"#; [?x :foo/knows "Daphne"])]"#;
let cc = alg(&schema, query); let cc = alg(&schema, query);
let mut tables = cc.computed_tables.into_iter();
match (tables.next(), tables.next()) {
(Some(ComputedTable::Union { projection, type_extraction, arms }), None) => {
assert_eq!(projection, vec![Variable::from_valid_name("?x")].into_iter().collect());
assert!(type_extraction.is_empty());
let mut arms = arms.into_iter();
match (arms.next(), arms.next(), arms.next()) {
(Some(and), Some(pattern), None) => {
let expected_and = alg_c(&schema,
0, // The first pattern to be processed.
r#"[:find ?x :where [?x :foo/knows "John"] [?x :foo/parent "Ámbar"]]"#);
compare_ccs(and, expected_and);
let expected_pattern = alg_c(&schema,
2, // Two aliases taken by the other arm.
r#"[:find ?x :where [?x :foo/knows "Daphne"]]"#);
compare_ccs(pattern, expected_pattern);
},
_ => {
panic!("Expected two arms");
}
}
},
_ => {
panic!("Didn't get two inner tables.");
},
}
} }
#[test] #[test]