-
Notifications
You must be signed in to change notification settings - Fork 115
Support inequality predicates for instants #482
Conversation
| /// Datalog and SQL don't use the same operators (e.g., `<>` and `!=`). | ||
| pub enum NumericComparison { | ||
| /// These are applicable to numbers and instants. | ||
| pub enum Inequality { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is Inequality entirely accurate when there are LessThanOrEquals and GreaterThanOrEquals as options on the enum?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes; the full technical term is "non-strict inequality".
| } | ||
|
|
||
| #[test] | ||
| fn test_instant_range() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have another test please testing the self.mark_known_empty(EmptyBecause::NonInstantArgument); case?
This trait exposes potential_types, which returns the set of types to which the provided FnArg could conform.
Adds translation and end-to-end tests.
de82eb2 to
69addb3
Compare
ncalexan
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm basically OK with this, although I don't understand how the or case will be handled. Is it that the two inner CCs will each restrict their arguments based on the known types, and then the outer CC will do the right thing? What would happen if you injected the attribute name in via ground, so that the schema couldn't be queried to determine the type?
| }, | ||
|
|
||
| &FnArg::IdentOrKeyword(ref x) => { | ||
| if schema.get_entid(x).is_some() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a note that interacts with multi-stage algebrizing? I guess the &Schema parameter says that pretty clearly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This bit in particular doesn't, except in the manner that all of our queries could fundamentally change behavior if the schema changes!
| &FnArg::Constant(NonIntegerConstant::Instant(x)) => ValueTypeSet::of_one(ValueType::Instant), | ||
| &FnArg::Constant(NonIntegerConstant::Uuid(x)) => ValueTypeSet::of_one(ValueType::Uuid), | ||
| &FnArg::Constant(NonIntegerConstant::Float(x)) => ValueTypeSet::of_one(ValueType::Double), | ||
| &FnArg::Constant(NonIntegerConstant::Boolean(_)) => ValueTypeSet::of_one(ValueType::Boolean), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fold into the previous patch.
| .intersection(&comparison.supported_types()); | ||
|
|
||
| // We expect the intersection to be Long, Long+Double, Double, or Instant. | ||
| let left_v; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't know Rust supported single-static-assignment with bare let. I wonder if there's a version requirement.
| // We expect the intersection to be Long, Long+Double, Double, or Instant. | ||
| let left_v; | ||
| let right_v; | ||
| if shared_types == ValueTypeSet::of_one(ValueType::Instant) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it not be possible to ask for values that could be long or instants? Something like:
[:find ?x ?y :where
(or
(and [_ :some/instant ?x]
[_ :some/other-instant ?y])
(and [_ :some/long ?x]
[_ :some/other-long ?y]))]There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what you mean is: can we algebrize a predicate where the types of the values are not known precisely, even if they could be mutually consistent?
I think your example needs a final clause for illustration:
[:find ?x ?y :where
(or
(and [_ :some/instant ?x]
[_ :some/other-instant ?y])
(and [_ :some/long ?x]
[_ :some/other-long ?y]))
[(< ?x ?y)]]
The answer is: no, at least not yet. We don't maintain possibility trees, only type sets, so the best we know about your query is that ?x and ?y can each be either Instant or Long. That means it's possible — as far as the currently implementation is concerned, anyway — for ?x to be an Instant and ?y to be a Long, which we're not prepared to handle.
The simplest workaround is to push the condition into each branch:
[:find ?x ?y :where
(or
(and [_ :some/instant ?x]
[_ :some/other-instant ?y]
[(< ?x ?y)])
(and [_ :some/long ?x]
[_ :some/other-long ?y]
[(< ?x ?y)]))]
which will also likely be more efficient.
The other way of looking at your question is to realize that we have built ourselves this problem: the comparison operators in Clojure, and the comparisons in SQL, are overloaded. If the SQL comparison were DATE_LESS_THAN instead of <, then you wouldn't even be asking this question!
| Ok(QueryValue::TypedValue(TypedValue::Instant(v))) | ||
| }, | ||
|
|
||
| // TODO: should we allow integers if they seem to be timestamps? It's ambiguous… |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally, I'd prefer Mentat to be strict (with errors rather than empty result sets) in ambiguous cases.
| [?e :foo/date ?t] | ||
| [(> ?t "2017-06-16T00:56:41.257Z")]]"#; | ||
| match bails(&schema, query).0 { | ||
| ErrorKind::InvalidArgument(op, why, idx) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not feasible to derive Eq or PartialEq on ErrorKind, eh? Rats.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rust-lang-deprecated/error-chain#95
rust-lang-deprecated/error-chain#134
We're also waiting for that so we can derive Sync and upgrade to the current version of error_chain!
This issue fixes #439.
#481 and #480 are fixes necessary for this to work correctly.