Part 5: eliminate is_known_empty in favor of empty_because and an accessor.
This commit is contained in:
parent
a07efc0a9e
commit
b693385495
6 changed files with 46 additions and 46 deletions
|
@ -142,8 +142,7 @@ impl<K: Clone + Ord, V: Clone> Intersection<K> for BTreeMap<K, V> {
|
||||||
/// * Inline expressions?
|
/// * Inline expressions?
|
||||||
///---------------------------------------------------------------------------------------
|
///---------------------------------------------------------------------------------------
|
||||||
pub struct ConjoiningClauses {
|
pub struct ConjoiningClauses {
|
||||||
/// `true` if this set of clauses cannot yield results in the context of the current schema.
|
/// `Some` if this set of clauses cannot yield results in the context of the current schema.
|
||||||
pub is_known_empty: bool,
|
|
||||||
pub empty_because: Option<EmptyBecause>,
|
pub empty_because: Option<EmptyBecause>,
|
||||||
|
|
||||||
/// A function used to generate an alias for a table -- e.g., from "datoms" to "datoms123".
|
/// A function used to generate an alias for a table -- e.g., from "datoms" to "datoms123".
|
||||||
|
@ -188,7 +187,7 @@ pub struct ConjoiningClauses {
|
||||||
impl Debug for ConjoiningClauses {
|
impl Debug for ConjoiningClauses {
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> ::std::fmt::Result {
|
fn fmt(&self, fmt: &mut Formatter) -> ::std::fmt::Result {
|
||||||
fmt.debug_struct("ConjoiningClauses")
|
fmt.debug_struct("ConjoiningClauses")
|
||||||
.field("is_known_empty", &self.is_known_empty)
|
.field("empty_because", &self.empty_because)
|
||||||
.field("from", &self.from)
|
.field("from", &self.from)
|
||||||
.field("wheres", &self.wheres)
|
.field("wheres", &self.wheres)
|
||||||
.field("column_bindings", &self.column_bindings)
|
.field("column_bindings", &self.column_bindings)
|
||||||
|
@ -204,7 +203,6 @@ impl Debug for ConjoiningClauses {
|
||||||
impl Default for ConjoiningClauses {
|
impl Default for ConjoiningClauses {
|
||||||
fn default() -> ConjoiningClauses {
|
fn default() -> ConjoiningClauses {
|
||||||
ConjoiningClauses {
|
ConjoiningClauses {
|
||||||
is_known_empty: false,
|
|
||||||
empty_because: None,
|
empty_because: None,
|
||||||
aliaser: default_table_aliaser(),
|
aliaser: default_table_aliaser(),
|
||||||
from: vec![],
|
from: vec![],
|
||||||
|
@ -222,7 +220,6 @@ impl Default for ConjoiningClauses {
|
||||||
impl ConjoiningClauses {
|
impl ConjoiningClauses {
|
||||||
fn make_receptacle(&self) -> ConjoiningClauses {
|
fn make_receptacle(&self) -> ConjoiningClauses {
|
||||||
let mut concrete = ConjoiningClauses::default();
|
let mut concrete = ConjoiningClauses::default();
|
||||||
concrete.is_known_empty = self.is_known_empty;
|
|
||||||
concrete.empty_because = self.empty_because.clone();
|
concrete.empty_because = self.empty_because.clone();
|
||||||
|
|
||||||
concrete.input_variables = self.input_variables.clone();
|
concrete.input_variables = self.input_variables.clone();
|
||||||
|
@ -238,7 +235,6 @@ impl ConjoiningClauses {
|
||||||
/// simple `or`.
|
/// simple `or`.
|
||||||
fn use_as_template(&self, vars: &BTreeSet<Variable>) -> ConjoiningClauses {
|
fn use_as_template(&self, vars: &BTreeSet<Variable>) -> ConjoiningClauses {
|
||||||
let mut template = ConjoiningClauses::default();
|
let mut template = ConjoiningClauses::default();
|
||||||
template.is_known_empty = self.is_known_empty;
|
|
||||||
template.empty_because = self.empty_because.clone();
|
template.empty_because = self.empty_because.clone();
|
||||||
|
|
||||||
template.input_variables = self.input_variables.intersection(vars).cloned().collect();
|
template.input_variables = self.input_variables.intersection(vars).cloned().collect();
|
||||||
|
@ -385,7 +381,7 @@ impl ConjoiningClauses {
|
||||||
/// Like `constrain_var_to_type` but in reverse: this expands the set of types
|
/// Like `constrain_var_to_type` but in reverse: this expands the set of types
|
||||||
/// with which a variable is associated.
|
/// with which a variable is associated.
|
||||||
///
|
///
|
||||||
/// N.B.,: if we ever call `broaden_types` after `is_known_empty` has been set, we might
|
/// N.B.,: if we ever call `broaden_types` after `empty_because` has been set, we might
|
||||||
/// actually move from a state in which a variable can have no type to one that can
|
/// actually move from a state in which a variable can have no type to one that can
|
||||||
/// yield results! We never do so at present -- we carefully set-union types before we
|
/// yield results! We never do so at present -- we carefully set-union types before we
|
||||||
/// set-intersect them -- but this is worth bearing in mind.
|
/// set-intersect them -- but this is worth bearing in mind.
|
||||||
|
@ -399,7 +395,7 @@ impl ConjoiningClauses {
|
||||||
e.insert(new_types);
|
e.insert(new_types);
|
||||||
},
|
},
|
||||||
Entry::Occupied(mut e) => {
|
Entry::Occupied(mut e) => {
|
||||||
if e.get().is_empty() && self.is_known_empty {
|
if e.get().is_empty() && self.empty_because.is_some() {
|
||||||
panic!("Uh oh: we failed this pattern, probably because {:?} couldn't match, but now we're broadening its type.",
|
panic!("Uh oh: we failed this pattern, probably because {:?} couldn't match, but now we're broadening its type.",
|
||||||
e.get());
|
e.get());
|
||||||
}
|
}
|
||||||
|
@ -478,8 +474,12 @@ impl ConjoiningClauses {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_known_empty(&self) -> bool {
|
||||||
|
self.empty_because.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
fn mark_known_empty(&mut self, why: EmptyBecause) {
|
fn mark_known_empty(&mut self, why: EmptyBecause) {
|
||||||
self.is_known_empty = true;
|
|
||||||
if self.empty_because.is_some() {
|
if self.empty_because.is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -589,7 +589,7 @@ impl ConjoiningClauses {
|
||||||
/// Produce a (table, alias) pair to handle the provided pattern.
|
/// Produce a (table, alias) pair to handle the provided pattern.
|
||||||
/// This is a mutating method because it mutates the aliaser function!
|
/// This is a mutating method because it mutates the aliaser function!
|
||||||
/// Note that if this function decides that a pattern cannot match, it will flip
|
/// Note that if this function decides that a pattern cannot match, it will flip
|
||||||
/// `is_known_empty`.
|
/// `empty_because`.
|
||||||
fn alias_table<'s, 'a>(&mut self, schema: &'s Schema, pattern: &'a Pattern) -> Option<SourceAlias> {
|
fn alias_table<'s, 'a>(&mut self, schema: &'s Schema, pattern: &'a Pattern) -> Option<SourceAlias> {
|
||||||
self.table_for_places(schema, &pattern.attribute, &pattern.value)
|
self.table_for_places(schema, &pattern.attribute, &pattern.value)
|
||||||
.map_err(|reason| {
|
.map_err(|reason| {
|
||||||
|
|
|
@ -342,7 +342,7 @@ impl ConjoiningClauses {
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
fn apply_simple_or_join(&mut self, schema: &Schema, patterns: Vec<Pattern>, mentioned_vars: BTreeSet<Variable>) -> Result<()> {
|
fn apply_simple_or_join(&mut self, schema: &Schema, patterns: Vec<Pattern>, mentioned_vars: BTreeSet<Variable>) -> Result<()> {
|
||||||
if self.is_known_empty {
|
if self.is_known_empty() {
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,7 +391,7 @@ impl ConjoiningClauses {
|
||||||
let mut receptacle = template.make_receptacle();
|
let mut receptacle = template.make_receptacle();
|
||||||
println!("Applying pattern with attribute {:?}", pattern.attribute);
|
println!("Applying pattern with attribute {:?}", pattern.attribute);
|
||||||
receptacle.apply_pattern_clause_for_alias(schema, &pattern, &source_alias);
|
receptacle.apply_pattern_clause_for_alias(schema, &pattern, &source_alias);
|
||||||
if receptacle.is_known_empty {
|
if receptacle.is_known_empty() {
|
||||||
println!("Receptacle is empty.");
|
println!("Receptacle is empty.");
|
||||||
let reason = receptacle.empty_because;
|
let reason = receptacle.empty_because;
|
||||||
None
|
None
|
||||||
|
@ -471,8 +471,7 @@ impl ConjoiningClauses {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn intersect(&mut self, mut cc: ConjoiningClauses) -> Result<()> {
|
fn intersect(&mut self, mut cc: ConjoiningClauses) -> Result<()> {
|
||||||
if cc.is_known_empty {
|
if cc.is_known_empty() {
|
||||||
self.is_known_empty = true;
|
|
||||||
self.empty_because = cc.empty_because;
|
self.empty_because = cc.empty_because;
|
||||||
}
|
}
|
||||||
self.wheres.append(&mut cc.wheres);
|
self.wheres.append(&mut cc.wheres);
|
||||||
|
@ -573,7 +572,7 @@ mod testing {
|
||||||
[?x :foo/nope2 "Ámbar"]
|
[?x :foo/nope2 "Ámbar"]
|
||||||
[?x :foo/nope3 "Daphne"])]"#;
|
[?x :foo/nope3 "Daphne"])]"#;
|
||||||
let cc = alg(&schema, query);
|
let cc = alg(&schema, query);
|
||||||
assert!(cc.is_known_empty);
|
assert!(cc.is_known_empty());
|
||||||
assert_eq!(cc.empty_because, Some(EmptyBecause::InvalidAttributeIdent(NamespacedKeyword::new("foo", "nope3"))));
|
assert_eq!(cc.empty_because, Some(EmptyBecause::InvalidAttributeIdent(NamespacedKeyword::new("foo", "nope3"))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,7 +586,7 @@ mod testing {
|
||||||
[?x :foo/parent "Ámbar"]
|
[?x :foo/parent "Ámbar"]
|
||||||
[?x :foo/nope "Daphne"])]"#;
|
[?x :foo/nope "Daphne"])]"#;
|
||||||
let cc = alg(&schema, query);
|
let cc = alg(&schema, query);
|
||||||
assert!(!cc.is_known_empty);
|
assert!(!cc.is_known_empty());
|
||||||
compare_ccs(cc, alg(&schema, r#"[:find ?x :where [?x :foo/parent "Ámbar"]]"#));
|
compare_ccs(cc, alg(&schema, r#"[:find ?x :where [?x :foo/parent "Ámbar"]]"#));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -612,7 +611,7 @@ mod testing {
|
||||||
let ambar = QueryValue::TypedValue(TypedValue::typed_string("Ámbar"));
|
let ambar = QueryValue::TypedValue(TypedValue::typed_string("Ámbar"));
|
||||||
let daphne = QueryValue::TypedValue(TypedValue::typed_string("Daphne"));
|
let daphne = QueryValue::TypedValue(TypedValue::typed_string("Daphne"));
|
||||||
|
|
||||||
assert!(!cc.is_known_empty);
|
assert!(!cc.is_known_empty());
|
||||||
assert_eq!(cc.wheres, ColumnIntersection(vec![
|
assert_eq!(cc.wheres, ColumnIntersection(vec![
|
||||||
ColumnConstraintOrAlternation::Alternation(
|
ColumnConstraintOrAlternation::Alternation(
|
||||||
ColumnAlternation(vec![
|
ColumnAlternation(vec![
|
||||||
|
@ -657,7 +656,7 @@ mod testing {
|
||||||
let ambar = QueryValue::TypedValue(TypedValue::typed_string("Ámbar"));
|
let ambar = QueryValue::TypedValue(TypedValue::typed_string("Ámbar"));
|
||||||
let daphne = QueryValue::TypedValue(TypedValue::typed_string("Daphne"));
|
let daphne = QueryValue::TypedValue(TypedValue::typed_string("Daphne"));
|
||||||
|
|
||||||
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(), name.clone())),
|
ColumnConstraintOrAlternation::Constraint(ColumnConstraint::Equals(d0a.clone(), name.clone())),
|
||||||
ColumnConstraintOrAlternation::Alternation(
|
ColumnConstraintOrAlternation::Alternation(
|
||||||
|
@ -706,7 +705,7 @@ mod testing {
|
||||||
let john = QueryValue::TypedValue(TypedValue::typed_string("John"));
|
let john = QueryValue::TypedValue(TypedValue::typed_string("John"));
|
||||||
let daphne = QueryValue::TypedValue(TypedValue::typed_string("Daphne"));
|
let daphne = QueryValue::TypedValue(TypedValue::typed_string("Daphne"));
|
||||||
|
|
||||||
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(), age.clone())),
|
ColumnConstraintOrAlternation::Constraint(ColumnConstraint::Equals(d0a.clone(), age.clone())),
|
||||||
ColumnConstraintOrAlternation::Constraint(ColumnConstraint::NumericInequality {
|
ColumnConstraintOrAlternation::Constraint(ColumnConstraint::NumericInequality {
|
||||||
|
@ -754,7 +753,7 @@ mod testing {
|
||||||
let knows = QueryValue::Entid(66);
|
let knows = QueryValue::Entid(66);
|
||||||
let parent = QueryValue::Entid(67);
|
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())),
|
||||||
ColumnConstraintOrAlternation::Constraint(ColumnConstraint::Equals(d1a.clone(), parent.clone())),
|
ColumnConstraintOrAlternation::Constraint(ColumnConstraint::Equals(d1a.clone(), parent.clone())),
|
||||||
|
|
|
@ -41,7 +41,7 @@ impl ConjoiningClauses {
|
||||||
/// account all information spread across two patterns.
|
/// account all information spread across two patterns.
|
||||||
///
|
///
|
||||||
/// If the constraints cannot be satisfied -- for example, if this pattern includes a numeric
|
/// If the constraints cannot be satisfied -- for example, if this pattern includes a numeric
|
||||||
/// attribute and a string value -- then the `is_known_empty` field on the CC is flipped and
|
/// attribute and a string value -- then the `empty_because` field on the CC is flipped and
|
||||||
/// the function returns.
|
/// the function returns.
|
||||||
///
|
///
|
||||||
/// A pattern being impossible to satisfy isn't necessarily a bad thing -- this query might
|
/// A pattern being impossible to satisfy isn't necessarily a bad thing -- this query might
|
||||||
|
@ -71,7 +71,7 @@ impl ConjoiningClauses {
|
||||||
///
|
///
|
||||||
/// This method is only public for use from `or.rs`.
|
/// This method is only public for use from `or.rs`.
|
||||||
pub fn apply_pattern_clause_for_alias<'s>(&mut self, schema: &'s Schema, pattern: &Pattern, alias: &SourceAlias) {
|
pub fn apply_pattern_clause_for_alias<'s>(&mut self, schema: &'s Schema, pattern: &Pattern, alias: &SourceAlias) {
|
||||||
if self.is_known_empty {
|
if self.is_known_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +154,7 @@ impl ConjoiningClauses {
|
||||||
// Wouldn't it be nice if we didn't need to clone in the found case?
|
// Wouldn't it be nice if we didn't need to clone in the found case?
|
||||||
// It doesn't matter too much: collisons won't be too frequent.
|
// It doesn't matter too much: collisons won't be too frequent.
|
||||||
self.constrain_var_to_type(v.clone(), this_type);
|
self.constrain_var_to_type(v.clone(), this_type);
|
||||||
if self.is_known_empty {
|
if self.is_known_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -322,7 +322,7 @@ mod testing {
|
||||||
tx: PatternNonValuePlace::Placeholder,
|
tx: PatternNonValuePlace::Placeholder,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert!(cc.is_known_empty);
|
assert!(cc.is_known_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -340,7 +340,7 @@ mod testing {
|
||||||
tx: PatternNonValuePlace::Placeholder,
|
tx: PatternNonValuePlace::Placeholder,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert!(cc.is_known_empty);
|
assert!(cc.is_known_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -370,7 +370,7 @@ mod testing {
|
||||||
let d0_v = QualifiedAlias("datoms00".to_string(), DatomsColumn::Value);
|
let d0_v = QualifiedAlias("datoms00".to_string(), DatomsColumn::Value);
|
||||||
|
|
||||||
// After this, we know a lot of things:
|
// After this, we know a lot of things:
|
||||||
assert!(!cc.is_known_empty);
|
assert!(!cc.is_known_empty());
|
||||||
assert_eq!(cc.from, vec![SourceAlias(DatomsTable::Datoms, "datoms00".to_string())]);
|
assert_eq!(cc.from, vec![SourceAlias(DatomsTable::Datoms, "datoms00".to_string())]);
|
||||||
|
|
||||||
// ?x must be a ref.
|
// ?x must be a ref.
|
||||||
|
@ -408,7 +408,7 @@ mod testing {
|
||||||
let d0_e = QualifiedAlias("datoms00".to_string(), DatomsColumn::Entity);
|
let d0_e = QualifiedAlias("datoms00".to_string(), DatomsColumn::Entity);
|
||||||
let d0_v = QualifiedAlias("datoms00".to_string(), DatomsColumn::Value);
|
let d0_v = QualifiedAlias("datoms00".to_string(), DatomsColumn::Value);
|
||||||
|
|
||||||
assert!(!cc.is_known_empty);
|
assert!(!cc.is_known_empty());
|
||||||
assert_eq!(cc.from, vec![SourceAlias(DatomsTable::Datoms, "datoms00".to_string())]);
|
assert_eq!(cc.from, vec![SourceAlias(DatomsTable::Datoms, "datoms00".to_string())]);
|
||||||
|
|
||||||
// ?x must be a ref.
|
// ?x must be a ref.
|
||||||
|
@ -457,7 +457,7 @@ mod testing {
|
||||||
let d0_e = QualifiedAlias("datoms00".to_string(), DatomsColumn::Entity);
|
let d0_e = QualifiedAlias("datoms00".to_string(), DatomsColumn::Entity);
|
||||||
let d0_a = QualifiedAlias("datoms00".to_string(), DatomsColumn::Attribute);
|
let d0_a = QualifiedAlias("datoms00".to_string(), DatomsColumn::Attribute);
|
||||||
|
|
||||||
assert!(!cc.is_known_empty);
|
assert!(!cc.is_known_empty());
|
||||||
assert_eq!(cc.from, vec![SourceAlias(DatomsTable::Datoms, "datoms00".to_string())]);
|
assert_eq!(cc.from, vec![SourceAlias(DatomsTable::Datoms, "datoms00".to_string())]);
|
||||||
|
|
||||||
// ?x must be a ref, and ?v a boolean.
|
// ?x must be a ref, and ?v a boolean.
|
||||||
|
@ -495,7 +495,7 @@ mod testing {
|
||||||
tx: PatternNonValuePlace::Placeholder,
|
tx: PatternNonValuePlace::Placeholder,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert!(cc.is_known_empty);
|
assert!(cc.is_known_empty());
|
||||||
assert_eq!(cc.empty_because.unwrap(), EmptyBecause::InvalidBinding(DatomsColumn::Attribute, hello));
|
assert_eq!(cc.empty_because.unwrap(), EmptyBecause::InvalidBinding(DatomsColumn::Attribute, hello));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,7 +521,7 @@ mod testing {
|
||||||
|
|
||||||
let d0_e = QualifiedAlias("all_datoms00".to_string(), DatomsColumn::Entity);
|
let d0_e = QualifiedAlias("all_datoms00".to_string(), DatomsColumn::Entity);
|
||||||
|
|
||||||
assert!(!cc.is_known_empty);
|
assert!(!cc.is_known_empty());
|
||||||
assert_eq!(cc.from, vec![SourceAlias(DatomsTable::AllDatoms, "all_datoms00".to_string())]);
|
assert_eq!(cc.from, vec![SourceAlias(DatomsTable::AllDatoms, "all_datoms00".to_string())]);
|
||||||
|
|
||||||
// ?x must be a ref.
|
// ?x must be a ref.
|
||||||
|
@ -552,7 +552,7 @@ mod testing {
|
||||||
let d0_e = QualifiedAlias("all_datoms00".to_string(), DatomsColumn::Entity);
|
let d0_e = QualifiedAlias("all_datoms00".to_string(), DatomsColumn::Entity);
|
||||||
let d0_v = QualifiedAlias("all_datoms00".to_string(), DatomsColumn::Value);
|
let d0_v = QualifiedAlias("all_datoms00".to_string(), DatomsColumn::Value);
|
||||||
|
|
||||||
assert!(!cc.is_known_empty);
|
assert!(!cc.is_known_empty());
|
||||||
assert_eq!(cc.from, vec![SourceAlias(DatomsTable::AllDatoms, "all_datoms00".to_string())]);
|
assert_eq!(cc.from, vec![SourceAlias(DatomsTable::AllDatoms, "all_datoms00".to_string())]);
|
||||||
|
|
||||||
// ?x must be a ref.
|
// ?x must be a ref.
|
||||||
|
@ -615,7 +615,7 @@ mod testing {
|
||||||
let d1_e = QualifiedAlias("datoms01".to_string(), DatomsColumn::Entity);
|
let d1_e = QualifiedAlias("datoms01".to_string(), DatomsColumn::Entity);
|
||||||
let d1_a = QualifiedAlias("datoms01".to_string(), DatomsColumn::Attribute);
|
let d1_a = QualifiedAlias("datoms01".to_string(), DatomsColumn::Attribute);
|
||||||
|
|
||||||
assert!(!cc.is_known_empty);
|
assert!(!cc.is_known_empty());
|
||||||
assert_eq!(cc.from, vec![
|
assert_eq!(cc.from, vec![
|
||||||
SourceAlias(DatomsTable::Datoms, "datoms00".to_string()),
|
SourceAlias(DatomsTable::Datoms, "datoms00".to_string()),
|
||||||
SourceAlias(DatomsTable::Datoms, "datoms01".to_string()),
|
SourceAlias(DatomsTable::Datoms, "datoms01".to_string()),
|
||||||
|
@ -715,7 +715,7 @@ mod testing {
|
||||||
});
|
});
|
||||||
|
|
||||||
// The type of the provided binding doesn't match the type of the attribute.
|
// The type of the provided binding doesn't match the type of the attribute.
|
||||||
assert!(cc.is_known_empty);
|
assert!(cc.is_known_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -747,7 +747,7 @@ mod testing {
|
||||||
});
|
});
|
||||||
|
|
||||||
// The type of the provided binding doesn't match the type of the attribute.
|
// The type of the provided binding doesn't match the type of the attribute.
|
||||||
assert!(cc.is_known_empty);
|
assert!(cc.is_known_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -790,13 +790,13 @@ mod testing {
|
||||||
// Finally, expand column bindings to get the overlaps for ?x.
|
// Finally, expand column bindings to get the overlaps for ?x.
|
||||||
cc.expand_column_bindings();
|
cc.expand_column_bindings();
|
||||||
|
|
||||||
assert!(cc.is_known_empty);
|
assert!(cc.is_known_empty());
|
||||||
assert_eq!(cc.empty_because.unwrap(),
|
assert_eq!(cc.empty_because.unwrap(),
|
||||||
EmptyBecause::TypeMismatch(y.clone(), unit_type_set(ValueType::String), ValueType::Boolean));
|
EmptyBecause::TypeMismatch(y.clone(), unit_type_set(ValueType::String), ValueType::Boolean));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "assertion failed: cc.is_known_empty")]
|
#[should_panic(expected = "assertion failed: cc.is_known_empty()")]
|
||||||
/// This test needs range inference in order to succeed: we must deduce that ?y must
|
/// This test needs range inference in order to succeed: we must deduce that ?y must
|
||||||
/// simultaneously be a boolean-valued attribute and a ref-valued attribute, and thus
|
/// simultaneously be a boolean-valued attribute and a ref-valued attribute, and thus
|
||||||
/// the CC can never return results.
|
/// the CC can never return results.
|
||||||
|
@ -828,7 +828,7 @@ mod testing {
|
||||||
// Finally, expand column bindings to get the overlaps for ?x.
|
// Finally, expand column bindings to get the overlaps for ?x.
|
||||||
cc.expand_column_bindings();
|
cc.expand_column_bindings();
|
||||||
|
|
||||||
assert!(cc.is_known_empty);
|
assert!(cc.is_known_empty());
|
||||||
assert_eq!(cc.empty_because.unwrap(),
|
assert_eq!(cc.empty_because.unwrap(),
|
||||||
EmptyBecause::TypeMismatch(x.clone(), unit_type_set(ValueType::Ref), ValueType::Boolean));
|
EmptyBecause::TypeMismatch(x.clone(), unit_type_set(ValueType::Ref), ValueType::Boolean));
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,7 @@ mod testing {
|
||||||
value: PatternValuePlace::Variable(y.clone()),
|
value: PatternValuePlace::Variable(y.clone()),
|
||||||
tx: PatternNonValuePlace::Placeholder,
|
tx: PatternNonValuePlace::Placeholder,
|
||||||
});
|
});
|
||||||
assert!(!cc.is_known_empty);
|
assert!(!cc.is_known_empty());
|
||||||
|
|
||||||
let op = PlainSymbol::new("<");
|
let op = PlainSymbol::new("<");
|
||||||
let comp = NumericComparison::from_datalog_operator(op.plain_name()).unwrap();
|
let comp = NumericComparison::from_datalog_operator(op.plain_name()).unwrap();
|
||||||
|
@ -150,11 +150,11 @@ mod testing {
|
||||||
FnArg::Variable(Variable::from_valid_name("?y")), FnArg::EntidOrInteger(10),
|
FnArg::Variable(Variable::from_valid_name("?y")), FnArg::EntidOrInteger(10),
|
||||||
]}).is_ok());
|
]}).is_ok());
|
||||||
|
|
||||||
assert!(!cc.is_known_empty);
|
assert!(!cc.is_known_empty());
|
||||||
|
|
||||||
// Finally, expand column bindings to get the overlaps for ?x.
|
// Finally, expand column bindings to get the overlaps for ?x.
|
||||||
cc.expand_column_bindings();
|
cc.expand_column_bindings();
|
||||||
assert!(!cc.is_known_empty);
|
assert!(!cc.is_known_empty());
|
||||||
|
|
||||||
// After processing those two clauses, we know that ?y must be numeric, but not exactly
|
// After processing those two clauses, we know that ?y must be numeric, but not exactly
|
||||||
// which type it must be.
|
// which type it must be.
|
||||||
|
@ -200,7 +200,7 @@ mod testing {
|
||||||
value: PatternValuePlace::Variable(y.clone()),
|
value: PatternValuePlace::Variable(y.clone()),
|
||||||
tx: PatternNonValuePlace::Placeholder,
|
tx: PatternNonValuePlace::Placeholder,
|
||||||
});
|
});
|
||||||
assert!(!cc.is_known_empty);
|
assert!(!cc.is_known_empty());
|
||||||
|
|
||||||
let op = PlainSymbol::new(">=");
|
let op = PlainSymbol::new(">=");
|
||||||
let comp = NumericComparison::from_datalog_operator(op.plain_name()).unwrap();
|
let comp = NumericComparison::from_datalog_operator(op.plain_name()).unwrap();
|
||||||
|
@ -210,7 +210,7 @@ mod testing {
|
||||||
FnArg::Variable(Variable::from_valid_name("?y")), FnArg::EntidOrInteger(10),
|
FnArg::Variable(Variable::from_valid_name("?y")), FnArg::EntidOrInteger(10),
|
||||||
]}).is_ok());
|
]}).is_ok());
|
||||||
|
|
||||||
assert!(!cc.is_known_empty);
|
assert!(!cc.is_known_empty());
|
||||||
cc.apply_pattern(&schema, Pattern {
|
cc.apply_pattern(&schema, Pattern {
|
||||||
source: None,
|
source: None,
|
||||||
entity: PatternNonValuePlace::Variable(x.clone()),
|
entity: PatternNonValuePlace::Variable(x.clone()),
|
||||||
|
@ -222,7 +222,7 @@ mod testing {
|
||||||
// Finally, expand column bindings to get the overlaps for ?x.
|
// Finally, expand column bindings to get the overlaps for ?x.
|
||||||
cc.expand_column_bindings();
|
cc.expand_column_bindings();
|
||||||
|
|
||||||
assert!(cc.is_known_empty);
|
assert!(cc.is_known_empty());
|
||||||
assert_eq!(cc.empty_because.unwrap(),
|
assert_eq!(cc.empty_because.unwrap(),
|
||||||
EmptyBecause::TypeMismatch(y.clone(),
|
EmptyBecause::TypeMismatch(y.clone(),
|
||||||
vec![ValueType::Double, ValueType::Long].into_iter()
|
vec![ValueType::Double, ValueType::Long].into_iter()
|
||||||
|
|
|
@ -63,8 +63,9 @@ impl AlgebraicQuery {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_known_empty(&self) -> bool {
|
pub fn is_known_empty(&self) -> bool {
|
||||||
self.cc.is_known_empty
|
self.cc.is_known_empty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,7 @@ fn cc_to_select_query<T: Into<Option<u64>>>(projection: Projection, cc: Conjoini
|
||||||
FromClause::TableList(TableList(cc.from))
|
FromClause::TableList(TableList(cc.from))
|
||||||
};
|
};
|
||||||
|
|
||||||
let limit = if cc.is_known_empty { Some(0) } else { limit.into() };
|
let limit = if cc.empty_because.is_some() { Some(0) } else { limit.into() };
|
||||||
SelectQuery {
|
SelectQuery {
|
||||||
distinct: distinct,
|
distinct: distinct,
|
||||||
projection: projection,
|
projection: projection,
|
||||||
|
@ -174,7 +174,7 @@ fn cc_to_select_query<T: Into<Option<u64>>>(projection: Projection, cc: Conjoini
|
||||||
/// Return a query that projects `1` if the `cc` matches the store, and returns no results
|
/// Return a query that projects `1` if the `cc` matches the store, and returns no results
|
||||||
/// if it doesn't.
|
/// if it doesn't.
|
||||||
pub fn cc_to_exists(cc: ConjoiningClauses) -> SelectQuery {
|
pub fn cc_to_exists(cc: ConjoiningClauses) -> SelectQuery {
|
||||||
if cc.is_known_empty {
|
if cc.is_known_empty() {
|
||||||
// In this case we can produce a very simple query that returns no results.
|
// In this case we can produce a very simple query that returns no results.
|
||||||
SelectQuery {
|
SelectQuery {
|
||||||
distinct: false,
|
distinct: false,
|
||||||
|
|
Loading…
Reference in a new issue