Hi, I was wondering if anyone knows the answer or could point me at a resource that would help me solve this problem.
I want to generate a list of entity-ids and then a list of entities, the catch is I want each entity in the list to be generated with an id that corresponds to a list from the entity id.
(s/def ::id (s/with-gen string? #(s/gen #{"a" "b" "c" "d"})))
(s/def ::entity-ids (s/coll-of ::id :count 2 :distinct true))
(s/def ::entity (s/keys :req-un [::id]))
(s/def ::entities (s/coll-of ::entity :count 4 :distinct true))
(s/def ::manifest (s/keys :req-un [::entity-ids]))
(s/def ::manifests (s/coll-of ::manifest :count 2 :distinct true))
(s/def ::foo (s/keys :req-un [::manifests ::entities]))
(gen/generate (s/gen ::foo))
;; output
{:manifests [{:entity-ids ["d" "a"]}
{:entity-ids ["a" "b"]}],
;; c is in neither of the manifests entity lists
:entities [{:id "a"}
{:id "d"}
{:id "c"}
{:id "b"}]}
;; But what I want is below.
;; Each entity has an id that maps to at least one of the entity-id lists
{:manifests [{:entity-ids ["a" "b"]}
{:entity-ids ["c" "d"]}],
:entities [{:id "a"}
{:id "d"}
{:id "c"}
{:id "b"}]}
If I haven’t made the problem clear enough, please let me know and I’ll try and elaborate. Thanks in advance!
That’s the part that I was missing! I completely forgot that s/and uses the first predicate/spec as a generator and those after it can narrow down the results. It makes perfect sense, like you said my spec for foo wasn’t capturing the constraint that I wanted, so it obviously wouldn’t generate the correct data.
Here’s what I ended up with if anyone is interested:
I started running into issues where spec was unable to generate large consistent sets in 100 tries. The solution I found was to use a custom generator with single item set that guaranteed that the manifest and the items would have the same keys. I don’t feel like this is a particularly elegant solution but it does work.
The data format is slightly different to that in my initial question.
Just read the PurelyFunctional.tv newsletter, (read issue 330 in full), which mentioned this. You’ve got your solution, but if you’re interested in more context, the newsletter might give you that.
@ericnormand provides an example for E-mail generation. Snipped from the newsletter (hope that’s okay):