Don't allow violation of cardinality-one restrictions within a single tx. (#531) r=nalexander
This commit is contained in:
parent
6ed5413cd4
commit
ef9f2d9c51
2 changed files with 44 additions and 1 deletions
43
db/src/db.rs
43
db/src/db.rs
|
@ -743,6 +743,10 @@ impl MentatStoring for rusqlite::Connection {
|
||||||
value_type_tag0 SMALLINT NOT NULL,
|
value_type_tag0 SMALLINT NOT NULL,
|
||||||
added0 TINYINT NOT NULL,
|
added0 TINYINT NOT NULL,
|
||||||
flags0 TINYINT NOT NULL)"#,
|
flags0 TINYINT NOT NULL)"#,
|
||||||
|
|
||||||
|
// We create this unique index so that it's impossible to violate a cardinality constraint
|
||||||
|
// within a transaction.
|
||||||
|
r#"CREATE UNIQUE INDEX IF NOT EXISTS temp.inexact_searches_unique ON inexact_searches (e0, a0) WHERE added0 = 1"#,
|
||||||
r#"DROP TABLE IF EXISTS temp.search_results"#,
|
r#"DROP TABLE IF EXISTS temp.search_results"#,
|
||||||
// TODO: don't encode search_type as a STRING. This is explicit and much easier to read
|
// TODO: don't encode search_type as a STRING. This is explicit and much easier to read
|
||||||
// than another flag, so we'll do it to start, and optimize later.
|
// than another flag, so we'll do it to start, and optimize later.
|
||||||
|
@ -824,6 +828,7 @@ impl MentatStoring for rusqlite::Connection {
|
||||||
let s: String = if search_type == SearchType::Exact {
|
let s: String = if search_type == SearchType::Exact {
|
||||||
format!("INSERT INTO temp.exact_searches (e0, a0, v0, value_type_tag0, added0, flags0) VALUES {}", values)
|
format!("INSERT INTO temp.exact_searches (e0, a0, v0, value_type_tag0, added0, flags0) VALUES {}", values)
|
||||||
} else {
|
} else {
|
||||||
|
// This will err for duplicates within the tx.
|
||||||
format!("INSERT INTO temp.inexact_searches (e0, a0, v0, value_type_tag0, added0, flags0) VALUES {}", values)
|
format!("INSERT INTO temp.inexact_searches (e0, a0, v0, value_type_tag0, added0, flags0) VALUES {}", values)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2271,4 +2276,42 @@ mod tests {
|
||||||
"[{:test/_dangling 1.23}]",
|
"[{:test/_dangling 1.23}]",
|
||||||
Err("EDN value \'1.23\' is not the expected Mentat value type Ref"));
|
Err("EDN value \'1.23\' is not the expected Mentat value type Ref"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cardinality_one_violation_existing_entity() {
|
||||||
|
let mut conn = TestConn::default();
|
||||||
|
|
||||||
|
// Start by installing a few attributes.
|
||||||
|
assert_transact!(conn, r#"[
|
||||||
|
[:db/add 111 :db/ident :test/one]
|
||||||
|
[:db/add 111 :db/valueType :db.type/long]
|
||||||
|
[:db/add 111 :db/cardinality :db.cardinality/one]
|
||||||
|
[:db/add 112 :db/ident :test/unique]
|
||||||
|
[:db/add 112 :db/index true]
|
||||||
|
[:db/add 112 :db/valueType :db.type/string]
|
||||||
|
[:db/add 112 :db/cardinality :db.cardinality/one]
|
||||||
|
[:db/add 112 :db/unique :db.unique/identity]
|
||||||
|
]"#);
|
||||||
|
|
||||||
|
assert_transact!(conn, r#"[
|
||||||
|
[:db/add "foo" :test/unique "x"]
|
||||||
|
]"#);
|
||||||
|
|
||||||
|
// You can try to assert two values for the same entity and attribute,
|
||||||
|
// but you'll get an error.
|
||||||
|
assert_transact!(conn, r#"[
|
||||||
|
[:db/add "foo" :test/unique "x"]
|
||||||
|
[:db/add "foo" :test/one 123]
|
||||||
|
[:db/add "bar" :test/unique "x"]
|
||||||
|
[:db/add "bar" :test/one 124]
|
||||||
|
]"#,
|
||||||
|
Err("Could not insert non-fts one statements into temporary search table!"));
|
||||||
|
|
||||||
|
// It also fails for map notation.
|
||||||
|
assert_transact!(conn, r#"[
|
||||||
|
{:test/unique "x", :test/one 123}
|
||||||
|
{:test/unique "x", :test/one 124}
|
||||||
|
]"#,
|
||||||
|
Err("Could not insert non-fts one statements into temporary search table!"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,7 @@ pub enum EntidOrLookupRefOrTempId {
|
||||||
TempId(TempId),
|
TempId(TempId),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
|
||||||
pub enum OpType {
|
pub enum OpType {
|
||||||
Add,
|
Add,
|
||||||
Retract,
|
Retract,
|
||||||
|
|
Loading…
Reference in a new issue