specter

richiardiandrea 2021-07-28T21:38:19.021Z

Hi there, say I have maps that can look like this {:foos [{:xx 1} {:yy 2] :bar "BAR"} {:foos [#uuid "xx" #uuid "yy"] :bar "BAR"} {:foos [{} {}] :bar "BAR"} How can I trim the :foos if "empty" in specter?

richiardiandrea 2021-07-28T21:40:23.021500Z

tried [(sp/must :foos) (sp/pred #(every? empty? %)) (sp/terminal sp/NONE)] but it throws in case of #uuid

isak 2021-07-28T22:03:58.023500Z

@richiardiandrea you should just check for map? first in that pred. Example:

(let [xs [{:foos [{:xx 1} {:yy 2}] :bar "BAR"}
            {:foos [#uuid "123e4567-e89b-12d3-a456-426652340000" #uuid "123e4567-e89b-12d3-a456-426652340010"] :bar "BAR"}
            {:foos [{} {}] :bar "BAR"}]]
    (sp/setval 
      [sp/ALL (sp/must :foos) (sp/pred #(every? (fn [x] (and (map? x) (empty? x))) %))]
      sp/NONE
      xs))

=> [{:foos [{:xx 1} {:yy 2}], :bar "BAR"}
 {:foos [#uuid"123e4567-e89b-12d3-a456-426652340000" #uuid"123e4567-e89b-12d3-a456-426652340010"], :bar "BAR"}
 {:bar "BAR"}]

richiardiandrea 2021-07-28T22:05:03.024Z

oh ok that makes sense - I was thinking there would be more specter magic I was missing instead

isak 2021-07-28T22:09:26.024800Z

This may be better, but depends what you are trying to do (adapted from a similar thing I needed):

(def rec-node-path
    (sp/recursive-path
      [] p
      (sp/cond-path 
        map? (sp/continue-then-stay sp/MAP-VALS p)
        vector? (sp/continue-then-stay sp/ALL p))))

  (let [xs [{:foos [{:xx 1} {:yy 2}] :bar "BAR"}
            {:foos [#uuid "123e4567-e89b-12d3-a456-426652340000" #uuid "123e4567-e89b-12d3-a456-426652340010"] :bar "BAR"}
            {:foos [{} {}] :bar "BAR"}]]
    (sp/setval [sp/ALL :foos rec-node-path empty?] sp/NONE xs))