Fork me on GitHub
#meander
<
2021-01-06
>
ribelo12:01:25

As part of the fun, I'm trying to write something similar to pull-syntax with a meander Let's say I have db in this form.

{:ivan {:db/id :ivan, :name "Ivan" :last-name "Ivanov" :friend :petr}
 :petr {:db/id :petr, :name "Petr" :last-name "Petrov" :friend :smith}
 ...
 ?id   {:db/id ?id
        ?k     ?v}}
(pull db [:name {:friend [:name]}] :ivan)
could be presented in this way
(m/find db
  {?id     {:name   ?name
            :friend ?friend}
   ?friend {:name ?friend-name}}
  {:name   ?name
   :friend {:name ?friend-name}})
But how to make a function that would translate pull-syntax to a meander's query? For now I have something like that, but I can't do it any simpler and more elegant.
(def eid? (some-fn string? keyword? int?))

(defn pull [db selector entity]
  (m/match selector
    {:as ?q}
    (reduce-kv
     (fn [acc k v]
       (m/match v
         (m/pred vector?)
         (assoc acc k (pull db v (get entity k)))))
     {}
     ?q)
    [!ks ...]
    (reduce
     (fn [acc elem]
       (m/match elem
         (m/pred eid?)
         (assoc acc elem (get-in db [entity elem]))
         {}
         (let [entity' (get-in db [entity])]
           (merge acc (pull db elem entity')))))
     {}
     !ks)))