Skip to content

Commit

Permalink
datalog shugar
Browse files Browse the repository at this point in the history
  • Loading branch information
niquola committed Aug 4, 2023
1 parent 4b50541 commit 8a23c3f
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 121 deletions.
5 changes: 5 additions & 0 deletions .dir-locals.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
((clojure-mode
(cider-clojure-cli-aliases . "-A:nrepl")))


;; (setq cider-clojure-cli-aliases "-A:nrepl")
35 changes: 35 additions & 0 deletions customers-x/queries.zd
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
:title "Queries"

:desc /

:menu-order 10
:query ?/

e :parent #people
e :desc d
\(clojure.string/includes? d "open")
e :title t
t :desc

> e
> e:title

:items ?/

e :type :needs
e :value v


> (min v)
> (max v)
> (avg v)
> (count v)


&item-1
:type :needs
:value 5

&item-2
:type :needs
:value 4
116 changes: 1 addition & 115 deletions src/zd/blocks/content.clj
Original file line number Diff line number Diff line change
Expand Up @@ -50,120 +50,6 @@
(d/query ztx data)))



(defn parse-query [q]
(let [xs (->> (str/split q #"\n")
(remove (fn [s] (or (str/blank? s) (str/starts-with? s "\\")))))
columns (->> xs
(filterv #(re-matches #"^\s?>.*" %))
(mapv #(subs % 1))
(mapv str/trim)
(filterv #(not (str/blank? %)))
(mapv (fn [x]
(if (str/starts-with? x "(")
['expr (edamame.core/parse-string x {:regex true})]
(let [[e k] (str/split x #":" 2)]
[(symbol e) (cond
(= k "*") (symbol k)
(nil? k) :meta/docname
:else (keyword k))])))))
index (atom {})
find-items (->> (group-by first columns)
(reduce (fn [acc [k xs]]
(if (= 'expr k)
(->> (mapv second xs)
(reduce (fn [acc e]
(swap! index assoc e (count acc))
(conj acc e))
acc))
(let [cs (->> (mapv second xs) (dedupe) (into []))]
(swap! index assoc k (count acc))
(if (filter (fn [x] (contains? #{'x :?} x)) cs)
(conj acc (list 'pull k ['*]))
(if (seq cs)
(conj acc (list 'pull k cs))
(conj acc k))))))
[]))
where-items
(->> xs
(filterv (every-pred #(not (str/ends-with? % " :asc"))
#(not (str/ends-with? % " :desc"))
#(not (re-matches #"^\s?>.*" %))))
(mapv (fn [x] (let [res (edamame.core/parse-string (str/replace (str "[" x "]") #"#" ":symbol/")
{:regex true})]
(cond
(list? (get res 1))
(vector res)

:else
res)
))))
where (->> where-items
(mapv (fn [x]
(clojure.walk/postwalk
(fn [y]
(if (and (keyword? y) (= "symbol" (namespace y)))
(str "'" (name y))
y)) x))))

order-items
(->> xs
(filterv (every-pred #(or (str/ends-with? % " :asc")
(str/ends-with? % " :desc"))
#(not (re-matches #"^\s?>.*" %))))
(mapv (fn [x] (edamame.core/parse-string (str/replace (str "[" x "]") #"#" ":symbol/") {:regex true}))))

order
(->> order-items
(mapv (fn [x]
(clojure.walk/postwalk
(fn [y]
(if (and (keyword? y) (= "symbol" (namespace y)))
(str "'" (name y))
y)) x))))]
(into {:where where
:order order
:find find-items
:columns columns
:index @index} )))



(def q
"
e :parent #organizations
e :rel #rel.partner
p :organization e
p :role #roles.cto
> d
> e:xt/id
> e:rel
> (count e)
> (mean e)
")

(def q2
"
e :parent #customers
e :category cat
(clojure.string/starts-with? cat \"s\")
e :customer-since since
e :asc
> e:name
> (count e)
"
)

(def q3
"
e :parent #customers
e asc
> e
")

(parse-query q3)

(defn render-table-value [ztx v block]
(cond
(symbol? v) (link/symbol-link ztx v)
Expand All @@ -177,7 +63,7 @@ e asc

(defmethod methods/rendercontent :?
[ztx ctx {{headers :table-of} :ann data :data :as block}]
(let [q (parse-query data)
(let [q (d/parse-query data)
idx (:index q)
res (d/query ztx (dissoc q :columns :index))
res (->> res
Expand Down
81 changes: 81 additions & 0 deletions src/zd/datalog.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
(:require [zen.core :as zen]
[clojure.walk]
[clojure.string :as str]
[edamame.core]
[xtdb.api :as xt]))

(defn get-state [ztx]
Expand Down Expand Up @@ -49,6 +50,10 @@
(let [xtdb-doc (flatten-doc ztx doc)
result (submit ztx xtdb-doc)]
;; TODO und where does result go in pub/sub
(doseq [[k sd] (:zd/subdocs doc)]
(let [pid (get-in doc [:zd/meta :docname])
id (str "'" pid "." (name k))]
(submit ztx (assoc (flatten-doc ztx sd) :xt/id id :parent (str "'" pid) :zd/subdoc true))))
result))

(defmethod zen/op 'zd.events/datalog-delete
Expand All @@ -66,3 +71,79 @@
(defmethod zen/stop 'zd.engines/datalog
[ztx config {n :node}]
(.close n))


(defn parse-query [q]
(let [xs (->> (str/split q #"\n")
(remove (fn [s] (or (str/blank? s) (str/starts-with? s "\\")))))
columns (->> xs
(filterv #(re-matches #"^\s?>.*" %))
(mapv #(subs % 1))
(mapv str/trim)
(filterv #(not (str/blank? %)))
(mapv (fn [x]
(if (str/starts-with? x "(")
['expr (edamame.core/parse-string x {:regex true})]
(let [[e k] (str/split x #":" 2)]
[(symbol e) (cond
(= k "*") (symbol k)
:else (keyword k))])))))
index (atom {})
find-items (->> (group-by first columns)
(reduce (fn [acc [k xs]]
(if (= 'expr k)
(->> (mapv second xs)
(reduce (fn [acc e]
(swap! index assoc e (count acc))
(conj acc e))
acc))
(let [cs (->> (mapv second xs) (filter identity) (dedupe) (into []))]
(swap! index assoc k (count acc))
(if (seq (filter (fn [x] (contains? #{'* :?} x)) cs))
(conj acc (list 'pull k ['*]))
(if (empty? cs)
(conj acc k)
(conj acc (list 'pull k cs)))))))
[]))
where-items
(->> xs
(filterv (every-pred #(not (str/ends-with? % " :asc"))
#(not (str/ends-with? % " :desc"))
#(not (re-matches #"^\s?>.*" %))))
(mapv (fn [x] (let [res (edamame.core/parse-string (str/replace (str "[" x "]") #"#" ":symbol/")
{:regex true})]
(cond
(list? (get res 1))
(vector res)

:else
res)
))))
where (->> where-items
(mapv (fn [x]
(clojure.walk/postwalk
(fn [y]
(if (and (keyword? y) (= "symbol" (namespace y)))
(str "'" (name y))
y)) x))))

order-items
(->> xs
(filterv (every-pred #(or (str/ends-with? % " :asc")
(str/ends-with? % " :desc"))
#(not (re-matches #"^\s?>.*" %))))
(mapv (fn [x] (edamame.core/parse-string (str/replace (str "[" x "]") #"#" ":symbol/") {:regex true}))))

order
(->> order-items
(mapv (fn [x]
(clojure.walk/postwalk
(fn [y]
(if (and (keyword? y) (= "symbol" (namespace y)))
(str "'" (name y))
y)) x))))]
(into {:where where
:order order
:find find-items
:columns columns
:index @index} )))
11 changes: 10 additions & 1 deletion src/zd/system.clj
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
(ns zd.system
(:require [zen.core :as zen]
[zd.datalog]
[zd.api :as api]))

(defn restart [ztx]
Expand All @@ -17,10 +18,18 @@
(reset! dtx ztx)
(restart ztx)))

(defn query [q]
(zd.datalog/query @dtx q))

(comment

(-main)

(restart @dtx)

(zen/stop-system @dtx))
(zen/stop-system @dtx)

(query '{:where [[e :parent p]]
:find [(pull e [:xt/id :title])]})

)
59 changes: 54 additions & 5 deletions test/zd/datalog_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
(defonce ztx (zen/new-context {}))

(comment
(def ztx (zen/new-context {})))
(def ztx (zen/new-context {}))
)

(deftest datalog-engine
(zen/stop-system ztx)
Expand All @@ -25,14 +26,15 @@

(xtdb/sync (:node (datalog/get-state ztx)))

(datalog/query ztx '{:find [?id ?e]
:where [[?e :xt/id ?id]]})

(testing "metadata is loaded into xtdb"
(matcho/assert
#{["customers"]}
(datalog/query ztx '{:find [?id]
:where [[?e :meta/docname docname]
[?e :xt/id ?id]]
:in [docname]}
'customers)))
:where [[?e :meta/docname "'customers"]
[?e :xt/id ?id]]})))

(matcho/assert
#{["customers.flame"] ["customers._schema"]}
Expand Down Expand Up @@ -112,3 +114,50 @@

(zen/stop-system ztx))


(deftest datalog-sugar





(def q
"
e :parent #organizations
e :rel #rel.partner
p :organization e
p :role #roles.cto
> d
> e:xt/id
> e:rel
> (count e)
> (mean e)
")

(def q2
"
e :parent #customers
e :category cat
(clojure.string/starts-with? cat \"s\")
e :customer-since since
e :asc
> e:name
> (count e)
"
)

(def q3
"
e :type #customers
> e
")

(matcho/match
(datalog/parse-query q3)
'{:where [[e :type "'customers"]],
:order []
:find [e]})


)

0 comments on commit 8a23c3f

Please sign in to comment.