Liking cljdoc? Tell your friends :D

Transactions

Overview

There are four transaction (write) operations:

Table 1. Write Operations
OperationPurpose

crux.tx/put

Write a version of a document

crux.tx/delete

Deletes the specific document at a given valid time

crux.tx/match

Check the document state against the given document

crux.tx/evict

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.

Valid IDs

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})

  • String (e.g. {:crux.db/id "my-id"})

  • Integers/Longs (e.g. {:crux.db/id 42})

  • UUID (e.g. {:crux.db/id #uuid "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 {:this :id-field}}) (Note: see issue #362).

The #crux/id reader literal will take URI/URL strings and attempt to coerce them into valid IDs.

URIs and URLs are interpreted using Java classes (java.net.URI and java.net.URL respectively) and therefore you can also use these directly.

Operations

Put

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)
1The document itself. Note that the ID must be included as part of the document.
2valid 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.

Delete

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

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)
1Entity id
2Document (or nil)
3(optional) valid time

Evict

Evicts a document from Crux. Historical versions of the document will no longer be available.

[:crux.tx/evict :dbpedia.resource/Pablo-Picasso]

Transaction functions

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}

Events

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, Håkan Råberg & Malcolm Sparks
Edit on GitHub

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close