# Infomercial

In the time-honored tradition of infomercials everywhere, these snippets gloss over a lot of details to reveal the truest, purest essence of a product. If you want to go all FDA on me and validate the claims, check out [the full source](https://app.gitbook.com/s/-LoN3fu4ydp8osDZFQch/examples/reifyhealth/infomercial.cljc).

The code below will ~~shout at~~ show you how you can generate and insert data for a forum's database. Here's an entity relationship diagram for the database:

![](https://4068685904-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LoN3fu4ydp8osDZFQch%2F-LoOIyaDu11URvAmPD_H%2F-LoOJArJBzYaUpCqZBZo%2Fforum-erd.png?alt=media\&token=d9155484-a1c1-441d-acae-87f6fe3a0500)

One thing the diagram doesn't capture is that, for the `like` type, there's a uniqueness constraint on `post-id` and `created-by-id`. Also, every instance of `created-by-id` and `updated-by-id` refers to a user, but including that in the diagram would just clutter it.

(You will learn later how to declare the entity schema with relationship and other constraints to Specmonstah. You can also have a look at the `(def schema ...)` in the [infomercial source code](https://app.gitbook.com/s/-LoN3fu4ydp8osDZFQch/examples/reifyhealth/infomercial.cljc).)

### Insert entity hierarchy in dependency order, with correct foreign keys

Posts have a foreign key referencing a Topic, Topics reference a Topic Category, and all of these reference a User. The snippet below shows that you can specify that you want one Post created, and Specmonstah will ensure that the other entities are created and inserted in dependency order:

```scheme
(insert {:post [[1]]})
@mock-db
; =>
[[:user {:id 1 :username "K7X5r6UVs9Mm2Eks"}]
 [:topic-category {:id 2 :created-by-id 1 :updated-by-id 1}]
 [:topic {:id 5
          :topic-category-id 2
          :title "ejJ2B88UZo2NK2sMuU4"
          :created-by-id 1
          :updated-by-id 1}]
 [:post {:id 9 :topic-id 5 :created-by-id 1 :updated-by-id 1}]]
```

The `insert` function is an example of code you might write to manage the relationship between specmonstah-generated data and your own database. In this case, `insert` simulates inserting records in a db by conjing entities on an `mock-db` atom. The maps were generated using `clojure.spec`. Notice that all the foreign keys line up.

### Specify different users

In the previous example, all entities referenced the same User. In this one, the Topic's `created-by-id` will reference a new user:

```scheme
(insert {:topic [[:t0 {:refs {:created-by-id :custom-user}}]]
         :post [[1]]})
@mock-db
; =>
[[:user {:id 1 :username "gMKGTwBnOvB0xt"}]
 [:topic-category {:id 2 :created-by-id 1 :updated-by-id 1}]
 [:user {:id 5 :username "2jK0TXCU2UcBM89"}]
 [:topic {:id 6
          :topic-category-id 2
          :title "cmo2Vg8DQByz302c"
          :created-by-id 5
          :updated-by-id 1}]
 [:post {:id 10 :topic-id 6 :created-by-id 1 :updated-by-id 1}]]
```

Two users, one with `:id 1` and another with `:id 5`. The topic's `:created-by-id` attribute is 5, and all other User references are `1`.

### Multiple entities

What if you want to insert 2 or 3 or more posts?

```scheme
(insert {:post [[3]]})
@mock-db
; =>
[[:user {:id 1 :username "yB96fd"}]
 [:topic-category {:id 2 :created-by-id 1 :updated-by-id 1}]
 [:topic {:id 5
          :topic-category-id 2
          :title "KEh29Ru7aVVg2"
          :created-by-id 1
          :updated-by-id 1}]
 [:post {:id 9 :topic-id 5 :created-by-id 1 :updated-by-id 1}]
 [:post {:id 13 :topic-id 5 :created-by-id 1 :updated-by-id 1}]
 [:post {:id 17 :topic-id 5 :created-by-id 1 :updated-by-id 1}]]
```

Just say "I want 3 posts" and Specmonstah delivers.

### Uniqueness constraints

You can't have two Likes that reference the same Post and User; in other words, a User can't Like the same Post twice. Specmonstah will automatically generate unique Users if you specify multiple Likes:

```scheme
(insert {:like [[3]]})
@mock-db
; =>
[[:user {:id 1 :username "T2TD3pAB79X5"}]
 [:user {:id 2 :username "ziJ9GnvNMOHcaUz"}]
 [:topic-category {:id 3 :created-by-id 2 :updated-by-id 2}]
 [:topic {:id 6
          :topic-category-id 3
          :title "4juV71q9Ih9eE1"
          :created-by-id 2
          :updated-by-id 2}]
 [:post {:id 10 :topic-id 6 :created-by-id 2 :updated-by-id 2}]
 [:like {:id 14 :post-id 10 :created-by-id 1}]
 [:like {:id 17 :post-id 10 :created-by-id 2}]
 [:user {:id 20 :username "b73Ts5BoO"}]
 [:like {:id 21 :post-id 10 :created-by-id 20}]]
```

Three Likes, Three different Users, and we're not violating the uniqueness constraint. With just one line of code. I think this feature is particularly cool.

### Polymorphic relations

Whereas foreign keys in RDBMSs must reference records in a specific table, some databases like Datomic have reference types attributes that can reference any entity at all. You might want to use this in your forum so that users can like either Topics or Posts. Specmonstah handles this use case.

There are two snippets below. In the first, you say you want to create three `:polymorphic-like`s with `{:ref-types {:liked-id :post}}`. Specmonstah generates 3 likes that refer to a post. The second snippet includes `{:ref-types {:liked-id :topic}}`, so the likes refer to a topic. Polymorphic references compose with uniqueness constraints, so three users are created, just like in the previous snippet.

```scheme
(insert {:polymorphic-like [[3 {:ref-types {:liked-id :post}}]]})
@mock-db
[[:user {:id 1 :username "gI3q3Y6HR1uwc"}]
 [:user {:id 2 :username "klKs7"}]
 [:topic-category {:id 3 :created-by-id 2 :updated-by-id 2}]
 [:topic {:id 6
          :topic-category-id 3
          :title "RF6g"
          :created-by-id 2
          :updated-by-id 2}]
 [:post {:id 10 :topic-id 6 :created-by-id 2 :updated-by-id 2}]
 [:polymorphic-like {:id 14 :liked-id 10 :created-by-id 1}]
 [:polymorphic-like {:id 17 :liked-id 10 :created-by-id 2}]
 [:user {:id 20 :username "Gcf"}]
 [:polymorphic-like {:id 21 :liked-id 10 :created-by-id 20}]]


(insert {:polymorphic-like [[3 {:ref-types {:liked-id :topic}}]]})
@mock-db
[[:user {:id 1 :username "5Z382YCNrJB"}]
 [:topic-category {:id 2 :created-by-id 1 :updated-by-id 1}]
 [:topic {:id 5
          :topic-category-id 2
          :title "i3"
          :created-by-id 1
          :updated-by-id 1}]
 [:user {:id 9 :username "dJtC"}]
 [:polymorphic-like {:id 10 :liked-id 5 :created-by-id 9}]
 [:polymorphic-like {:id 13 :liked-id 5 :created-by-id 1}]
 [:user {:id 16 :username "8ZS"}]
 [:polymorphic-like {:id 17 :liked-id 5 :created-by-id 16}]]
```

### Visualization

Sometimes you want to inspect all the work that Specmonstah is doing for you. One way to do that is to produce an image of the entities Specmonstah produces, and their relationships:

```scheme
(lio/view (:data (sm/add-ents {:schema schema} {:like [[2]]})))
```

![](https://4068685904-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LoN3fu4ydp8osDZFQch%2F-LoOIyaDu11URvAmPD_H%2F-LoOJUS3KkFqYO7TRX-i%2Flike-graph.png?alt=media\&token=eef4e244-fb90-4471-8851-635ff9f2cae4)

This shows that that two Likes were generated (`l0` and `l1`). The Likes are applied to a Post (`p0`), and so forth.

And that brings the infomercial to a close. If you're ready to learn how you, too, can accomplish these amazing feats, read on!


---

# 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://sweet-tooth.gitbook.io/specmonstah/infomercial.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.
