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]