Fork me on GitHub
#meander
<
2022-06-01
>
Aleksander13:06:33

Maybe a trivial question... but how can I transform list items of a list nested in a map, eg in the sample structure below I would like to transform both val1 and all of it* items. The return should be a single top level map with nested items updated. Doing a match on each of the it* would work, but I assume there needs to be a better way to do it rather than update-in map match

{:key val1
 :key2 {:key3 [it1 it2 it3]}}

Richie14:06:35

Do you mean like this?

(m/rewrite {:key "val1"
            :key2 {:key3 ["it1" "it2" "it3"]}}
  {:key ?a
   :key2 {:key3 [!b ...]}}
  {:key ?a
   :key2 {:key3 [(m/app string/reverse !b) ...]}})
;; {:key "val1", :key2 {:key3 ["1ti" "2ti" "3ti"]}}

Richie14:06:30

Maybe you mean like this:

(ns scratch
  (:require [meander.epsilon :as m]
            [clojure.string :as string]))

(defn my-fun
  [a b]
  {:a a
   :b b})

(m/rewrite {:key "val1"
            :key2 {:key3 ["it1" "it2" "it3"]}}
  {:key ?a
   :key2 {:key3 [!b ...]}}
  {:key ?a
   :key2 {:key3 [(m/app #(my-fun ?a %) !b) ...]}})
;; {:key "val1", :key2 {:key3 [{:a "val1", :b "it1"} {:a "val1", :b "it2"} {:a "val1", :b "it3"}]}}e

Aleksander14:06:15

hmm, maybe using examples from specter would be easier:

(specter/transform [:sites s/MAP-VALS :services s/ALL] #(meander/match ~~fairly simple map trasformation here, just structure, not using values~~))

Richie14:06:50

Can you give an example input and output?

Aleksander14:06:46

sites:
  site1:
    services:
      mainService:
        name: "name1"
      sidecar1:
        name: "name2"
      sidecar2:
        name: "name3"
  site2:
    services:
      mainService:
        name: "name4"
      sidecar1:
        name: "name5"
      sidecar2:
        name: "name6"
sites:
  site1:
     httpService:
       name: "name1"
     sidecars:
        - name: "name2"
        - name: "name3"
  site2: 
     httpService:
       name: "name4"
     sidecars:
        - name: "name5"
        - name: "name6"    

👍 1
Aleksander14:06:23

the number/name of sites can be variable, we can't depend of them, they need to be maintained

Aleksander14:06:33

same for number of sidecars

Aleksander14:06:15

out of services one has special status and is treated as main service, the rest are sidecars

Aleksander14:06:57

This is still a simplified example. Right now I'm tempted to have few transformations using combination of specter and meander, ie using transform to select appropriate places in the tree to update, use meanders match to do the transformation

Richie16:06:55

(def ex1 {:sites {:site-one {:services {:main-service {:name "s1-main"}
                                        :side-car-one {:name "s1-one"}
                                        :side-car-two {:name "s1-two"}}}
                  :site-two {:services {:main-service {:name "main"}
                                        :side-car-one {:name "s2-one"}
                                        :side-car-two {:name "s2-two"}}}}})

(m/rewrite ex1
  {:sites (m/map-of !k {:services {:main-service !main-service
                                   & (m/app seq ([_ !sidecar] ..!n))}})}
  {:sites (m/map-of !k {:http-service !main-service
                        :sidecars [!sidecar ..!n]})})

;; {:sites {:site-one {:http-service {:name "s1-main"}
;;                     :sidecars [{:name "s1-one"}
;;                                {:name "s1-two"}]}
;;          :site-two {:http-service {:name "main"}
;;                     :sidecars [{:name "s2-one"}
;;                                {:name "s2-two"}]}}}

Aleksander16:06:17

Thanks a lot! That looks near 🙂

👍 1
Aleksander14:06:03

What if I wanted to extend the example with main-service having a key, eg environment that is supposed to go up one level. From being subkey of :main-service to being a sibling of :http-service

(def ex1 {:sites {:site-one {:services {:main-service {:name "s1-main" :environment {:env-var1 "env-var1"}}
                                        :side-car-one {:name "s1-one"}
                                        :side-car-two {:name "s1-two"}}}
                  :site-two {:services {:main-service {:name "main" :environment {:env-var2 "env-var2"}}
                                        :side-car-one {:name "s2-one"}
                                        :side-car-two {:name "s2-two"}}}}})

(m/rewrite ex1
  {:sites (m/map-of !k {:services {:main-service !main-service
                                   & (m/app seq ([_ !sidecar] ..!n))}})}
  {:sites (m/map-of !k {:http-service !main-service
                        :sidecars [!sidecar ..!n]})})

;; {:sites {:site-one {:http-service {:name "s1-main"}
;;                     :environment {:env-var1 "env-var1"}                  
;;                     :sidecars [{:name "s1-one"}
;;                                {:name "s1-two"}]}
;;          :site-two {:http-service {:name "main"}
;;                     :environment {:env-var2 "env-var2"}
;;                     :sidecars [{:name "s2-one"}
;;                                {:name "s2-two"}]}}}