Hey, I've got a data structure (which I cannot change) like
[{:identifier "abc" :other-key-1 "abc"}
{:identifier "SELF" :content {}}
{:identifier "def" :other-key-2 []}]
I would like to do the following:
1. Determine if there is exactly one item in the vector of maps which has the :identifier "SELF".
2. For that item, determine if there exists the key :content
3. Make sure its value is a map (whose properties I also would like to spec)
Can anyone think of a good way of doing this in spec or give me pointers of how to think about this?(require '[clojure.spec.alpha :as s])
(def d [{:identifier "abc" :other-key-1 "abc"}
{:identifier "SELF" :content {}}
{:identifier "def" :other-key-2 []}])
(defn- self-id? [{:keys [identifier]}] (= "SELF" identifier))
(s/def :self/identifier #{"SELF"})
(s/def :self/content (s/keys)) ; TBD
(s/def ::self (s/keys :req-un [:self/identifier :self/content]))
(s/def ::not-self (s/or :!m (complement map?) :!self (complement self-id?)))
(s/explain-data ::self (first (filter self-id? d)))
(s/def ::d (s/and (s/coll-of map?)
(s/cat :before (s/* ::not-self)
:self ::self
:after (s/* ::not-self))))
(s/explain-data ::d d)
(s/conform ::d d)
; {:before [[:!self {:identifier "abc", :other-key-1 "abc"}]],
; :self {:identifier "SELF", :content {}},
; :after [[:!self {:identifier "def", :other-key-2 []}]]}This is fantastic! Thank you so much, @clojurians-slack100
> "...pointers of how to think about this"
Thing of it like regex: you want to match 0 or more non-self maps, followed by a self map, followed by 0 or more non-self maps.
(An s/not spec would've been handy here.)
Yeah, like a regex. It totally makes sense. The docs even stated this, but just didn't come up with this in the moment.
> An s/not spec would've been handy here.
🤔 Interesting. I see, for the :not-self ...
Yeah, I would've liked to do (s/not ::self) rather than having to define a negation of ::self manually, because now they could drift out of sync.
Yes. I have an intuition that it should generally be possible to make such a thing. One would need to account for the different, uhm, don't know the name, the different things like s/keys , s/cat and so on. The negation of the s/keys was an s/or with complement. Not in the mood to solve that puzzle right now, but certainly an interesting challenge 😀