use corium_protocol::codec::encode_edn;
use corium_query::edn::Edn;
use corium_query::{QInput, q};
use corium_transactor::StoreSpec;
use corium_transactor::node::{NodeConfig, NodeError, TransactorNode};
fn schema() -> Vec<u8> {
encode_edn(&Edn::Vector(vec![
Edn::Map(vec![
(Edn::keyword("db/ident"), Edn::keyword("artist/name")),
(Edn::keyword("db/valueType"), Edn::keyword("db.type/string")),
(
Edn::keyword("db/cardinality"),
Edn::keyword("db.cardinality/one"),
),
(
Edn::keyword("db/unique"),
Edn::keyword("db.unique/identity"),
),
]),
Edn::Map(vec![
(Edn::keyword("db/ident"), Edn::keyword("artist/year")),
(Edn::keyword("db/valueType"), Edn::keyword("db.type/long")),
(
Edn::keyword("db/cardinality"),
Edn::keyword("db.cardinality/one"),
),
]),
]))
}
fn tx() -> Vec<u8> {
encode_edn(&Edn::Vector(vec![Edn::Map(vec![
(Edn::keyword("db/id"), Edn::Str("artist".into())),
(Edn::keyword("artist/name"), Edn::Str("Portishead".into())),
(Edn::keyword("artist/year"), Edn::Long(1991)),
])]))
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn mem_backend_runs_the_full_create_transact_read_path() {
let mut config = NodeConfig::new(std::path::PathBuf::from("/nonexistent-mem-node"));
config.store = StoreSpec::Memory;
let node = TransactorNode::open(config).await.expect("open mem node");
assert!(
node.create_db("mbrainz", &schema(), None)
.await
.expect("create")
);
let response = node.transact("mbrainz", &tx()).await.expect("transact");
assert!(response.basis_t > response.basis_before);
let db = node.db_state("mbrainz").await.expect("db state").db();
let query = Edn::Vector(vec![
Edn::keyword("find"),
Edn::symbol("?year"),
Edn::keyword("where"),
Edn::Vector(vec![
Edn::symbol("?e"),
Edn::keyword("artist/name"),
Edn::Str("Portishead".into()),
]),
Edn::Vector(vec![
Edn::symbol("?e"),
Edn::keyword("artist/year"),
Edn::symbol("?year"),
]),
]);
let result = q(&query, &[QInput::Db(&db)]).expect("query");
assert_eq!(result.to_string(), "[[1991]]");
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn expected_basis_rejects_a_stale_transaction_before_commit() {
let mut config = NodeConfig::new(std::path::PathBuf::from("/nonexistent-mem-node"));
config.store = StoreSpec::Memory;
let node = TransactorNode::open(config).await.expect("open mem node");
assert!(
node.create_db("mbrainz", &schema(), None)
.await
.expect("create")
);
let first = node
.transact_at("mbrainz", &tx(), Some(0))
.await
.expect("basis zero is current");
assert_eq!(first.basis_t, 1);
let stale = node
.transact_at("mbrainz", &tx(), Some(0))
.await
.expect_err("stale basis must fail");
assert!(matches!(
stale,
NodeError::BasisMismatch {
expected: 0,
actual: 1
}
));
assert_eq!(
node.db_state("mbrainz")
.await
.expect("state")
.db()
.basis_t(),
1
);
}