This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-03-06
Channels
- # babashka (60)
- # beginners (36)
- # clj-kondo (29)
- # clojure (91)
- # clojure-dev (18)
- # clojure-europe (12)
- # clojure-nl (1)
- # clojure-norway (11)
- # clojure-uk (5)
- # clojuredesign-podcast (8)
- # clojurescript (40)
- # core-typed (74)
- # data-science (8)
- # datomic (9)
- # emacs (22)
- # events (5)
- # fulcro (56)
- # gratitude (3)
- # hyperfiddle (11)
- # lsp (6)
- # malli (36)
- # meander (23)
- # off-topic (50)
- # polylith (4)
- # portal (10)
- # reitit (4)
- # schema (1)
- # shadow-cljs (66)
- # squint (3)
- # tools-deps (16)
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.
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.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 ...]})