This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-10-07
Channels
- # announcements (10)
- # architecture (25)
- # babashka (5)
- # beginners (95)
- # calva (1)
- # cider (3)
- # clerk (16)
- # clj-on-windows (41)
- # clojure (64)
- # clojure-europe (7)
- # clojurescript (9)
- # deps-new (2)
- # graalvm (25)
- # honeysql (3)
- # hyperfiddle (19)
- # malli (1)
- # meander (5)
- # music (1)
- # nbb (1)
- # off-topic (54)
- # rdf (10)
- # releases (2)
- # shadow-cljs (12)
- # tools-deps (41)
Is it possible to match the path to a node matching some predicate, through an arbitrarily nested data structure? For example, I can do this to get the binding I care about:
(def pull
[:db/id
{:menu/items
[:db/id
{:menu.item/entities
[{:translatable/fields
[:field/key
:field/content]}]}]}])
(m/search pull
(m/$ (m/scan (m/pred translatable-binding? ?binding)))
?binding)
;; => (#:translatable{:fields [:field/key :field/content]})
But what I'd really like to be able to do is something like this:
(m/search pull
(PATH-OP (m/scan (m/pred translatable-binding? ?path)))
?path)
;; => [1 :menu/items 1 :menu.item/entities 0]
I've had some luck with this simplified example using map?
as a predicate:
(m/search [:a :b :c {:d [:e {:f :g}]} [{}]]
[(m/not (m/pred map?)) ..?n {?k ?v} & _]
(concat [?n ?k] (m/cata (doto ?v prn))))
; (out) [:e {:f :g}]
;; => ((3 :d))
However, I'm not sure why the recursion is coming back with nil
. The value of ?v
is what I expect based on the output.ah, I was using cata
on the RHS when it should've been on the left.
Got this working!
(let [tree pull
search-key :translatable/fields
pred #(some #{'* :field/content} %)]
(m/search
tree
{~search-key (m/pred pred ?v)}
{search-key ?v}
[_ ..?n (m/cata ?map) & _]
[[?n] ?map]
[_ ..?n {(m/and (m/not ~search-key) ?k) (m/cata ?v)} & _]
(let [[path m] ?v]
[(vec (concat [?n ?k] path)) m])))
^ That replaces about 75 lines of baroque, buggy Clojure...I think I'm in love 😍