meander

2022-06-01T13:13:33.189669Z

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]}}

Richie 2022-06-01T14:05:35.875919Z

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"]}}

Richie 2022-06-01T14:07:30.607709Z

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

2022-06-01T14:33:15.125979Z

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~~))

Richie 2022-06-01T14:33:50.749259Z

Can you give an example input and output?

2022-06-01T14:51:46.312309Z

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
2022-06-01T14:52:23.622329Z

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

2022-06-01T14:52:33.788899Z

same for number of sidecars

2022-06-01T14:53:15.759959Z

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

2022-06-01T14:57:57.765569Z

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

Richie 2022-06-01T16:05:55.121459Z

(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"}]}}}

2022-06-01T16:36:17.546299Z

Thanks a lot! That looks near 🙂

👍 1
Richie 2022-07-03T20:45:20.202139Z

2022-06-24T14:24:03.677349Z

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"}]}}}