01: ent db

The end db is the central data structure that Specmonstah works on.

In this section you'll learn about the ent db, which is central to how Specmonstah works.To start, open reifyhealth.specmonstah-tutorial.01. It looks like this:

(ns reifyhealth.specmonstah-tutorial.01
  (:require [reifyhealth.specmonstah.core :as sm]
            [loom.io :as lio]))

(def schema
  {:user {:prefix :u}})

(defn ex-01
  []
  (sm/add-ents {:schema schema} {:user [[3]]}))

Specmonstah works by constructing a graph whose nodes correspond to the fixture records we want to insert. That graph (plus the schema used to construct the graph) is stored in a Clojure map that we refer to as the ent db.

In the example above, you're using sm/add-ents to perform a fundamental Specmonstah operation: adding an ent graph to an ent db. The function takes two arguments: an ent db and a query to generate ents. (Queries are covered in section 03 of the tutorial).

This means that the map {:schema schema} is a valid ent db. It's an ent db with no ents added. sm/add-ents generates the ent graph, and returns a new ent db:

(ex-01) ;=>
{:schema {:user {:prefix :u}}
 :data {:nodeset #{:u1 :u0 :u2 :user}
        :adj {:user #{:u1 :u0 :u2}}
        :in {:u0 #{:user} :u1 #{:user} :u2 #{:user}}
        :attrs {:user {:type :ent-type}
                :u0 {:type :ent, :index 0, :ent-type :user, :query-term [3]}
                :u1 {:type :ent, :index 1, :ent-type :user, :query-term [3]}
                :u2 {:type :ent, :index 2, :ent-type :user, :query-term [3]}}}
 :queries ({:user [[3]]})
 :relation-graph {:nodeset #{:user} :adj {} :in {}}
 :types #{:user}
 :ref-ents []}

We only care about the :schema and :data keys. The rest are mostly used internally and can be ignored. I'm only showing them so that you'll have a clearer picture of what an ent db is: a Clojure map of a particular shape.

The ent graph is stored under the :data key of the ent db. The graph stores ent nodes, their relationships, and their ent attributes (as opposed to business attributes). In this ent db there are three users, :u0, :u1, and :u2. There aren't any ent relationships because our schema didn't specify any, but each ent does have attributes: :type, :index, :ent-type, and :query-term. I know I've said it multiple times already, but these are ent attributes, which are distinct from business attributes. The latter are the attributes related to whatever domain you're modeling; for users, these might include name, username, email address, and so forth. As you go through the tutorial, you'll see how a lot of Specmonstah functions involve reading and updating ents' attributes.

The schema is stored under the :schema key of the ent db. In this case, the schema is {:user {:prefix :u}}, which is as simple a schema as possible. In later sections, you'll learn more about schemas and how they're used to define relationships and constraints among ents.

It happens that the ent graph is produced by loom, a sweet little library for working with graphs. Specmonstah doesn't try to hide this implementation detail from you: it's entirely possible you'll want to use one of loom's many useful graph functions to interact with the ent db's data. You might, for instance, want to render the graph as an image. Try this in your REPL:

(lio/view (:data (ex-01)))

While it's useful to know that Specmonstah's ent graph is implemented using loom, if you're using Specmonstah in the REPL then viewing the entire raw loom graph is often overwhelming and unnecessary. The following functions help you project a more useful view of the ent db:

(-> (ex-01)
    (sm/ents-by-type))

(-> (ex-01)
    (sm/ent-relations :u0))

(-> (ex-01)
    (sm/all-ent-relations))

I encourage you to try these functions out in the REPL. Some of them reveal information about ent relationships and so will only be useful when we're working with more than one ent type; try those functions out in the next section as well as you can get a better idea of what they do.

Adding ents to an ent db is the first step whenever you're using Specmonstah. The two main ingredients for building an ent db are the query and schema. In the next section, we'll explain how schemas work, and section 3 will explain queries.

Last updated