Support tx places in queries (#485) r=rnewman
* Support tx places in queries
This commit is contained in:
parent
d1ad3c47f7
commit
c15973f269
3 changed files with 88 additions and 11 deletions
|
@ -611,13 +611,8 @@ impl ConjoiningClauses {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensure that the given place has the correct types to be a tx-id.
|
/// Ensure that the given place has the correct types to be a tx-id.
|
||||||
/// Right now this is mostly unimplemented: we fail hard if anything but a placeholder is
|
|
||||||
/// present.
|
|
||||||
fn constrain_to_tx(&mut self, tx: &PatternNonValuePlace) {
|
fn constrain_to_tx(&mut self, tx: &PatternNonValuePlace) {
|
||||||
match *tx {
|
self.constrain_to_ref(tx);
|
||||||
PatternNonValuePlace::Placeholder => (),
|
|
||||||
_ => unimplemented!(), // TODO: #440.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensure that the given place can be an entity, and is congruent with existing types.
|
/// Ensure that the given place can be an entity, and is congruent with existing types.
|
||||||
|
|
|
@ -81,7 +81,7 @@ impl ConjoiningClauses {
|
||||||
// Sorry for the duplication; Rust makes it a pain to abstract this.
|
// Sorry for the duplication; Rust makes it a pain to abstract this.
|
||||||
|
|
||||||
// The transaction part of a pattern must be an entid, variable, or placeholder.
|
// The transaction part of a pattern must be an entid, variable, or placeholder.
|
||||||
self.constrain_to_tx(&pattern.tx); // See #440.
|
self.constrain_to_tx(&pattern.tx);
|
||||||
self.constrain_to_ref(&pattern.entity);
|
self.constrain_to_ref(&pattern.entity);
|
||||||
self.constrain_to_ref(&pattern.attribute);
|
self.constrain_to_ref(&pattern.attribute);
|
||||||
|
|
||||||
|
@ -238,9 +238,27 @@ impl ConjoiningClauses {
|
||||||
if value_type.is_none() {
|
if value_type.is_none() {
|
||||||
self.wheres.add_intersection(ColumnConstraint::HasType(col.clone(), typed_value_type));
|
self.wheres.add_intersection(ColumnConstraint::HasType(col.clone(), typed_value_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match pattern.tx {
|
||||||
|
PatternNonValuePlace::Placeholder => (),
|
||||||
|
PatternNonValuePlace::Variable(ref v) => {
|
||||||
|
self.bind_column_to_var(schema, col.clone(), DatomsColumn::Tx, v.clone());
|
||||||
|
},
|
||||||
|
PatternNonValuePlace::Entid(entid) => {
|
||||||
|
self.constrain_column_to_entity(col.clone(), DatomsColumn::Tx, entid);
|
||||||
|
},
|
||||||
|
PatternNonValuePlace::Ident(ref ident) => {
|
||||||
|
if let Some(entid) = self.entid_for_ident(schema, ident.as_ref()) {
|
||||||
|
self.constrain_column_to_entity(col.clone(), DatomsColumn::Tx, entid)
|
||||||
|
} else {
|
||||||
|
// A resolution failure means we're done here.
|
||||||
|
self.mark_known_empty(EmptyBecause::UnresolvedIdent(ident.cloned()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_pattern<'s, 'p>(&mut self, schema: &'s Schema, pattern: Pattern) {
|
pub fn apply_pattern<'s, 'p>(&mut self, schema: &'s Schema, pattern: Pattern) {
|
||||||
|
|
|
@ -232,11 +232,9 @@ fn test_instants_and_uuids() {
|
||||||
conn.transact(&mut c, r#"[
|
conn.transact(&mut c, r#"[
|
||||||
[:db/add "u" :foo/uuid #uuid "cf62d552-6569-4d1b-b667-04703041dfc4"]
|
[:db/add "u" :foo/uuid #uuid "cf62d552-6569-4d1b-b667-04703041dfc4"]
|
||||||
]"#).unwrap();
|
]"#).unwrap();
|
||||||
|
|
||||||
// We don't yet support getting the tx from a pattern (#440), so run wild.
|
|
||||||
let r = conn.q_once(&mut c,
|
let r = conn.q_once(&mut c,
|
||||||
r#"[:find [?x ?u ?when]
|
r#"[:find [?x ?u ?when]
|
||||||
:where [?x :foo/uuid ?u]
|
:where [?x :foo/uuid ?u ?tx]
|
||||||
[?tx :db/txInstant ?when]]"#, None);
|
[?tx :db/txInstant ?when]]"#, None);
|
||||||
match r {
|
match r {
|
||||||
Result::Ok(QueryResults::Tuple(Some(vals))) => {
|
Result::Ok(QueryResults::Tuple(Some(vals))) => {
|
||||||
|
@ -257,6 +255,72 @@ fn test_instants_and_uuids() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tx() {
|
||||||
|
let mut c = new_connection("").expect("Couldn't open conn.");
|
||||||
|
let mut conn = Conn::connect(&mut c).expect("Couldn't open DB.");
|
||||||
|
conn.transact(&mut c, r#"[
|
||||||
|
[:db/add "s" :db/ident :foo/uuid]
|
||||||
|
[:db/add "s" :db/valueType :db.type/uuid]
|
||||||
|
[:db/add "s" :db/cardinality :db.cardinality/one]
|
||||||
|
]"#).expect("successful transaction");
|
||||||
|
|
||||||
|
let t = conn.transact(&mut c, r#"[
|
||||||
|
[:db/add "u" :foo/uuid #uuid "cf62d552-6569-4d1b-b667-04703041dfc4"]
|
||||||
|
]"#).expect("successful transaction");
|
||||||
|
|
||||||
|
conn.transact(&mut c, r#"[
|
||||||
|
[:db/add "u" :foo/uuid #uuid "550e8400-e29b-41d4-a716-446655440000"]
|
||||||
|
]"#).expect("successful transaction");
|
||||||
|
|
||||||
|
let r = conn.q_once(&mut c,
|
||||||
|
r#"[:find ?tx
|
||||||
|
:where [?x :foo/uuid #uuid "cf62d552-6569-4d1b-b667-04703041dfc4" ?tx]]"#, None);
|
||||||
|
match r {
|
||||||
|
Result::Ok(QueryResults::Rel(ref v)) => {
|
||||||
|
assert_eq!(*v, vec![
|
||||||
|
vec![TypedValue::Ref(t.tx_id),]
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
_ => panic!("Expected query to work."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tx_as_input() {
|
||||||
|
let mut c = new_connection("").expect("Couldn't open conn.");
|
||||||
|
let mut conn = Conn::connect(&mut c).expect("Couldn't open DB.");
|
||||||
|
conn.transact(&mut c, r#"[
|
||||||
|
[:db/add "s" :db/ident :foo/uuid]
|
||||||
|
[:db/add "s" :db/valueType :db.type/uuid]
|
||||||
|
[:db/add "s" :db/cardinality :db.cardinality/one]
|
||||||
|
]"#).expect("successful transaction");
|
||||||
|
conn.transact(&mut c, r#"[
|
||||||
|
[:db/add "u" :foo/uuid #uuid "550e8400-e29b-41d4-a716-446655440000"]
|
||||||
|
]"#).expect("successful transaction");
|
||||||
|
let t = conn.transact(&mut c, r#"[
|
||||||
|
[:db/add "u" :foo/uuid #uuid "cf62d552-6569-4d1b-b667-04703041dfc4"]
|
||||||
|
]"#).expect("successful transaction");
|
||||||
|
conn.transact(&mut c, r#"[
|
||||||
|
[:db/add "u" :foo/uuid #uuid "267bab92-ee39-4ca2-b7f0-1163a85af1fb"]
|
||||||
|
]"#).expect("successful transaction");
|
||||||
|
|
||||||
|
let tx = (Variable::from_valid_name("?tx"), TypedValue::Ref(t.tx_id));
|
||||||
|
let inputs = QueryInputs::with_value_sequence(vec![tx]);
|
||||||
|
let r = conn.q_once(&mut c,
|
||||||
|
r#"[:find ?uuid
|
||||||
|
:in ?tx
|
||||||
|
:where [?x :foo/uuid ?uuid ?tx]]"#, inputs);
|
||||||
|
match r {
|
||||||
|
Result::Ok(QueryResults::Rel(ref v)) => {
|
||||||
|
assert_eq!(*v, vec![
|
||||||
|
vec![TypedValue::Uuid(Uuid::from_str("cf62d552-6569-4d1b-b667-04703041dfc4").expect("Valid UUID")),]
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
_ => panic!("Expected query to work."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fulltext() {
|
fn test_fulltext() {
|
||||||
let mut c = new_connection("").expect("Couldn't open conn.");
|
let mut c = new_connection("").expect("Couldn't open conn.");
|
||||||
|
|
Loading…
Reference in a new issue