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:
1
{:username "birb"
2
:favorite-ids [1 2 3 4]}
Copied!
Here's how you'd model this in Specmonstah:
1
(ns reifyhealth.specmonstah-tutorial.11
2
(:require [clojure.spec.alpha :as s]
3
[reifyhealth.specmonstah.core :as sm]
4
[reifyhealth.specmonstah.spec-gen :as sg]))
5
6
(s/def ::id (s/and pos-int? #(< % 100)))
7
8
(s/def ::post (s/keys :req-un [::id]))
9
10
(s/def ::favorite-ids (s/coll-of ::id))
11
(s/def ::user (s/keys :req-un [::id ::favorite-ids]))
12
13
(def schema
14
{:post {:prefix :p
15
:spec ::post}
16
:user {:prefix :u
17
:spec ::user
18
:relations {:favorite-ids [:post :id]}
19
:constraints {:favorite-ids #{:coll}}}})
Copied!
There's our buddy :constraints again :) This time the constraint is :coll. This is used by the clojure.spec visitor to generate data correctly:
1
(defn ex-01
2
[]
3
(sg/ent-db-spec-gen-attr {:schema schema} {:user [[1]]}))
4
5
(ex-01) ;; =>
6
{:p0 {:id 6}
7
:u0 {:id 9, :favorite-ids [6]}}
Copied!
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:
1
(defn ex-02
2
[]
3
(sg/ent-db-spec-gen-attr {:schema schema}
4
{:user [[1 {:refs {:favorite-ids 3}}]]}))
5
(ex-02)
6
;; =>
7
{:p0 {:id 6}
8
:p1 {:id 21}
9
:p2 {:id 8}
10
:u0 {:id 1
11
:favorite-ids [6 21 8]}}
Copied!
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:
1
(defn ex-03
2
[]
3
(sm/view (sm/add-ents {:schema schema}
4
{:user [[2 {:refs {:favorite-ids 3}}]]})))
5
(ex-03)
Copied!
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:
1
(defn ex-04
2
[]
3
(sm/view (sm/add-ents {:schema schema}
4
{:user [[1 {:refs {:favorite-ids [:my-p0 :my-p1]}}]
5
[1 {:refs {:favorite-ids [:my-p2 :my-p3]}}]]})))
6
(ex-04)
Copied!
Last modified 2yr ago
Copy link