Fork me on GitHub
#datalevin
<
2024-01-23
>
plexus10:01:25

Is is possible to query inside a nested map? e.g. given an entity

{:foo {:bar 123}}
do something like
(ds/q '[:find (pull ?e [*]) 
  :where
  [?e :foo ?foo]
  [(= (get ?foo :bar) 123)]])
I tried this, or with [?foo :bar 123], but neither seem to do the trick.

Huahai19:01:12

You can convert nested maps into structure suitable for Datalevin with libraries such as this: https://github.com/alandipert/intension

Huahai19:01:13

The code is simply this

Huahai19:01:31

(defn paths
  "Returns the set of paths into a nested map/vector."
  ([root]
   {:pre [(or (map? root)
              (vector? root))]}
   (paths [] root))
  ([parent x]
   (cond (map? x)
         (mapcat (fn [[k v]] (paths (conj parent k) v)) x)
         (vector? x)
         (mapcat #(paths (conj parent %1) %2) (range) x)
         :else [parent])))

(defn make-db
  "Converts a nested structure of vectors/maps into a set of tuples suitable for
   query by Datalog.  Attaches the original structure to the vector returned under the :alandipert.intension/original key.

   Takes an optional configuration map that can contain these options:

     :paths? - false by default.  Whether or not to prefix every tuple with the path.
               Useful for processing structures with update-in based on query results."
  [coll & [{:keys [paths?]
            :or   {paths? false}}]]
  (with-meta
    (mapv (fn [path]
            (conj
             (if paths? (vec (list* path path)) path)
             (get-in coll path)))
          (paths coll))
    {::original coll}))

plexus16:01:25

Thank you!