meander 2024-03-06

I'm pretty new to Meander, but I have some pretty straight-forward use cases; I'm having trouble understanding how to express them. Basic example; for this input:

{:widget/id           "xyz"
 :widget/manufacturer {:company/name "Widget Co."}
 :widget/parts        [{:part/id       123
                        :part/location {:bin/id 23}}
                       {:part/id       456
                        :part/location {:bin/id 97}}]}
I'd like to fold/spindle/mutilate to:
{:widget-id         "xyz"
 :manufacturer-name "Widget Co."
 :parts             [{:id  123
                      :bin 23}
                     {:id  456
                      :bin 97}]}
I'm at a loss for how to handle transforming the :widget/parts key. And I'd prefer a solution where I can adapt it to a case where I'm converting multiple widgets, not just one.

Here’s a solution

This is a slightly better one

To explain some of the non-obvious pieces of the solution: • m/some is used to ensure that the key exists in the map. Without it, meander might match the wrong map. • Handling the vector of widget parts is a bit magicky. First, we capture each element of the vector into the memory variable !widget-part . During expansion, we try rewriting each element of the vector against the matching rules. The first match rule fails (because of the m/some keys don’t match). The second rule matches and returns the rewritten data.

Is there something like cata, but I specify the rules right there? That would eliminate the m/some calls if I'm following you.

i.e., can I use m/rewrite inline?

Kind of. You can create a separate function which calls m/rewrite

One sec and I’ll show you

Would you consider what I'm doing a common use case? I think anyone getting Datomic data out on the wire would 😉

Here’s an example of “inline” rewrite

The m/app is necessary because the rewrite macro assumes it’s own micro-language on the right-hand side of the rewrite rule.

In this case, it would be more straightforward to write this code using m/find

It’s just that I normally reach for m/rewrite because it’s so compact and powerful.

As for common use case: Yes! I use meander like this all the time.

As an advanced use case, I will occasionally dynamically generate rewrite rules using the meander strategy namespace.

Here’s an example of using m/find instead of m/rewrite

(oh, you’re right, btw, in these last couple of examples the m/some are not necessary)

I'm happy with this:

(def widget {:widget/id           "xyz"
             :widget/manufacturer {:company/name "Widget Co."}
             :widget/parts        [{:part/id       123
                                    :part/location {:bin/id 23}}
                                   {:part/id       456
                                    :part/location {:bin/id 97}}]})

(defn- rewrite-widget-part [part]
  (m/match part
           {:part/id       ?part-id
            :part/location {:bin/id ?bin-id}}
           {:id  ?part-id
            :bin ?bin-id}))

(m/rewrite widget
           {:widget/id           ?id
            :widget/manufacturer {:company/name ?company-name}
            :widget/parts        [(m/app rewrite-widget-part !widget-parts) ...]}
           {:widget-id         ?id
            :manufacturer-name ?company-name
            :parts             [!widget-parts ...]})
But it feels like there could be some syntax sugar instead of the m/app call.

Thanks for the help!

Sure thing!

Strawman:

(m/rewrite widget
           {:widget/id           ?id
            :widget/manufacturer {:company/name ?company-name}
            :widget/parts        [(m/each !widget-parts
                                          {:part/id       ?part-id
                                           :part/location {:bin/id ?bin-id}}
                                          {:id  ?part-id
                                           :bin ?bin-id}) ...]}
           {:widget-id         ?id
            :manufacturer-name ?company-name
            :parts             [!widget-parts ...]})

I don't have. a feel for how you combine the pieces.