11: collection constraint (vector of foreign keys)

Let's say the forum you're building stores a user's favorite posts as a vector of foreign keys, like this:

{:username "birb"
 :favorite-ids [1 2 3 4]}

Here's how you'd model this in Specmonstah:

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

(s/def ::id (s/and pos-int? #(< % 100)))

(s/def ::post (s/keys :req-un [::id]))

(s/def ::favorite-ids (s/coll-of ::id))
(s/def ::user (s/keys :req-un [::id ::favorite-ids]))

(def schema
  {:post {:prefix :p
          :spec   ::post}
   :user {:prefix      :u
          :spec        ::user
          :relations   {:favorite-ids [:post :id]}
          :constraints {:favorite-ids #{:coll}}}})

There's our buddy :constraints again :) This time the constraint is :coll. This is used by the clojure.spec visitor to generate data correctly:

Specmonstah generated a post with :id 6, and sure enough you can see that the value of :favorite-ids is a vector containing the post's :id. But what if you want to generate multiple posts? Here's how you'd do that:

And boom goes the dynamite. The key here is the map {:refs {:favorite-ids 3}} - this tells Specmonstah that this user will have 3 :favorite-ids.

You might be wondering, what happens if you generate 2 separate users, each with 3 :favorite-ids? Well my friend, wonder no more:

Both users reference the same posts because Specmonstah generates the minimum data necessary to satisfy the query. You can also "manually" specify the ents you want to reference:

Last updated

Was this helpful?