You find yourself at passport control where you are told your Crux experience is needed.

Kaarlang has arrived there first and has been chatting to the manager here. As an advanced civilization, they are quite happily using Crux with no issues, but still have a problem with human error. Some employees have been handing out passports before putting the travelers information into Crux. When it gets particularly busy, it’s not uncommon for the employees to forget to go back and put the data in, resulting in unregistered travelers.

Kaarlang has told the manager that you have a background in solving problems using Crux, so has offered them your skills.

Your task is to make a function that ensures no passport is given before the travelers data is successfully ingested into Crux.

(defn ingest-and-query [traveler-doc] (crux/submit-tx node [[:crux.tx/put traveler-doc]]) (crux/q (crux/db node) {:find '[n] :where '[[e :crux.db/id id] [e :passport-number n]] :args [{'id (:crux.db/id traveler-doc)}]}))

You test out your function.

(ingest-and-query {:crux.db/id :origin-planet/test-traveler :chosen-name "Test" :given-name "Test Traveler" :passport-number (java.util.UUID/randomUUID) :stamps [] :penalties []}) ;;=> #{}

This strikes you as peculiar - you received no errors from your Crux node upon submitting, but the ingested traveler doc has not returned a passport number.

You are sure your query and ingest syntax is correct, but to check you try running the query again. This time you get the expected result:

(ingest-and-query {:crux.db/id :origin-planet/test-traveler :chosen-name "Test" :given-name "Test Traveler" :passport-number (java.util.UUID/randomUUID) :stamps [] :penalties []}) ;;=> #{[#uuid "aa1015d9-83f4-48c3-adc6-386a0816e145"]}

The plot thickens. Confused, you open your trusty Crux manual, skimming through until you hit the page on await-tx :

Blocks until the node has indexed a transaction that is at or past the supplied tx. Will throw on timeout. Returns the most recent tx indexed by the node.

Read More — Crux manual

Of course. Submit operations in Crux are asynchronous - your query did not return the new data as it had not yet been indexed into Crux. You decide to rewrite your function using await-tx :

(defn ingest-and-query "Ingests the given travelers document into Crux, returns the passport number once the transaction is complete." [traveler-doc] (crux/await-tx node (crux/submit-tx node [[:crux.tx/put traveler-doc]])) (crux/q (crux/db node) {:find '[n] :where '[[e :crux.db/id id] [e :passport-number n]] :args [{'id (:crux.db/id traveler-doc)}]}))

You run the function again, Changing the traveler-doc so you can see if it’s worked. This time you receive the following:

(ingest-and-query {:crux.db/id :origin-planet/new-test-traveler :chosen-name "Testy" :given-name "Test Traveler" :passport-number (java.util.UUID/randomUUID) :stamps [] :penalties []}) ;;=> #{[#uuid "87e442fe-14e3-4da2-ba29-468546833c58"]}

Caution Crux is fundamentally asynchronous: you submit a transaction to the central transaction log - then, later, each individual Crux node reads the transaction from the log and indexes it. If you submit a transaction and then run a query without explicitly waiting for the node to have indexed the transaction, you’re not guaranteed that your query will reflect your recent transaction. On a small use-case, you might get lucky - but, if you want to reliably read your writes, use await-tx . If you’re ingesting a large batch of data though, calling await-tx after every transaction will slow the process significantly - you only need to await the final transaction to know that all of the preceding transactions are available.

You show this to the manager at the passport control office. They are happy that this will work.

Thank you, this will save us so much time in dealing with missing traveler information. As a token of our gratitude, we would like to grant you with free entry to the planet. — Passport control manager

You graciously accept. For the passport you must provide your origin planet, name and also a chosen name. Many people come to Kepra-5 in order to start fresh, so your chosen name can be anything you wish.

Once chosen you can not easily change it, so you think carefully.

(ingest-and-query {:crux.db/id :earth/ioelena :chosen-name "Ioelena" :given-name "Johanna" :passport-number (java.util.UUID/randomUUID) :stamps [] :penalties []}) ;;=> #{[#uuid "b75ee2fe-6f2f-47d6-b3b2-7aee3503c5bc"]}

New name, new you.

Now that you are in the Gilese 667C you must keep your passport up to date wherever you travel. You take a note of your passport number and put it somewhere safe.