Drop ? from all keyword options

This commit is contained in:
Sean Corfield 2021-02-01 13:10:57 -08:00
parent 2ef9d4dad2
commit 379d3d05c4
3 changed files with 58 additions and 59 deletions

View file

@ -17,8 +17,7 @@ This is the README for the upcoming 2.x version of HoneySQL which provides a str
All sample code in this README is automatically run as a unit test using All sample code in this README is automatically run as a unit test using
[seancorfield/readme](https://github.com/seancorfield/readme). [seancorfield/readme](https://github.com/seancorfield/readme).
Note that while some of these samples show pretty-printed SQL, this is just for Some of these samples show pretty-printed SQL: HoneySQL 2.x supports `:pretty true` which inserts newlines between clauses in the generated SQL strings.
README readability; honeysql does not generate pretty-printed SQL.
## Usage ## Usage
@ -154,7 +153,7 @@ then provide a collection of rows, each a collection of column values:
[["Jon" "Smith" 34] [["Jon" "Smith" 34]
["Andrew" "Cooper" 12] ["Andrew" "Cooper" 12]
["Jane" "Daniels" 56]]) ["Jane" "Daniels" 56]])
(sql/format {:pretty? true})) (sql/format {:pretty true}))
=> [" => ["
INSERT INTO properties INSERT INTO properties
(name, surname, age) (name, surname, age)
@ -172,7 +171,7 @@ and the remaining maps *must* have the same set of keys and values:
(values [{:name "John" :surname "Smith" :age 34} (values [{:name "John" :surname "Smith" :age 34}
{:name "Andrew" :surname "Cooper" :age 12} {:name "Andrew" :surname "Cooper" :age 12}
{:name "Jane" :surname "Daniels" :age 56}]) {:name "Jane" :surname "Daniels" :age 56}])
(sql/format {:pretty? true})) (sql/format {:pretty true}))
=> [" => ["
INSERT INTO properties INSERT INTO properties
(name, surname, age) VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?) (name, surname, age) VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?)
@ -194,7 +193,7 @@ The column values do not have to be literals, they can be nested queries:
:role_id (-> (select :id) :role_id (-> (select :id)
(from :role) (from :role)
(where [:= :name role-name]))}]) (where [:= :name role-name]))}])
(sql/format {:pretty? true}))) (sql/format {:pretty true})))
=> [" => ["
INSERT INTO user_profile_to_role INSERT INTO user_profile_to_role
@ -222,7 +221,7 @@ Composite types are supported:
(values (values
[["small" (composite 1 "inch")] [["small" (composite 1 "inch")]
["large" (composite 10 "feet")]]) ["large" (composite 10 "feet")]])
(sql/format {:pretty? true})) (sql/format {:pretty true}))
=> [" => ["
INSERT INTO comp_table INSERT INTO comp_table
(name, comp_column) (name, comp_column)
@ -240,7 +239,7 @@ Updates are possible too:
(set {:kind "dramatic" (set {:kind "dramatic"
:watched [:+ :watched 1]}) :watched [:+ :watched 1]})
(where [:= :kind "drama"]) (where [:= :kind "drama"])
(sql/format {:pretty? true})) (sql/format {:pretty true}))
=> [" => ["
UPDATE films UPDATE films
SET kind = ?, watched = watched + ? SET kind = ?, watched = watched + ?
@ -276,7 +275,7 @@ If your database supports it, you can also delete from multiple tables:
(from :films) (from :films)
(join :directors [:= :films.director_id :directors.id]) (join :directors [:= :films.director_id :directors.id])
(where [:<> :kind "musical"]) (where [:<> :kind "musical"])
(sql/format {:pretty? true})) (sql/format {:pretty true}))
=> [" => ["
DELETE films, directors DELETE films, directors
FROM films FROM films
@ -363,7 +362,7 @@ have a lot of function calls needed in code:
(values [{:location [:ST_SetSRID (values [{:location [:ST_SetSRID
[:ST_MakePoint 0.291 32.621] [:ST_MakePoint 0.291 32.621]
[:cast 4325 :integer]]}]) [:cast 4325 :integer]]}])
(sql/format {:pretty? true})) (sql/format {:pretty true}))
=> [" => ["
INSERT INTO sample INSERT INTO sample
(location) VALUES (ST_SETSRID(ST_MAKEPOINT(?, ?), CAST(? AS integer))) (location) VALUES (ST_SETSRID(ST_MAKEPOINT(?, ?), CAST(? AS integer)))
@ -523,7 +522,7 @@ big-complicated-map
```clojure ```clojure
(sql/format big-complicated-map (sql/format big-complicated-map
{:params {:param1 "gabba" :param2 2} {:params {:param1 "gabba" :param2 2}
:pretty? true}) :pretty true})
=> [" => ["
SELECT DISTINCT f.*, b.baz, c.quux, b.bla \"bla-bla\", NOW(), @x := 10 SELECT DISTINCT f.*, b.baz, c.quux, b.bla \"bla-bla\", NOW(), @x := 10
FROM foo AS f, baz AS b FROM foo AS f, baz AS b

View file

@ -115,13 +115,13 @@
(defn- namespace-_ [x] (some-> (namespace x) (str/replace "-" "_"))) (defn- namespace-_ [x] (some-> (namespace x) (str/replace "-" "_")))
(defn- name-_ [x] (str/replace (name x) "-" "_")) (defn- name-_ [x] (str/replace (name x) "-" "_"))
(defn- format-entity [x & [{:keys [aliased? drop-ns?]}]] (defn- format-entity [x & [{:keys [aliased drop-ns]}]]
(let [nn (if (or *quoted* (string? x)) name name-_) (let [nn (if (or *quoted* (string? x)) name name-_)
q (if (or *quoted* (string? x)) (:quote *dialect*) identity) q (if (or *quoted* (string? x)) (:quote *dialect*) identity)
[t c] (if-let [n (when-not (or drop-ns? (string? x)) [t c] (if-let [n (when-not (or drop-ns (string? x))
(namespace-_ x))] (namespace-_ x))]
[n (nn x)] [n (nn x)]
(if aliased? (if aliased
[nil (nn x)] [nil (nn x)]
(let [[t c] (str/split (nn x) #"\.")] (let [[t c] (str/split (nn x) #"\.")]
(if c [t c] [nil t]))))] (if c [t c] [nil t]))))]
@ -162,30 +162,30 @@
(cond-> (format-entity s) (cond-> (format-entity s)
pair? pair?
(str (if (and (contains? *dialect* :as) (not (:as *dialect*))) " " " AS ") (str (if (and (contains? *dialect* :as) (not (:as *dialect*))) " " " AS ")
(format-entity (second x) {:aliased? true})))) (format-entity (second x) {:aliased true}))))
:else :else
(format-entity x))) (format-entity x)))
(defn- format-selectable-dsl [x & [{:keys [as? aliased?] :as opts}]] (defn- format-selectable-dsl [x & [{:keys [as aliased] :as opts}]]
(cond (map? x) (cond (map? x)
(format-dsl x {:nested? true}) (format-dsl x {:nested true})
(sequential? x) (sequential? x)
(let [s (first x) (let [s (first x)
pair? (< 1 (count x)) pair? (< 1 (count x))
a (second x) a (second x)
[sql & params] (if (map? s) [sql & params] (if (map? s)
(format-dsl s {:nested? true}) (format-dsl s {:nested true})
(format-expr s)) (format-expr s))
[sql' & params'] (when pair? [sql' & params'] (when pair?
(if (sequential? a) (if (sequential? a)
(let [[sql params] (format-expr-list a {:aliased? true})] (let [[sql params] (format-expr-list a {:aliased true})]
(into [(str/join " " sql)] params)) (into [(str/join " " sql)] params))
(format-selectable-dsl a {:aliased? true})))] (format-selectable-dsl a {:aliased true})))]
(-> [(cond-> sql (-> [(cond-> sql
pair? pair?
(str (if as? (str (if as
(if (and (contains? *dialect* :as) (if (and (contains? *dialect* :as)
(not (:as *dialect*))) (not (:as *dialect*)))
" " " "
@ -195,11 +195,11 @@
(into params'))) (into params')))
(or (keyword? x) (symbol? x)) (or (keyword? x) (symbol? x))
(if aliased? (if aliased
[(format-entity x opts)] [(format-entity x opts)]
(format-var x opts)) (format-var x opts))
(and aliased? (string? x)) (and aliased (string? x))
[(format-entity x opts)] [(format-entity x opts)]
:else :else
@ -212,7 +212,7 @@
(reduce (fn [[sql params] [sql' & params']] (reduce (fn [[sql params] [sql' & params']]
[(conj sql sql') (if params' (into params params') params)]) [(conj sql sql') (if params' (into params params') params)])
[[] []] [[] []]
(map #(format-dsl % {:nested? true}) xs))] (map #(format-dsl % {:nested true}) xs))]
(into [(str/join (str " " (sql-kw k) " ") sqls)] params))) (into [(str/join (str " " (sql-kw k) " ") sqls)] params)))
(defn format-expr-list (defn format-expr-list
@ -235,7 +235,7 @@
(map #(format-expr % opts) exprs))) (map #(format-expr % opts) exprs)))
(defn- format-columns [k xs] (defn- format-columns [k xs]
(let [[sqls params] (format-expr-list xs {:drop-ns? (= :columns k)})] (let [[sqls params] (format-expr-list xs {:drop-ns (= :columns k)})]
(into [(str "(" (str/join ", " sqls) ")")] params))) (into [(str "(" (str/join ", " sqls) ")")] params)))
(defn- format-selects [k xs] (defn- format-selects [k xs]
@ -244,9 +244,9 @@
(reduce (fn [[sql params] [sql' & params']] (reduce (fn [[sql params] [sql' & params']]
[(conj sql sql') (if params' (into params params') params)]) [(conj sql sql') (if params' (into params params') params)])
[[] []] [[] []]
(map #(format-selectable-dsl % {:as? (#{:select :from} k)}) xs))] (map #(format-selectable-dsl % {:as (#{:select :from} k)}) xs))]
(into [(str (sql-kw k) " " (str/join ", " sqls))] params)) (into [(str (sql-kw k) " " (str/join ", " sqls))] params))
(let [[sql & params] (format-selectable-dsl xs {:as? (#{:select :from} k)})] (let [[sql & params] (format-selectable-dsl xs {:as (#{:select :from} k)})]
(into [(str (sql-kw k) " " sql)] params)))) (into [(str (sql-kw k) " " sql)] params))))
(defn- format-with-part [x] (defn- format-with-part [x]
@ -386,7 +386,7 @@
xs))] xs))]
(into [(str "(" (into [(str "("
(str/join ", " (str/join ", "
(map #(format-entity % {:drop-ns? true}) cols)) (map #(format-entity % {:drop-ns true}) cols))
") " ") "
(sql-kw k) (sql-kw k)
" " " "
@ -419,7 +419,7 @@
(defn- format-do-update-set [k x] (defn- format-do-update-set [k x]
(if (or (keyword? x) (symbol? x)) (if (or (keyword? x) (symbol? x))
(let [e (format-entity x {:drop-ns? true})] (let [e (format-entity x {:drop-ns true})]
[(str (sql-kw k) " " e " = EXCLUDED." e)]) [(str (sql-kw k) " " e " = EXCLUDED." e)])
(format-set-exprs k x))) (format-set-exprs k x)))
@ -489,7 +489,7 @@
This is intended to be used when writing your own formatters to This is intended to be used when writing your own formatters to
extend the DSL supported by HoneySQL." extend the DSL supported by HoneySQL."
[statement-map & [{:keys [aliased? nested? pretty?]}]] [statement-map & [{:keys [aliased nested pretty]}]]
(let [[sqls params leftover] (let [[sqls params leftover]
(reduce (fn [[sql params leftover] k] (reduce (fn [[sql params leftover] k]
(if-let [xs (or (k statement-map) (if-let [xs (or (k statement-map)
@ -507,10 +507,10 @@
(throw (ex-info (str "Unknown SQL clauses: " (throw (ex-info (str "Unknown SQL clauses: "
(str/join ", " (keys leftover))) (str/join ", " (keys leftover)))
leftover)) leftover))
(into [(cond-> (str/join (if pretty? "\n" " ") (filter seq sqls)) (into [(cond-> (str/join (if pretty "\n" " ") (filter seq sqls))
pretty? pretty
(as-> s (str "\n" s "\n")) (as-> s (str "\n" s "\n"))
(and nested? (not aliased?)) (and nested (not aliased))
(as-> s (str "(" s ")")))] params)))) (as-> s (str "(" s ")")))] params))))
(def ^:private infix-aliases (def ^:private infix-aliases
@ -552,8 +552,8 @@
x)) x))
(defn- format-in [in [x y]] (defn- format-in [in [x y]]
(let [[sql-x & params-x] (format-expr x {:nested? true}) (let [[sql-x & params-x] (format-expr x {:nested true})
[sql-y & params-y] (format-expr y {:nested? true}) [sql-y & params-y] (format-expr y {:nested true})
values (unwrap (first params-y) {})] values (unwrap (first params-y) {})]
(if (and (= "?" sql-y) (= 1 (count params-y)) (coll? values)) (if (and (= "?" sql-y) (= 1 (count params-y)) (coll? values))
(let [sql (str "(" (str/join ", " (repeat (count values) "?")) ")")] (let [sql (str "(" (str/join ", " (repeat (count values) "?")) ")")]
@ -572,9 +572,9 @@
(into [(str "ARRAY[" (str/join ", " sqls) "]")] params))) (into [(str "ARRAY[" (str/join ", " sqls) "]")] params)))
:between :between
(fn [_ [x a b]] (fn [_ [x a b]]
(let [[sql-x & params-x] (format-expr x {:nested? true}) (let [[sql-x & params-x] (format-expr x {:nested true})
[sql-a & params-a] (format-expr a {:nested? true}) [sql-a & params-a] (format-expr a {:nested true})
[sql-b & params-b] (format-expr b {:nested? true})] [sql-b & params-b] (format-expr b {:nested true})]
(-> [(str sql-x " BETWEEN " sql-a " AND " sql-b)] (-> [(str sql-x " BETWEEN " sql-a " AND " sql-b)]
(into params-x) (into params-x)
(into params-a) (into params-a)
@ -625,7 +625,7 @@
{::wrapper (fn [fx _] (fx))})]) {::wrapper (fn [fx _] (fx))})])
:nest :nest
(fn [_ [x]] (fn [_ [x]]
(format-expr x {:nested? true})) (format-expr x {:nested true}))
:not :not
(fn [_ [x]] (fn [_ [x]]
(let [[sql & params] (format-expr x)] (let [[sql & params] (format-expr x)]
@ -655,12 +655,12 @@
This is intended to be used when writing your own formatters to This is intended to be used when writing your own formatters to
extend the DSL supported by HoneySQL." extend the DSL supported by HoneySQL."
[expr & [{:keys [nested?] :as opts}]] [expr & [{:keys [nested] :as opts}]]
(cond (or (keyword? expr) (symbol? expr)) (cond (or (keyword? expr) (symbol? expr))
(format-var expr opts) (format-var expr opts)
(map? expr) (map? expr)
(format-dsl expr (assoc opts :nested? true)) (format-dsl expr (assoc opts :nested true))
(sequential? expr) (sequential? expr)
(let [op (first expr) (let [op (first expr)
@ -678,10 +678,10 @@
[(conj sql sql') [(conj sql sql')
(if params' (into params params') params)]) (if params' (into params params') params)])
[[] []] [[] []]
(map #(format-expr % {:nested? true}) (map #(format-expr % {:nested true})
(rest x)))] (rest x)))]
(into [(cond-> (str/join (str " " (sql-kw op) " ") sqls) (into [(cond-> (str/join (str " " (sql-kw op) " ") sqls)
nested? nested
(as-> s (str "(" s ")")))] (as-> s (str "(" s ")")))]
params)) params))
(let [[_ a b & y] expr (let [[_ a b & y] expr
@ -690,26 +690,26 @@
op op
" is supported") " is supported")
{:expr expr}))) {:expr expr})))
[s1 & p1] (format-expr a {:nested? true}) [s1 & p1] (format-expr a {:nested true})
[s2 & p2] (format-expr b {:nested? true}) [s2 & p2] (format-expr b {:nested true})
op (get infix-aliases op op)] op (get infix-aliases op op)]
(if (and (#{:= :<>} op) (or (nil? a) (nil? b))) (if (and (#{:= :<>} op) (or (nil? a) (nil? b)))
(-> (str (if (nil? a) (-> (str (if (nil? a)
(if (nil? b) "NULL" s2) (if (nil? b) "NULL" s2)
s1) s1)
(if (= := op) " IS NULL" " IS NOT NULL")) (if (= := op) " IS NULL" " IS NOT NULL"))
(cond-> nested? (cond-> nested
(as-> s (str "(" s ")"))) (as-> s (str "(" s ")")))
(vector)) (vector))
(-> (str s1 " " (sql-kw op) " " s2) (-> (str s1 " " (sql-kw op) " " s2)
(cond-> nested? (cond-> nested
(as-> s (str "(" s ")"))) (as-> s (str "(" s ")")))
(vector) (vector)
(into p1) (into p1)
(into p2))))) (into p2)))))
(contains? #{:in :not-in} op) (contains? #{:in :not-in} op)
(let [[sql & params] (format-in op (rest expr))] (let [[sql & params] (format-in op (rest expr))]
(into [(if nested? (str "(" sql ")") sql)] params)) (into [(if nested (str "(" sql ")") sql)] params))
(contains? @special-syntax op) (contains? @special-syntax op)
(let [formatter (get @special-syntax op)] (let [formatter (get @special-syntax op)]
(formatter op (rest expr))) (formatter op (rest expr)))
@ -849,7 +849,7 @@
(format {:select [:*] :from [:table] (format {:select [:*] :from [:table]
:order-by [[[:date :expiry] :desc] :bar]} {}) :order-by [[[:date :expiry] :desc] :bar]} {})
(println (format {:select [:*] :from [:table] (println (format {:select [:*] :from [:table]
:order-by [[[:date :expiry] :desc] :bar]} {:pretty? true})) :order-by [[[:date :expiry] :desc] :bar]} {:pretty true}))
(format {:select [:*] :from [:table] (format {:select [:*] :from [:table]
:where [:< [:date_add :expiry [:interval 30 :days]] [:now]]} {}) :where [:< [:date_add :expiry [:interval 30 :days]] [:now]]} {})
(format-expr [:interval 30 :days]) (format-expr [:interval 30 :days])
@ -859,10 +859,10 @@
:where [:= :id (with-meta (constantly 42) {:foo true})]} :where [:= :id (with-meta (constantly 42) {:foo true})]}
{:dialect :mysql})) {:dialect :mysql}))
(println (format {:select [:*] :from [:table] (println (format {:select [:*] :from [:table]
:where [:in :id [1 2 3 4]]} {:pretty? true})) :where [:in :id [1 2 3 4]]} {:pretty true}))
(println (format {:select [:*] :from [:table] (println (format {:select [:*] :from [:table]
:where [:and [:in :id [1 [:param :foo]]] :where [:and [:in :id [1 [:param :foo]]]
[:= :bar [:param :quux]]]} [:= :bar [:param :quux]]]}
{:params {:foo 42 :quux 13} {:params {:foo 42 :quux 13}
:pretty? true})) :pretty true}))
,) ,)

View file

@ -477,14 +477,14 @@ VALUES ('UA502', 'Bananas', 105, '1971-07-13', 'Comedy', '82 minutes')
:values [[[:inline "UA502"] [:inline "Bananas"] [:inline 105] :values [[[:inline "UA502"] [:inline "Bananas"] [:inline 105]
[:inline "1971-07-13"] [:inline "Comedy"] [:inline "1971-07-13"] [:inline "Comedy"]
[:inline "82 minutes"]]]} [:inline "82 minutes"]]]}
{:pretty? true}))) {:pretty true})))
(is (= [" (is (= ["
INSERT INTO films INSERT INTO films
VALUES (?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?)
" "UA502", "Bananas", 105, "1971-07-13", "Comedy", "82 minutes"] " "UA502", "Bananas", 105, "1971-07-13", "Comedy", "82 minutes"]
(format {:insert-into :films (format {:insert-into :films
:values [["UA502" "Bananas" 105 "1971-07-13" "Comedy" "82 minutes"]]} :values [["UA502" "Bananas" 105 "1971-07-13" "Comedy" "82 minutes"]]}
{:pretty? true}))) {:pretty true})))
(is (= [" (is (= ["
INSERT INTO films INSERT INTO films
(code, title, did, date_prod, kind) (code, title, did, date_prod, kind)
@ -493,14 +493,14 @@ VALUES (?, ?, ?, ?, ?)
(format {:insert-into :films (format {:insert-into :films
:columns [:code :title :did :date_prod :kind] :columns [:code :title :did :date_prod :kind]
:values [["T_601", "Yojimo", 106, "1961-06-16", "Drama"]]} :values [["T_601", "Yojimo", 106, "1961-06-16", "Drama"]]}
{:pretty? true}))) {:pretty true})))
(is (= [" (is (= ["
INSERT INTO films INSERT INTO films
VALUES (?, ?, ?, DEFAULT, ?, ?) VALUES (?, ?, ?, DEFAULT, ?, ?)
" "UA502", "Bananas", 105, "Comedy", "82 minutes"] " "UA502", "Bananas", 105, "Comedy", "82 minutes"]
(format {:insert-into :films (format {:insert-into :films
:values [["UA502" "Bananas" 105 [:default] "Comedy" "82 minutes"]]} :values [["UA502" "Bananas" 105 [:default] "Comedy" "82 minutes"]]}
{:pretty? true}))) {:pretty true})))
(is (= [" (is (= ["
INSERT INTO films INSERT INTO films
(code, title, did, date_prod, kind) (code, title, did, date_prod, kind)
@ -509,7 +509,7 @@ VALUES (?, ?, ?, DEFAULT, ?)
(format {:insert-into :films (format {:insert-into :films
:columns [:code :title :did :date_prod :kind] :columns [:code :title :did :date_prod :kind]
:values [["T_601", "Yojimo", 106, [:default], "Drama"]]} :values [["T_601", "Yojimo", 106, [:default], "Drama"]]}
{:pretty? true})))) {:pretty true}))))
(deftest on-conflict-tests (deftest on-conflict-tests
;; these examples are taken from https://www.postgresqltutorial.com/postgresql-upsert/ ;; these examples are taken from https://www.postgresqltutorial.com/postgresql-upsert/
@ -525,7 +525,7 @@ DO NOTHING
:values [[[:inline "Microsoft"], [:inline "hotline@microsoft.com"]]] :values [[[:inline "Microsoft"], [:inline "hotline@microsoft.com"]]]
:on-conflict {:on-constraint :customers_name_key} :on-conflict {:on-constraint :customers_name_key}
:do-nothing true} :do-nothing true}
{:pretty? true}))) {:pretty true})))
(is (= [" (is (= ["
INSERT INTO customers INSERT INTO customers
(name, email) (name, email)
@ -538,7 +538,7 @@ DO NOTHING
:values [[[:inline "Microsoft"], [:inline "hotline@microsoft.com"]]] :values [[[:inline "Microsoft"], [:inline "hotline@microsoft.com"]]]
:on-conflict :name :on-conflict :name
:do-nothing true} :do-nothing true}
{:pretty? true}))) {:pretty true})))
(is (= [" (is (= ["
INSERT INTO customers INSERT INTO customers
(name, email) (name, email)
@ -551,7 +551,7 @@ DO UPDATE SET email = EXCLUDED.email || ';' || customers.email
:values [[[:inline "Microsoft"], [:inline "hotline@microsoft.com"]]] :values [[[:inline "Microsoft"], [:inline "hotline@microsoft.com"]]]
:on-conflict :name :on-conflict :name
:do-update-set {:email [:|| :EXCLUDED.email [:inline ";"] :customers.email]}} :do-update-set {:email [:|| :EXCLUDED.email [:inline ";"] :customers.email]}}
{:pretty? true})))) {:pretty true}))))
(deftest issue-285 (deftest issue-285
(is (= [" (is (= ["
@ -564,4 +564,4 @@ ORDER BY id = ? DESC
(h/from :processes) (h/from :processes)
(h/where [:= :state 42]) (h/where [:= :state 42])
(h/order-by [[:= :id 123] :desc])) (h/order-by [[:= :id 123] :desc]))
{:pretty? true})))) {:pretty true}))))