Implement :?foo [:param :foo] and primitive [:raw "sql"]

This commit is contained in:
Sean Corfield 2020-10-01 23:30:18 -07:00
parent ddef4068ba
commit 9f8d1a8564
3 changed files with 47 additions and 26 deletions

View file

@ -317,8 +317,8 @@ Keywords that begin with `?` are interpreted as bindable parameters:
(-> (select :id) (-> (select :id)
(from :foo) (from :foo)
(where [:= :a :?baz]) (where [:= :a :?baz])
(sql/format :params {:baz "BAZ"})) (sql/format {:params {:baz "BAZ"}}))
=> ["SELECT id FROM foo WHERE a = ?" "BAZ"] => ["SELECT id FROM foo WHERE (a = ?)" "BAZ"]
``` ```
### Miscellaneous ### Miscellaneous

View file

@ -86,27 +86,39 @@
(defn- format-entity [x & [{:keys [aliased? drop-ns?]}]] (defn- format-entity [x & [{:keys [aliased? drop-ns?]}]]
(let [q (if *quoted* (:quote *dialect*) identity) (let [q (if *quoted* (:quote *dialect*) identity)
call (fn [f x] (str f "(" x ")")) [t c] (if-let [n (when-not (or drop-ns? (string? x))
[f t c] (if-let [n (when-not (or drop-ns? (string? x))
(namespace x))] (namespace x))]
[nil n (name x)] [n (name x)]
(let [[t c] (if aliased? (if aliased?
[(name x)] [nil (name x)]
(str/split (name x) #"\."))] (let [[t c] (str/split (name x) #"\.")]
;; I really dislike like %func.arg shorthand syntax! (if c [t c] [nil t]))))]
(cond (= \% (first t))
[(subs t 1) nil c]
c
[nil t c]
:else
[nil nil t])))]
(cond->> c (cond->> c
(not= "*" c) (not= "*" c)
(q) (q)
t t
(str (q t) ".") (str (q t) "."))))
f
(call f)))) (defn- ->param [k]
(with-meta (constantly k)
{::wrapper
(fn [fk {:keys [params]}]
(let [k (fk)]
(if (contains? params k)
(get params k)
(throw (ex-info (str "missing parameter value for " k)
{:params (keys params)})))))}))
(defn- format-var [x & [opts]]
(let [c (name x)]
(cond (= \% (first c))
(let [[f & args] (str/split (subs c 1) #"\.")]
;; TODO: this does not quote arguments -- does that matter?
[(str f "(" (str/join "," args) ")")])
(= \? (first c))
["?" (->param (keyword (subs c 1)))]
:else
[(format-entity x opts)])))
(defn- format-entity-alias [x] (defn- format-entity-alias [x]
(cond (sequential? x) (cond (sequential? x)
@ -151,7 +163,9 @@
(into params'))) (into params')))
(or (keyword? x) (symbol? x)) (or (keyword? x) (symbol? x))
(if aliased?
[(format-entity x opts)] [(format-entity x opts)]
(format-var x opts))
(and aliased? (string? x)) (and aliased? (string? x))
[(format-entity x opts)] [(format-entity x opts)]
@ -419,7 +433,7 @@
;:order-by 190 ;:order-by 190
;:limit 200 ;:limit 200
;:offset 210 ;:offset 210
:lock 215 ;:lock 215
;:values 220 ;:values 220
:query-values 230}) :query-values 230})
;; :on-conflict -- https://www.postgresqltutorial.com/postgresql-upsert/ ;; :on-conflict -- https://www.postgresqltutorial.com/postgresql-upsert/
@ -517,11 +531,18 @@
:not :not
(fn [_ [x]] (fn [_ [x]]
(let [[sql & params] (format-expr x)] (let [[sql & params] (format-expr x)]
(into [(str "NOT " sql)] params)))})) (into [(str "NOT " sql)] params)))
:param
(fn [_ [k]]
["?" (->param k)])
:raw
;; TODO: only supports single raw string right now
(fn [_ [s]]
[s])}))
(defn format-expr [x & [{:keys [nested?] :as opts}]] (defn format-expr [x & [{:keys [nested?] :as opts}]]
(cond (or (keyword? x) (symbol? x)) (cond (or (keyword? x) (symbol? x))
[(format-entity x opts)] (format-var x opts)
(map? x) (map? x)
(format-dsl x (assoc opts :nested? true)) (format-dsl x (assoc opts :nested? true))

View file

@ -317,8 +317,8 @@ WHERE kind <> ?
(-> (select :id) (-> (select :id)
(from :foo) (from :foo)
(where [:= :a :?baz]) (where [:= :a :?baz])
(sql/format :params {:baz "BAZ"})) (sql/format {:params {:baz "BAZ"}}))
=> ["SELECT id FROM foo WHERE a = ?" "BAZ"] => ["SELECT id FROM foo WHERE (a = ?)" "BAZ"]
) )