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:
?age
[?foo ?bar ?baz]
[?name ...]
[[?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".
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! ]