> For the complete documentation index, see [llms.txt](https://sweet-tooth.gitbook.io/specmonstah/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sweet-tooth.gitbook.io/specmonstah/tutorial/06-spec-gen.md).

# 06: spec-gen

If you're not familiar with clojure.spec, check out [the spec guide on clojure.org](https://clojure.org/guides/spec). It's very well-written.

Our code:

```scheme
(ns reifyhealth.specmonstah-tutorial.06
  (:require [reifyhealth.specmonstah.core :as sm]
            [clojure.spec.alpha :as s]
            [clojure.spec.gen.alpha :as gen]
            [reifyhealth.specmonstah.spec-gen :as sg]))

(s/def ::id (s/and pos-int? #(< % 100)))
(s/def ::not-empty-string (s/and string? not-empty #(< (count %) 10)))

(s/def ::username ::not-empty-string)
(s/def ::user (s/keys :req-un [::id ::username]))

(s/def ::name ::not-empty-string)
(s/def ::topic (s/keys :req-un [::id ::name ::owner-id]))

(s/def ::owner-id ::id)
(s/def ::topic-id ::id)
(s/def ::content ::not-empty-string)
(s/def ::post (s/keys :req-un [::id ::owner-id ::topic-id ::content]))

(def schema
  {:user  {:prefix :u
           :spec   ::user}
   :topic {:prefix    :t
           :spec      ::topic
           :relations {:owner-id [:user :id]}}
   :post  {:prefix    :p
           :spec      ::todo
           :relations {:topic-id [:topic :id]}}})

(defn ex-01
  []
  {:user  (gen/generate (s/gen ::user))
   :topic (gen/generate (s/gen ::topic))
   :post  (gen/generate (s/gen ::post))})
```

First we define some specs (lines 7-19) to generate a little dummy data. Here's what the raw generated data looks like:

```scheme
(ex-01) ;=>
{:user  {:id 2,  :username "G95seixU"},
 :topic {:id 11, :name "stA9xO50w", :owner-id 1},
 :post  {:id 57, :owner-id 2, :topic-id 2, :content "937x"}}
```

That's useful, but we can't insert that into a test database because the foreign keys wouldn't match the values they reference. The `:topic`'s `:owner-id`, for example, is `1`, where the `:user`'s `:id` is `2`.

We can use `reifyhealth.specmonstah.spec-gen/ent-db-spec-gen` to generate data and then assign the foreign keys:

```scheme
(defn ex-02
  []
  (:data (sg/ent-db-spec-gen {:schema schema} {:post [[1]]})))

(ex-02)
; =>
{:nodeset #{:t0 :topic :p0 :u0 :post :user},
 :adj     {:post #{:p0}, :p0 #{:t0}, :topic #{:t0}, :t0 #{:u0}, :user #{:u0}},
 :in      {:p0 #{:post}, :t0 #{:topic :p0}, :u0 #{:t0 :user}},
 :attrs   {:post  {:type :ent-type},
           :p0    {:type                 :ent,
                   :index                0,
                   :ent-type             :post,
                   :query-term           [1],
                   :loom.attr/edge-attrs {:t0 {:relation-attrs #{:topic-id}}},
                   :spec-gen             {:id 2, :owner-id 7, :topic-id 16, :content "3IU"}},
           :topic {:type :ent-type},
           :t0    {:type                 :ent,
                   :index                0,
                   :ent-type             :topic,
                   :query-term           [:_],
                   :loom.attr/edge-attrs {:u0 {:relation-attrs #{:owner-id}}},
                   :spec-gen             {:id 16, :name "FM4fcV3t", :owner-id 2}},
           :user  {:type :ent-type},
           :u0    {:type       :ent,
                   :index      0,
                   :ent-type   :user,
                   :query-term [:_],
                   :spec-gen   {:id 2, :username "xh"}}}}
```

Oh wow, OK. That's a lot to look at. Let's step through it.

We're looking at the value for the ent db's `:data` key. This is the loom graph that we've looked at in earlier sections, the graph returned by `add-ents` that captures ents and their relationships. Under the `:attrs` key, you can see that each ent (`:p0`, `:t0`, and `:u0`) now has the attribute `:spec-gen`. Under `:spec-gen` is a map that's been generated using clojure.spec, except that the foreign keys have been updated to be correct.

Sometimes you want to view just the data that clojure.spec has generated; viewing the entire ent db is overwhelming. To make that easier, Specmonstah has the `reifyhealth.specmonstah.core/attr-map` function:

```
(defn ex-03
  []
  (-> (sg/ent-db-spec-gen {:schema schema} {:todo [[1]]})
      (sm/attr-map :spec-gen)))

(ex-03)
;; =>
{:p0 {:id 30, :owner-id 6, :topic-id 11, :content "03hK"}
 :t0 {:id 11, :name "A4rq01NK", :owner-id 84}
 :u0 {:id 84, :username "QN8J68"}}
```

`attr-map` returns a map where the keys are ent names and the values are the value of the given node attribute (`:spec-gen` here) for each ent. There's a convenience function that combines `sg/ent-db-spec-gen` and `sm/attr-map`, `sg/ent-db-spec-gen-attr`:

```
(defn ex-04
  []
  (sg/ent-db-spec-gen-attr {:schema schema} {:post [[1]]}))

(ex-04)
;; =>
{:p0 {:id 2, :owner-id 20, :topic-id 2, :content "573AAM1D"}
 :t0 {:id 2, :name "6q7a4", :owner-id 2}
 :u0 {:id 2, :username "h"}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://sweet-tooth.gitbook.io/specmonstah/tutorial/06-spec-gen.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
