Transformation functions

Transformation functions are pure (= side-effect free) functions or methods which can be used in queries to transform values and bind their results to pattern variables. Say, for example, there exists an attribute :person/born with type :db.type/instant. Given the birthday, it's easy to calculate the (very approximate) age of a person:

(defn age [birthday today]
  (quot (- (.getTime today)
           (.getTime birthday))
        (* 1000 60 60 24 365)))

with this function, we can now calculate the age of a person inside the query itself:

[:find ?age
 :in $ ?name ?today
 :where
 [?p :person/name ?name]
 [?p :person/born ?born]
 [(tutorial.fns/age ?born ?today) ?age]]

A transformation function clause has the shape [(<fn> <arg1> <arg2> ...) <result-binding>] where <result-binding> can be the same binding forms as we saw in chapter 3:

  • Scalar: ?age
  • Tuple: [?foo ?bar ?baz]
  • Collection: [?name ...]
  • Relation: [[?title ?rating]]

One thing to be aware of is that transformation functions can't be nested. You can't write

[(f (g ?x)) ?a]

instead, you must bind intermediate results in temporary pattern variables

[(g ?x) ?t]
[(f ?t) ?a]

Find people by age. Use the function tutorial.fns/age to find the age given a birthday and a date representing "today".

Query:[ I give up! ]

Input #1:

Input #2:

Find people younger than Bruce Willis and their ages.

Query:[ I give up! ]

Input #1:

The birthday paradox states that in a room of 23 people there is a 50% chance that someone has the same birthday. Write a query to find who has the same birthday. Use the < predicate on the names to avoid duplicate answers. You can use (the deprecated) .getDate and .getMonth java Date methods.

Query:[ I give up! ]