ex-01
function, we see that it calls sg/ent-db-spec-gen
. As you saw earlier, this creates the ent db and uses clojure.spec to generate a map for each ent, storing the map under the ent's :spec-gen
attribute. The resulting ent db is passed to sm/visit-ents
with the visit key :insert
and visiting function insert
.insert
works by:database
atom by conjing a vector of thespec-gen
.insert
line by line::ent-type
, :visit-val
, and :spec-gen
. The full map includes::spec-gen
):visit-val
, the value from previous visits if there have been any:visit-key
- when the visiting function returns, its value is:visit-key
:query-opts
- any query opts like {:refs {} :spec-gen {}}
for:visit-query-opts
- any query opts meant for this visiting fn(when-not visit-val ...)
, checks whether insert
has already visited this ent. (I'll explain why you want to perform this check soon.) If the ent hasn't been visited, the database
gets updated by conjing a vector of the ent-type
and spec-gen
. The database
atom ends up with a value like this::user
first, then :topic
, then :post
.(when-not visit-val ...)
. You want to perform this check because of Specmonstah's progressive construction feature. As we covered in 05: Progressive construction, it's possible to pass an ent-db to successive calls to sm/add-ents
. If you added more ents and wanted to insert, you wouldn't want to re-insert previous ents. ex-02
demonstrates this::user
, :todo-list
, and :todo
ents from the first call to ent-db-spec-gen
are only inserted once, even though they are visited by insert
multiple times.ent-db-spec-gen
internally calls sm/add-ents
and then calls the sg/spec-gen
visiting function. sg/spec-gen
is written with this same principle in mind: it can visit the ent db multiple times, and won't overwrite any existing values. The pattern is common enough that Specmonstah provides the sm/visit-ents-once
which you can use instead of sm/visit-ents
:when-not
conditional yourself, visit-ents-once
checks whether any value exists for the visiting function (even nil
or false
), and if it does, it doesn't apply the visiting function to that ent.visit-ents
and visit-ents-once
, you should be able to handle most use cases. The rest of the guide covers more specific modeling uses cases, like: like
the same post twice)binding
to specify that all the refs in an entire hierarchy should refer to a specified entlike
can refer to either post
or a topic
)