Propagate external scalar bindings consumed from the argument list when generating SQL.
This commit is contained in:
parent
fbd8c0bfbb
commit
ae0dac2817
2 changed files with 57 additions and 18 deletions
|
@ -190,7 +190,11 @@
|
||||||
;; reorder your query yourself.
|
;; reorder your query yourself.
|
||||||
(util/conj-in cc [:wheres]
|
(util/conj-in cc [:wheres]
|
||||||
(not-join->where-fragment
|
(not-join->where-fragment
|
||||||
(Not->NotJoinClause (:source cc) (:bindings cc) not))))
|
(Not->NotJoinClause (:source cc)
|
||||||
|
(merge-with concat
|
||||||
|
(:external-bindings cc)
|
||||||
|
(:bindings cc))
|
||||||
|
not))))
|
||||||
|
|
||||||
;; We're keeping this simple for now: a straightforward type switch.
|
;; We're keeping this simple for now: a straightforward type switch.
|
||||||
(defn apply-clause [cc it]
|
(defn apply-clause [cc it]
|
||||||
|
|
|
@ -10,12 +10,30 @@
|
||||||
[datomish.projection :as projection]
|
[datomish.projection :as projection]
|
||||||
[datomish.transforms :as transforms]
|
[datomish.transforms :as transforms]
|
||||||
[datascript.parser :as dp
|
[datascript.parser :as dp
|
||||||
#?@(:cljs [:refer [Pattern DefaultSrc Variable Constant Placeholder]])]
|
#?@(:cljs
|
||||||
|
[:refer [
|
||||||
|
BindScalar
|
||||||
|
Constant
|
||||||
|
DefaultSrc
|
||||||
|
Pattern
|
||||||
|
Placeholder
|
||||||
|
SrcVar
|
||||||
|
Variable
|
||||||
|
]])]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[honeysql.core :as sql]
|
[honeysql.core :as sql]
|
||||||
)
|
)
|
||||||
#?(:clj (:import [datascript.parser Pattern DefaultSrc Variable Constant Placeholder]))
|
#?(:clj
|
||||||
)
|
(:import
|
||||||
|
[datascript.parser
|
||||||
|
BindScalar
|
||||||
|
Constant
|
||||||
|
DefaultSrc
|
||||||
|
Pattern
|
||||||
|
Placeholder
|
||||||
|
SrcVar
|
||||||
|
Variable
|
||||||
|
])))
|
||||||
|
|
||||||
;; Setting this to something else will make your output more readable,
|
;; Setting this to something else will make your output more readable,
|
||||||
;; but not automatically safe for use.
|
;; but not automatically safe for use.
|
||||||
|
@ -42,20 +60,35 @@
|
||||||
(raise-str "`with` not supported.")))
|
(raise-str "`with` not supported.")))
|
||||||
|
|
||||||
(defn- validate-in [in]
|
(defn- validate-in [in]
|
||||||
(when-not (and (== 1 (count in))
|
(when-not (= "$" (name (-> in first :variable :symbol)))
|
||||||
(= "$" (name (-> in first :variable :symbol))))
|
(raise-str "Non-default sources not supported."))
|
||||||
(raise-str "Complex `in` not supported: " in)))
|
(when-not (every? (partial instance? BindScalar) (rest in))
|
||||||
|
(raise-str "Non-scalar bindings not supported.")))
|
||||||
|
|
||||||
|
(defn in->bindings
|
||||||
|
"Take an `:in` list and return a bindings map suitable for use
|
||||||
|
as external bindings in a CC."
|
||||||
|
[in]
|
||||||
|
(reduce
|
||||||
|
(fn [m b]
|
||||||
|
(or
|
||||||
|
(when (instance? BindScalar b)
|
||||||
|
(let [var (:variable b)]
|
||||||
|
(when (instance? Variable var)
|
||||||
|
(let [v (:symbol var)]
|
||||||
|
(assoc m v [(sql/param (util/var->sql-var v))])))))
|
||||||
|
m))
|
||||||
|
{}
|
||||||
|
in))
|
||||||
|
|
||||||
(defn expand-find-into-context [context find]
|
(defn expand-find-into-context [context find]
|
||||||
;; There's some confusing use of 'where' and friends here. That's because
|
|
||||||
;; the parsed Datalog includes :where, and it's also input to honeysql's
|
|
||||||
;; SQL formatter.
|
|
||||||
(let [{:keys [find in with where]} find] ; Destructure the Datalog query.
|
(let [{:keys [find in with where]} find] ; Destructure the Datalog query.
|
||||||
(validate-with with)
|
(validate-with with)
|
||||||
(validate-in in)
|
(validate-in in)
|
||||||
(assoc context
|
(let [external-bindings (in->bindings in)]
|
||||||
:elements (:elements find)
|
(assoc context
|
||||||
:cc (clauses/patterns->cc (:default-source context) where nil))))
|
:elements (:elements find)
|
||||||
|
:cc (clauses/patterns->cc (:default-source context) where external-bindings)))))
|
||||||
|
|
||||||
(defn find->sql-clause
|
(defn find->sql-clause
|
||||||
"Take a parsed `find` expression and turn it into a structured SQL
|
"Take a parsed `find` expression and turn it into a structured SQL
|
||||||
|
@ -70,10 +103,10 @@
|
||||||
|
|
||||||
(defn find->sql-string
|
(defn find->sql-string
|
||||||
"Take a parsed `find` expression and turn it into SQL."
|
"Take a parsed `find` expression and turn it into SQL."
|
||||||
[context find]
|
[context find args]
|
||||||
(->
|
(->
|
||||||
(find->sql-clause context find)
|
(find->sql-clause context find)
|
||||||
(sql/format :quoting sql-quoting-style)))
|
(sql/format args :quoting sql-quoting-style)))
|
||||||
|
|
||||||
(defn parse
|
(defn parse
|
||||||
"Parse a Datalog query array into a structured `find` expression."
|
"Parse a Datalog query array into a structured `find` expression."
|
||||||
|
@ -82,10 +115,12 @@
|
||||||
|
|
||||||
(comment
|
(comment
|
||||||
(def sql-quoting-style nil)
|
(def sql-quoting-style nil)
|
||||||
(datomish.query/find->sql-string (datomish.context/->Context (datomish.source/datoms-source nil) nil nil)
|
(datomish.query/find->sql-string
|
||||||
|
(datomish.context/->Context (datomish.source/datoms-source nil) nil nil)
|
||||||
(datomish.query/parse
|
(datomish.query/parse
|
||||||
'[:find ?timestampMicros ?page :in $ :where
|
'[:find ?timestampMicros ?page :in $ ?latest :where
|
||||||
[?page :page/starred true ?t]
|
[?page :page/starred true ?t]
|
||||||
[?t :db/txInstant ?timestampMicros]
|
[?t :db/txInstant ?timestampMicros]
|
||||||
(not [(> ?t 1000000)]) ]))
|
(not [(> ?t ?latest)]) ])
|
||||||
|
{:latest 5})
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue