# Concepts

This section explains Specmonstah's model: the *data* that Specmonstah works with, and the *operations* you can perform on that data. You'll learn these concepts by answering the following questions:

* How does Specmonstah generate data for database insertion?
* How does Specmonstah insert records in the correct order?

### Data Generation

Data generation happens in two phases:

1. You ***add ents*** to an ***ent db***'s ***ent graph***
2. You add the data generated by clojure.spec to each ent as an ***ent attr*** during ***ent visitation***

Let's unpack this.

Specmonstah works by generating an ***ent graph***. Say you want to generate and insert three `topic`s that references a `topic-category`, where the `topic`s and the `topic-category` all reference a `user`. Specmonstah accomplishes this by first creating a graph like this:

![](https://4068685904-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LoN3fu4ydp8osDZFQch%2F-Lor39dRy1ggis9JSMSM%2F-Lor3fkJtNglCy331eQi%2Ftopic-graph.png?alt=media\&token=c006c11f-884c-4afc-bcfd-b5eac3dbe4aa)

In the graph above, we call the `:topic`, `:topic-category`, and `:user` nodes ***ent types*** and the rest ***ents**:*

**Ent type.** An ent type is analogous to a relation in a relational database, or a class in object-oriented programming. It differs in that relations and classes define all the attributes of their instances, whereas ent types don't. Ent types define how instances are related to each other. For example, a Todo *schema* might include a `:description` attribute, but the `:todo` *ent type* doesn't. On the other hand, the `:todo` ent type *does* specify that a `:todo` instances reference `:todo-list` instances.

Ent types are represented as nodes in the ent graph, with directed edges going from ent types to their instances. It's rare that you'll interact with ent types directly.

**Ent.** An ent is an instance of an ent type. Ents have names (`:t0, :u0`, etc), and reference other ents. They're represented as nodes in the ent graph, with directed edges going from ents to the ents they reference; there's a directed edge from `:tl0` to `:u0` because `:tl0` references `:u0`. The graph's topology is used to ensure that `:u0` gets inserted before `:tl0`.

In creating the above graph, we would say that we *add ents* to an *ent db*. An ent db is represented as a map that contains an ent graph.

The ent db also contains a ***schema***. The schema describes how ents of different types refer to each other, and it's used to construct the directed edges between ents. You'll learn all about schemas in a later section of the tutorial.

So that's the first step of data generation: You *add ents* to an *ent db*'s *ent graph*. After that, you add the data generated by clojure.spec to each ent as an ***ent attr***.

For example, the ents `:u0` and `:tl0` are not maps. They're just a graph node, and as such they cannot be inserted in a database. Specmonstah uses clojure.spec to generate data for `:u0` and `:tl0` and then associates the data with `:u0` and `:tl0` as an *ent attr*. You can think of this as being represented using a map like this, with `:spec-gen` as the ent attr:

```scheme
{:u0  {:spec-gen {:username "billy"
                  :id       1}}
 :tc0 {:spec-gen {:id       2
                  :owner-id 1
                  :title    "topic category"}}}
```

### Ent Visitation

The process of adding ent attrs is called ***visitation***. Visiting ent nodes is kind of like mapping: when you call `map` on a seq, you apply a mapping function to each element, creating a new seq from the mapping function's return values. By the same token, when you visit ents you apply a visiting function to each ent. The visiting function's return value is stored as an attribute on the ent - in this case, `:spec-gen`.

Visitation happens in reverse topologically sorted order, meaning that since `:tc0` has a directed edge pointing to `:u0`, the visiting function is applied to `:u0` before `:tc0`. This is how the spec data generating visiting function is able to correctly set `:owner-id` to `1`:

1. The visiting function is applied to `:u0`, generating the `:id` `1`
2. The visiting function is applied to `:tl0`. It's able to use the

   edge from `:tl0` to `:u0` to look up `:u0`'s `:id` and set that

   as the value for `:owner-id`.

The same visitation process that's used to generate data with clojure.spec is also used to insert records in a database. The insertions happen in the correct order, satisfying foreign key constraints.

One more note: When you play with Specmonstah in a REPL, you'll notice that it generates a lot of data. Specmonstah provides a bunch of functions that project different views of the ent db so that you can focus just on whatever's relevant for you. For example, `sm/view` will create an image of the ent graph - it's what I used to create the image at the beginning of this page.

That covers the main data structures and operations:

* **Data**
  * ent db
    * schema
    * ent graph
    * ent attrs
* **Operations**
  * add ents
  * add ent attrs (ent visitation)
  * create views of the ent graph

Now that you have the broad picture of how Specmonstah works, let's start exploring the details with source code. The rest of the tutorial consists of numbered sections with corresponding clojure files under the  examples directory, each introducing new concepts. You'll have the best experience if you follow along in a REPL.
