# Deriving Values

Some new requirements for our app have come in:

* We want to anonymize admins even further. Their name should be of the form "Admin-X" where 'X' is the admin users id
* Each post should contain the name of its author

(both of these are bad ideas, but office politics forces you to accept them)

Function 'directives' (see [Directives 101](/fabrikk/tutorial/directives-101.md)) won't really help us here since they don't have access to the entity being built. We need a new directive, `derive`:

```clojure
(ns fab.tutorial
  (:require [fabrikk.alpha.core :as fab]))

(defn admin-email []
  (str "admin-" (rand-int 10000) "@example.com"))

(def user
  (fab/->factory
   ::user
   {:template {:id (fab/sequence)
               :name "John Smith"
               :email "john@example.org"
               :role "user"
               :verified true}
    :traits {:admin {:name (fab/derive :id (partial str "Admin-"))
                     :email admin-email
                     :role "admin"}
             :unverified {:verified false}}}))

(def post
  (fab/->factory
   ::post
   {:template {:id random-uuid
               :title "This one weird trick"
               :content "Some content goes here...."
               :author (fab/one ::user)
               :author-name (fab/derive [:author] :name}}))
```

`derive` allows us to, well, *derive* values from either keys on the same entity or from any dependent entities created using `one` (or other similar directives). Its first argument can be a key or a **path** - i.e. it identifies the entity or key to be derived from - the second is a function that's used to transform the source value into the derived value.

We'll go into more detail on paths later, for now it's enough to know that a path is a sequence of one or more keywords. Our path in the post factory is `[:author]` which can be translated to 'derive a value from the entity referenced through the author key', and we're using `:name` as the transform function to get the author's name.

Let's see this in action on the user entity first:

```clojure
(fab/build user {:traits [:admin]})
;; => {:id 1, :name "Admin-1", :email "admin-8575@example.com", :role "admin", :verified true}
(fab/build user {:with {:id 100}
                 :traits [:admin]})
;; => {:id 100, :name "Admin-100", :email "admin-8902@example.com", :role "admin", :verified true}
(fab/build user {:with {:name "Omega-Admin"}
                 :traits [:admin]})
;; => {:id 2, :name "Omega-Admin", :email "admin-7767@example.com", :role "admin", :verified true}
```

The derived value responds to changes in the value of the underlying key - if we specify the ID it gets reflected in the user's name. If we specify the name as a string the `derive` has no effect.&#x20;

Now for the post factory:

```clojure
(fab/build post)
;; => {:author 3,
;;     :id #uuid "233c7e97-f7cf-413b-89e3-69b782c9a4d8",
;;     :title "This one weird trick",
;;     :content "Some content goes here....",
;;     :author-name "John Smith"}

(let [jimmy (fab/build user {:with {:name "Jimmy Murphy"}})]
  (fab/build post {:with {:author jimmy}}))
;; => {:author 4,
;;     :id #uuid "564653ee-5e06-40bd-a5a0-8cf8b0032172",
;;     :title "This one weird trick",
;;     :content "Some content goes here....",
;;     :author-name "Jimmy Murphy"}
```

As before: if we change the name of the author user, we change the value of the author-name key. Now let's try:

```clojure
(fab/build post {:with {:author-name (fab/derive :author str)
                        :author-email (fab/derive [:author] :email)}})
;; => {:author 5,
;;     :id #uuid "781f0ca7-6399-46de-b056-3232cae71a98",
;;     :title "This one weird trick",
;;     :content "Some content goes here....",
;;     :author-name "5",
;;     :author-email "john@example.org"}
```

There are a few things to unpack here:

* The `derive` directive works happily in a `:with` option
* If we derive from the keyword `:author` instead of a path `[:author]`, we derive from the value of that key on the post entity we build - in this case the id of the author entity
* We can derive multiple values from the same dependent entity


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://deadeyejoe.gitbook.io/fabrikk/tutorial/deriving-values.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
