A common pattern I've encountered is:
let link_title = ip.get_entid(&kw!(:link/title)).unwrap();
let results = ip.q_once(r#"
[:find ?e ?t2
:where [?e :link/title ?t1]
[?e :link/title ?t2]
[(unpermute ?t1 ?t2)]]
"#, None).into_rel_result()?;
if !results.is_empty() {
let mut builder = TermBuilder::new();
for row in results.into_iter() {
let mut r = row.into_iter();
let e = r.next().and_then(|e| e.into_known_entid()).expect("entity");
let obsolete = r.next().expect("value");
builder.retract(e, link_title, obsolete)?;
}
ip.transact_builder(builder)?;
}
That is: query to build up retractions and/or assertions, then transact those.
Datomic follows this model easily: it's loosely typed, data is local and in memory, etc. etc.
It's slightly less comfortable in Rust because of the rigid type system: we can't easily make builder ergonomic, and the caller needs to do some ritual (into_rel_result, consuming the results, etc.) to make this happen.
It's likely to be even more uncomfortable, and perhaps a little slow, from other languages.
We might instead choose to borrow from SPARQL UPDATE and extend our syntax to do this inline:
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
WITH <http://example/addresses>
DELETE { ?person foaf:givenName 'Bill' }
INSERT { ?person foaf:givenName 'William' }
WHERE
{ ?person foaf:givenName 'Bill'
}
which for Mentat might look exactly like a :find query with different operands:
[:retract (?person :person/name "Bill")
:assert (?person :person/name "William")
:where [?person :person/name "Bill"]]
This could be evaluated in one of two ways:
- As a special kind of projection that does the ritual consume/build/transact work for you. This is expensive — values will be pulled into memory, collected, then serialized for SQL and transacted — but it's relatively little work.
- By translation into SQL. In part this will encode some of the work the transactor already does. More development work, but more production-grade.
A common pattern I've encountered is:
That is: query to build up retractions and/or assertions, then transact those.
Datomic follows this model easily: it's loosely typed, data is local and in memory, etc. etc.
It's slightly less comfortable in Rust because of the rigid type system: we can't easily make
builderergonomic, and the caller needs to do some ritual (into_rel_result, consuming the results, etc.) to make this happen.It's likely to be even more uncomfortable, and perhaps a little slow, from other languages.
We might instead choose to borrow from SPARQL UPDATE and extend our syntax to do this inline:
which for Mentat might look exactly like a
:findquery with different operands:This could be evaluated in one of two ways: