{:crux.db/id :dbpedia.resource/Pablo-Picasso
:name "Pablo"
:last-name "Picasso"}
There are four transaction (write) operations:
Operation | Purpose |
---|---|
| Write a version of a document |
| Deletes the specific document at a given |
| Check the document state against the given document |
| Evicts a document entirely, including all historical versions |
A document looks like this:
{:crux.db/id :dbpedia.resource/Pablo-Picasso
:name "Pablo"
:last-name "Picasso"}
In practice when using Crux, one calls crux.db/submit-tx
with a
sequence of transaction operations:
[[:crux.tx/put
{:crux.db/id :dbpedia.resource/Pablo-Picasso
:name "Pablo"
:last-name "Picasso"}
#inst "2018-05-18T09:20:27.966-00:00"]]
If the transaction contains pre-conditions, all pre-conditions must pass or the entire transaction is aborted. This happens at the query node during indexing, and not when submitting the transaction.
For operations containing documents, the id and the document are
hashed, and the operation and hash is submitted to the tx-topic
in
the event log. The document itself is submitted to the doc-topic
,
using its content hash as key. In Kafka, the doc-topic
is compacted,
which enables later deletion of documents.
The following types of :crux.db/id
are allowed:
Keyword (e.g. {:crux.db/id :my-id}
or {:crux.db/id :dbpedia.resource/Pablo-Picasso}
)
UUID (e.g. {:crux.db/id #uuid "6f0232d0-f3f9-4020-a75f-17b067f41203"}
or {:crux.db/id #crux/id "6f0232d0-f3f9-4020-a75f-17b067f41203"}
)
URI (e.g. {:crux.db/id #crux/id "mailto:crux@juxt.pro"}
)
URL (e.g. {:crux.db/id #crux/id "https://github.com/juxt/crux"}
), including http
, https
, ftp
and file
protocols
Maps (e.g. {:crux.db/id #crux/id {:this :id-field}}
) (Note: see issue #362).
The #crux/id
reader literal will take any string and attempt to coerce it
into a valid ID. Use of #crux/id
with a valid ID type will also work
(e.g. {:crux.db/id #crux/id :my-id}
).
URIs and URLs are interpreted using Java classes (java.net.URI and java.net.URL respectively) and therefore you can also use these directly.
Put’s a document into Crux. If a document already exists with the
given :crux.db/id
, a new version of this document will be created at
the supplied valid time
.
[:crux.tx/put
{:crux.db/id :dbpedia.resource/Pablo-Picasso :first-name :Pablo} (1)
#inst "2018-05-18T09:20:27.966-00:00"] (2)
1 | The document itself. Note that the ID must be included as part of the document. |
2 | valid time |
Note that valid time
is optional and defaults to transaction time,
which is taken from the Kafka log.
Crux currently writes into the past at a single point, so to overwrite several versions or a range in time, one is required to submit a transaction containing several operations.
Deletes a document at a given valid time
.
Historical versions of the document will still be available.
[:crux.tx/delete :dbpedia.resource/Pablo-Picasso
#inst "2018-05-18T09:21:52.151-00:00"]
Match operations check the current state of an entity - if the entity doesn’t match the provided doc, the transaction will not continue.
You can also pass nil
to check that the entity doesn’t exist prior to your transaction.
[:crux.tx/match
:ivan (1)
{..} (2)
#inst "2018-05-18T09:21:31.846-00:00"] (3)
1 | Entity id |
2 | Document (or nil) |
3 | (optional) valid time |
Evicts a document from Crux. Historical versions of the document will no longer be available.
[:crux.tx/evict :dbpedia.resource/Pablo-Picasso]
Transaction functions are user-supplied functions that run on the individual Crux nodes when a transaction is being ingested.
They can take any number of parameters, and return normal transaction operations which are then indexed as above.
If they return false
or throw an exception, the whole transaction will roll back.
Transaction functions can be used, for example, to safely check the current database state before applying a transaction, for integrity checks, or to patch an entity.
Transaction functions are created/updated by submitting a document to Crux with a crux.db/fn
key.
These functions are passed a 'context' parameter, which can be used to obtain a database value using db
or open-db
.
(crux/submit-tx node [[:crux.tx/put {:crux.db/id :increment-age
;; note that the function body is quoted.
:crux.db/fn '(fn [ctx eid]
(let [db (crux.api/db ctx)
entity (crux.api/entity db eid)]
[[:crux.tx/put (update entity :age inc)]]))}]])
You can then invoke these transaction functions by submitting a :crux.tx/fn
operation:
(crux/submit-tx node [[:crux.tx/put {:crux.db/id :ivan, :age 40}]])
(crux/submit-tx node [[:crux.tx/fn :increment-age :ivan]])
;; once those transactions have been indexed
(crux/entity (crux/db node) :ivan)
;; => {:crux.db/id :ivan, :age 41}
You can subscribe to Crux events using the (crux.api/listen node event-opts f)
function.
Currently we expose one event type, :crux/indexed-tx
, called when Crux indexes a transaction.
(require '[crux.api :as crux])
(crux/listen node {:crux/event-type :crux/indexed-tx, :with-tx-ops? true}
(fn [ev]
(println "event received!")
(clojure.pprint/pprint ev)))
(crux/submit-tx node [[:crux.tx/put {:crux.db/id :ivan, :name "Ivan"}]])
prints:
event received!
{:crux/event-type :crux/indexed-tx,
:crux.tx/tx-id ...,
:crux.tx/tx-time #inst "...",
:committed? true,
:crux/tx-ops [[:crux.tx/put {:crux.db/id :ivan, :name "Ivan"}]]}
You can .close
the return value from (crux.api/listen …)
to detach the listener, should you need to.
Can you improve this documentation? These fine people already did:
Jeremy Taylor, Jon Pither, James Henderson, Antonelli712, Johantonelli, Tom Taylor, Daniel Mason, Ivan Fedorov & Malcolm SparksEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close