Down to just 8 failures now!

Mising: array, inline, parameterizer.
This commit is contained in:
Sean Corfield 2020-09-23 18:15:20 -07:00
parent 1a699f18ab
commit f7d5e3a4cf
2 changed files with 203 additions and 95 deletions

View file

@ -9,12 +9,13 @@
(declare format-dsl) (declare format-dsl)
(declare format-expr) (declare format-expr)
(declare format-expr-list)
;; dynamic dialect handling for formatting ;; dynamic dialect handling for formatting
(def ^:private default-clause-order (def ^:private default-clause-order
"The (default) order for known clauses. Can have items added and removed." "The (default) order for known clauses. Can have items added and removed."
[:intersect :union :union-all :except [:with :with-recursive :intersect :union :union-all :except
:select :insert-into :update :delete :delete-from :truncate :select :insert-into :update :delete :delete-from :truncate
:columns :set :from :columns :set :from
:join :left-join :right-join :inner-join :outer-join :full-join :join :left-join :right-join :inner-join :outer-join :full-join
@ -50,7 +51,9 @@
(def ^:private default-dialect (atom (:ansi dialects))) (def ^:private default-dialect (atom (:ansi dialects)))
(def ^:private ^:dynamic *dialect* nil) (def ^:private ^:dynamic *dialect* nil)
(def ^:private ^:dynamic *clause-order* nil) ;; nil would be a better default but that makes testing individual
;; functions harder than necessary:
(def ^:private ^:dynamic *clause-order* default-clause-order)
(def ^:private ^:dynamic *quoted* nil) (def ^:private ^:dynamic *quoted* nil)
;; clause helpers ;; clause helpers
@ -72,41 +75,66 @@
(defn- sql-kw [k] (defn- sql-kw [k]
(-> k (name) (upper-case) (str/replace "-" " "))) (-> k (name) (upper-case) (str/replace "-" " ")))
(defn- format-entity [x] (defn- format-entity [x & [{:keys [aliased? drop-ns?]}]]
(let [q (if *quoted* (:quote *dialect*) identity) (let [q (if *quoted* (:quote *dialect*) identity)
[t c] (if-let [n (namespace x)] call (fn [f x] (str f "(" x ")"))
[n (name x)] [f t c] (if-let [n (when-not (or drop-ns? (string? x))
(let [[t c] (str/split (name x) #"\.")] (namespace x))]
(if c [t c] [nil t])))] [nil n (name x)]
(let [[t c] (if aliased?
[(name x)]
(str/split (name x) #"\."))]
;; I really dislike like %func.arg shorthand syntax!
(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- format-selectable [x] (defn- format-entity-alias [x]
(cond (sequential? x) (cond (sequential? x)
(str (let [s (first x)] (str (let [s (first x)]
(if (map? s) (if (map? s)
(format-dsl s true) (throw (ex-info "selectable cannot be statement!"
{:selectable s}))
(format-entity s))) (format-entity s)))
#_" AS " " " #_" AS " " "
(format-entity (second x))) (format-entity (second x) {:aliased? true}))
:else :else
(format-entity x))) (format-entity x)))
(defn- format-selectable-dsl [x] (defn- format-selectable-dsl [x & [{:keys [as? aliased?] :as opts}]]
(cond (map? x) (cond (map? x)
(format-dsl x true) (format-dsl x {:nested? true})
(sequential? x) (sequential? x)
(let [s (first x) (let [s (first x)
[sql & params] (if (map? s) (format-dsl s true) [(format-entity s)])] a (second x)
(into [(str sql #_" AS " " " (format-entity (second x)))] params)) [sql & params] (if (map? s)
(format-dsl s {:nested? true})
(format-expr s))
[sql' & params'] (if (sequential? a)
(let [[sql params] (format-expr-list a {:aliased? true})]
(into [(str/join " " sql)] params))
(format-selectable-dsl a {:aliased? true}))]
(-> [(str sql (if as? " AS " " ") sql')]
(into params)
(into params')))
(keyword? x) (or (keyword? x) (symbol? x))
[(format-entity x)] [(format-entity x opts)]
(and aliased? (string? x))
[(format-entity x opts)]
:else :else
(format-expr x))) (format-expr x)))
@ -121,17 +149,55 @@
(map #'format-dsl xs))] (map #'format-dsl xs))]
(into [(str/join (str " " (sql-kw k) " ") sqls)] params))) (into [(str/join (str " " (sql-kw k) " ") sqls)] params)))
(defn- format-selector [k xs] (defn- format-expr-list [xs & [opts]]
(reduce (fn [[sql params] [sql' & params']]
[(conj sql sql') (if params' (into params params') params)])
[[] []]
(map #(format-expr % opts) xs)))
(defn- format-columns [_ xs]
(let [[sqls params] (format-expr-list xs {:drop-ns? true})]
(into [(str "(" (str/join ", " sqls) ")")] params)))
(defn- format-selects [k xs]
(if (sequential? xs) (if (sequential? xs)
(let [[sqls params] (let [[sqls params]
(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 xs))] (map #(format-selectable-dsl % {:as? (= k :select)}) 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)] (let [[sql & params] (format-selectable-dsl xs {:as? (= k :select)})]
(into [(str (sql-kw k) " " sql)] params)))) (into [(str (sql-kw k) " " sql)] params))))
(defn- format-with-part [x]
(if (sequential? x)
(let [[sql & params] (format-dsl (second x))]
(into [(str (format-entity (first x)) " " sql)] params))
[(format-entity x)]))
(defn- format-with [k xs]
;; TODO: a sequence of pairs -- X AS expr -- where X is either [entity expr]
;; or just entity, as far as I can tell...
(let [[sqls params]
(reduce (fn [[sql params] [sql' & params']]
[(conj sql sql') (if params' (into params params') params)])
[[] []]
(map (fn [[x expr]]
(let [[sql & params] (format-with-part x)
[sql' & params'] (format-dsl expr)]
(cond-> [(str sql " AS "
(if (seq params')
(str "(" sql' ")")
sql'))]
params (into params)
params' (into params'))))
xs))]
(into [(str (sql-kw k) " " (str/join ", " sqls))] params)))
(defn- format-selector [k xs]
(format-selects k [xs]))
(defn- format-insert [k table] (defn- format-insert [k table]
;; table can be just a table, a pair of table and statement, or a ;; table can be just a table, a pair of table and statement, or a
;; pair of a pair of table and columns and a statement (yikes!) ;; pair of a pair of table and columns and a statement (yikes!)
@ -139,24 +205,24 @@
(if (sequential? (first table)) (if (sequential? (first table))
(let [[[table cols] statement] table (let [[[table cols] statement] table
[sql & params] (format-dsl statement)] [sql & params] (format-dsl statement)]
(into [(str (sql-kw k) " " (format-selectable table) (into [(str (sql-kw k) " " (format-entity-alias table)
" (" " ("
(str/join ", " (map #'format-selectable cols)) (str/join ", " (map #'format-entity-alias cols))
") " ") "
sql)] sql)]
params)) params))
(let [[table statement] table (let [[table statement] table
[sql & params] (format-dsl statement)] [sql & params] (format-dsl statement)]
(into [(str (sql-kw k) " " (format-selectable table) (into [(str (sql-kw k) " " (format-entity-alias table)
" " sql)] " " sql)]
params))) params)))
[(str (sql-kw k) " " (format-selectable table))])) [(str (sql-kw k) " " (format-entity-alias table))]))
(defn- format-join [k [j e]] (defn- format-join [k [j e]]
(let [[sql & params] (format-expr e)] (let [[sql & params] (format-expr e)]
;; for backward compatibility, treat plain JOIN as INNER JOIN: ;; for backward compatibility, treat plain JOIN as INNER JOIN:
(into [(str (sql-kw (if (= :join k) :inner-join k)) " " (into [(str (sql-kw (if (= :join k) :inner-join k)) " "
(format-selectable j) " ON " (format-entity-alias j) " ON "
sql)] sql)]
params))) params)))
@ -164,12 +230,6 @@
(let [[sql & params] (format-expr e)] (let [[sql & params] (format-expr e)]
(into [(str (sql-kw k) " " sql)] params))) (into [(str (sql-kw k) " " sql)] params)))
(defn- format-expr-list [xs]
(reduce (fn [[sql params] [sql' & params']]
[(conj sql sql') (if params' (into params params') params)])
[[] []]
(map #'format-expr xs)))
(defn- format-group-by [k xs] (defn- format-group-by [k xs]
(let [[sqls params] (format-expr-list xs)] (let [[sqls params] (format-expr-list xs)]
(into [(str (sql-kw k) " " (str/join ", " sqls))] params))) (into [(str (sql-kw k) " " (str/join ", " sqls))] params)))
@ -184,7 +244,7 @@
dirs)))] params))) dirs)))] params)))
(defn- format-values [k xs] (defn- format-values [k xs]
(if (sequential? (first xs)) (cond (sequential? (first xs))
;; [[1 2 3] [4 5 6]] ;; [[1 2 3] [4 5 6]]
(let [[sqls params] (let [[sqls params]
(reduce (fn [[sql params] [sqls' params']] (reduce (fn [[sql params] [sqls' params']]
@ -193,13 +253,38 @@
[[] []] [[] []]
(map #'format-expr-list xs))] (map #'format-expr-list xs))]
(into [(str (sql-kw k) " " (str/join ", " sqls))] params)) (into [(str (sql-kw k) " " (str/join ", " sqls))] params))
;; [1 2 3]
(let [[sqls params] (format-expr-list xs)] (map? (first xs))
(into [(str (sql-kw k) " (" (str/join ", " sqls) ")")] params)))) ;; [{:a 1 :b 2 :c 3}]
(let [cols (keys (first xs))
[sqls params]
(reduce (fn [[sql params] [sqls' params']]
[(conj sql (str/join ", " sqls'))
(if params' (into params params') params')])
[[] []]
(map (fn [m]
(format-expr-list (map #(get m %) cols)))
xs))]
(into [(str "("
(str/join ", "
(map #(format-entity % {:drop-ns? true}) cols))
") "
(sql-kw k) " (" (str/join ", " sqls) ")")]
params))
:else
(throw (ex-info ":values expects sequences or maps"
{:first (first xs)}))))
(defn- format-set-exprs [k xs] (defn- format-set-exprs [k xs]
;; TODO: !!! (let [[sqls params]
["SET a = ?, b = ?" 42 13]) (reduce-kv (fn [[sql params] v e]
(let [[sql' & params'] (format-expr e)]
[(conj sql (str (format-entity v) " = " sql'))
(if params' (into params params') params)]))
[[] []]
xs)]
(into [(str (sql-kw k) " " (str/join ", " sqls))] params)))
(def ^:private current-clause-order (def ^:private current-clause-order
"The (current) order for known clauses. Can have items added and removed." "The (current) order for known clauses. Can have items added and removed."
@ -208,26 +293,28 @@
(def ^:private clause-format (def ^:private clause-format
"The (default) behavior for each known clause. Can also have items added "The (default) behavior for each known clause. Can also have items added
and removed." and removed."
(atom {:intersect #'format-on-set-op (atom {:with #'format-with
:with-recursive #'format-with
:intersect #'format-on-set-op
:union #'format-on-set-op :union #'format-on-set-op
:union-all #'format-on-set-op :union-all #'format-on-set-op
:except #'format-on-set-op :except #'format-on-set-op
:select #'format-selector :select #'format-selects
:insert-into #'format-insert :insert-into #'format-insert
:update #'format-selector :update #'format-selector
:delete #'format-selector :delete #'format-selects
:delete-from #'format-selector :delete-from #'format-selector
:truncate #'format-selector :truncate #'format-selector
:columns #'format-selector :columns #'format-columns
:set #'format-set-exprs :set #'format-set-exprs
:from #'format-selector :from #'format-selects
:join #'format-join :join #'format-join
:left-join #'format-join :left-join #'format-join
:right-join #'format-join :right-join #'format-join
:inner-join #'format-join :inner-join #'format-join
:outer-join #'format-join :outer-join #'format-join
:full-join #'format-join :full-join #'format-join
:cross-join #'format-selector :cross-join #'format-selects
:where #'format-on-expr :where #'format-on-expr
:group-by #'format-group-by :group-by #'format-group-by
:having #'format-on-expr :having #'format-on-expr
@ -239,8 +326,8 @@
(assert (= (set @current-clause-order) (set (keys @clause-format)))) (assert (= (set @current-clause-order) (set (keys @clause-format))))
(comment :target (comment :target
{:with 20 {;:with 20
:with-recursive 30 ;:with-recursive 30
;:intersect 35 ;:intersect 35
;:union 40 ;:union 40
;:union-all 45 ;:union-all 45
@ -253,15 +340,15 @@
;:truncate 85 ;:truncate 85
;:columns 90 ;:columns 90
:composite 95 :composite 95
:set0 100 ; low-priority set clause ;; no longer needed/supported :set0 100 ; low-priority set clause
;:from 110 ;:from 110
;:join 120 ;:join 120
;:left-join 130 ;:left-join 130
;:right-join 140 ;:right-join 140
;:full-join 150 ;:full-join 150
;:cross-join 152 ; doesn't have on clauses ;:cross-join 152 ; doesn't have on clauses
:set 155 ;:set 155
:set1 156 ; high-priority set clause (synonym for :set) ;; no longer needed/supported :set1 156 ; high-priority set clause (synonym for :set)
;:where 160 ;:where 160
;:group-by 170 ;:group-by 170
;:having 180 ;:having 180
@ -269,10 +356,10 @@
;:limit 200 ;:limit 200
;:offset 210 ;:offset 210
:lock 215 :lock 215
:values 220 ;:values 220
:query-values 230}) :query-values 230})
(defn- format-dsl [x & [nested?]] (defn- format-dsl [x & [{:keys [aliased? nested?]}]]
(let [[sqls params leftover] (let [[sqls params leftover]
(reduce (fn [[sql params leftover] k] (reduce (fn [[sql params leftover] k]
(if-let [xs (k x)] (if-let [xs (k x)]
@ -294,7 +381,8 @@
leftover)) leftover))
[(str "<unknown" (str/join (keys leftover)) ">")]) [(str "<unknown" (str/join (keys leftover)) ">")])
(into [(cond-> (str/join " " sqls) (into [(cond-> (str/join " " sqls)
nested? (as-> s (str "(" s ")")))] params)))) (and nested? (not aliased?))
(as-> s (str "(" s ")")))] params))))
(def ^:private infix-aliases (def ^:private infix-aliases
"Provided for backward compatibility with earlier HoneySQL versions." "Provided for backward compatibility with earlier HoneySQL versions."
@ -316,9 +404,9 @@
(def ^:private special-syntax (def ^:private special-syntax
{:between {:between
(fn [[x a b]] (fn [[x a b]]
(let [[sql-x & params-x] (format-expr x true) (let [[sql-x & params-x] (format-expr x {:nested? true})
[sql-a & params-a] (format-expr a true) [sql-a & params-a] (format-expr a {:nested? true})
[sql-b & params-b] (format-expr b 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)
@ -332,20 +420,20 @@
(let [[sql & params] (format-expr n)] (let [[sql & params] (format-expr n)]
(into [(str "INTERVAL " sql " " (sql-kw units))] params)))}) (into [(str "INTERVAL " sql " " (sql-kw units))] params)))})
(defn format-expr [x & [nested?]] (defn format-expr [x & [{:keys [nested?] :as opts}]]
(cond (keyword? x) (cond (or (keyword? x) (symbol? x))
[(format-entity x)] [(format-entity x opts)]
(map? x) (map? x)
(format-dsl x true) (format-dsl x (assoc opts :nested? true))
(sequential? x) (sequential? x)
(let [op (first x)] (let [op (first x)]
(if (keyword? op) (if (keyword? op)
(cond (infix-ops op) (cond (infix-ops op)
(let [[_ a b] x (let [[_ a b] x
[s1 & p1] (format-expr a true) [s1 & p1] (format-expr a {:nested? true})
[s2 & p2] (format-expr b true)] [s2 & p2] (format-expr b {:nested? true})]
(-> (str s1 " " (-> (str s1 " "
(sql-kw (get infix-aliases op op)) (sql-kw (get infix-aliases op op))
" " s2) " " s2)
@ -358,14 +446,22 @@
(let [formatter (special-syntax op)] (let [formatter (special-syntax op)]
(formatter (rest x))) (formatter (rest x)))
:else :else
(let [[sqls params] (format-expr-list (rest x))] (let [args (rest x)
[sqls params] (format-expr-list args)]
(into [(str (sql-kw op) (into [(str (sql-kw op)
"(" (str/join ", " sqls) ")")] (if (and (= 1 (count args))
(map? (first args))
(= 1 (count sqls)))
(str " " (first sqls))
(str "(" (str/join ", " sqls) ")")))]
params))) params)))
(into [(str "(" (str/join ", " (into [(str "(" (str/join ", "
(repeat (count x) "?")) ")")] (repeat (count x) "?")) ")")]
x))) x)))
(boolean? x)
[(upper-case (str x))]
:else :else
["?" x])) ["?" x]))

View file

@ -8,7 +8,7 @@
(deftest mysql-tests (deftest mysql-tests
(is (= ["SELECT * FROM `table` WHERE `id` = ?" 1] (is (= ["SELECT * FROM `table` WHERE `id` = ?" 1]
(#'sut/format {:select [:*] :from [:table] :where [:= :id 1]} (sut/format {:select [:*] :from [:table] :where [:= :id 1]}
{:dialect :mysql})))) {:dialect :mysql}))))
(deftest expr-tests (deftest expr-tests
@ -33,24 +33,24 @@
(deftest general-tests (deftest general-tests
(is (= ["SELECT * FROM \"table\" WHERE \"id\" = ?" 1] (is (= ["SELECT * FROM \"table\" WHERE \"id\" = ?" 1]
(#'sut/format {:select [:*] :from [:table] :where [:= :id 1]} {:quoted true}))) (sut/format {:select [:*] :from [:table] :where [:= :id 1]} {:quoted true})))
;; temporarily remove AS from alias here ;; temporarily remove AS from alias here
(is (= ["SELECT \"t\".* FROM \"table\" \"t\" WHERE \"id\" = ?" 1] (is (= ["SELECT \"t\".* FROM \"table\" \"t\" WHERE \"id\" = ?" 1]
(#'sut/format {:select [:t.*] :from [[:table :t]] :where [:= :id 1]} {:quoted true}))) (sut/format {:select [:t.*] :from [[:table :t]] :where [:= :id 1]} {:quoted true})))
(is (= ["SELECT * FROM \"table\" GROUP BY \"foo\", \"bar\""] (is (= ["SELECT * FROM \"table\" GROUP BY \"foo\", \"bar\""]
(#'sut/format {:select [:*] :from [:table] :group-by [:foo :bar]} {:quoted true}))) (sut/format {:select [:*] :from [:table] :group-by [:foo :bar]} {:quoted true})))
(is (= ["SELECT * FROM \"table\" GROUP BY DATE(\"bar\")"] (is (= ["SELECT * FROM \"table\" GROUP BY DATE(\"bar\")"]
(#'sut/format {:select [:*] :from [:table] :group-by [[:date :bar]]} {:quoted true}))) (sut/format {:select [:*] :from [:table] :group-by [[:date :bar]]} {:quoted true})))
(is (= ["SELECT * FROM \"table\" ORDER BY \"foo\" DESC, \"bar\" ASC"] (is (= ["SELECT * FROM \"table\" ORDER BY \"foo\" DESC, \"bar\" ASC"]
(#'sut/format {:select [:*] :from [:table] :order-by [[:foo :desc] :bar]} {:quoted true}))) (sut/format {:select [:*] :from [:table] :order-by [[:foo :desc] :bar]} {:quoted true})))
(is (= ["SELECT * FROM \"table\" ORDER BY DATE(\"expiry\") DESC, \"bar\" ASC"] (is (= ["SELECT * FROM \"table\" ORDER BY DATE(\"expiry\") DESC, \"bar\" ASC"]
(#'sut/format {:select [:*] :from [:table] :order-by [[[:date :expiry] :desc] :bar]} {:quoted true}))) (sut/format {:select [:*] :from [:table] :order-by [[[:date :expiry] :desc] :bar]} {:quoted true})))
(is (= ["SELECT * FROM \"table\" WHERE DATE_ADD(\"expiry\", INTERVAL ? DAYS) < NOW()" 30] (is (= ["SELECT * FROM \"table\" WHERE DATE_ADD(\"expiry\", INTERVAL ? DAYS) < NOW()" 30]
(#'sut/format {:select [:*] :from [:table] :where [:< [:date_add :expiry [:interval 30 :days]] [:now]]} {:quoted true}))) (sut/format {:select [:*] :from [:table] :where [:< [:date_add :expiry [:interval 30 :days]] [:now]]} {:quoted true})))
(is (= ["SELECT * FROM `table` WHERE `id` = ?" 1] (is (= ["SELECT * FROM `table` WHERE `id` = ?" 1]
(#'sut/format {:select [:*] :from [:table] :where [:= :id 1]} {:dialect :mysql}))) (sut/format {:select [:*] :from [:table] :where [:= :id 1]} {:dialect :mysql})))
(is (= ["SELECT * FROM \"table\" WHERE \"id\" IN (?, ?, ?, ?)" 1 2 3 4] (is (= ["SELECT * FROM \"table\" WHERE \"id\" IN (?, ?, ?, ?)" 1 2 3 4]
(#'sut/format {:select [:*] :from [:table] :where [:in :id [1 2 3 4]]} {:quoted true})))) (sut/format {:select [:*] :from [:table] :where [:in :id [1 2 3 4]]} {:quoted true}))))
;; tests lifted from HoneySQL v1 to check for compatibility ;; tests lifted from HoneySQL v1 to check for compatibility
@ -105,8 +105,12 @@
["INSERT INTO foo (id) VALUES (?)" 2]))) ["INSERT INTO foo (id) VALUES (?)" 2])))
(deftest exists-test (deftest exists-test
(is (= (format {:exists {:select [:a] :from [:foo]}}) ;; EXISTS should never have been implemented as SQL syntax: it's an operator!
#_(is (= (format {:exists {:select [:a] :from [:foo]}})
["EXISTS (SELECT a FROM foo)"])) ["EXISTS (SELECT a FROM foo)"]))
;; ugly because it's hard to select just a function call without an alias:
(is (= (format {:select [[[:exists {:select [:a] :from [:foo]}] :x]]})
["SELECT EXISTS (SELECT a FROM foo) AS x"]))
(is (= (format {:select [:id] (is (= (format {:select [:id]
:from [:foo] :from [:foo]
:where [:exists {:select [1] :where [:exists {:select [1]
@ -115,12 +119,12 @@
["SELECT id FROM foo WHERE EXISTS (SELECT ? FROM bar WHERE deleted)" 1]))) ["SELECT id FROM foo WHERE EXISTS (SELECT ? FROM bar WHERE deleted)" 1])))
(deftest array-test (deftest array-test
(println 'sql-array :unimplemented) (is nil "sql-array unimplemented")
#_(is (= (format {:insert-into :foo #_(is (= (format {:insert-into :foo
:columns [:baz] :columns [:baz]
:values [[(sql/array [1 2 3 4])]]}) :values [[(sql/array [1 2 3 4])]]})
["INSERT INTO foo (baz) VALUES (ARRAY[?, ?, ?, ?])" 1 2 3 4])) ["INSERT INTO foo (baz) VALUES (ARRAY[?, ?, ?, ?])" 1 2 3 4]))
(println 'sql-array :unimplemented) (is nil "sql-array unimplemented")
#_(is (= (format {:insert-into :foo #_(is (= (format {:insert-into :foo
:columns [:baz] :columns [:baz]
:values [[(sql/array ["one" "two" "three"])]]}) :values [[(sql/array ["one" "two" "three"])]]})
@ -135,7 +139,15 @@
;; ORDER BY foo ASC ;; ORDER BY foo ASC
(is (= (format {:union [{:select [:foo] :from [:bar1]} (is (= (format {:union [{:select [:foo] :from [:bar1]}
{:select [:foo] :from [:bar2]}]}) {:select [:foo] :from [:bar2]}]})
["SELECT foo FROM bar1 UNION SELECT foo FROM bar2"]))) ["SELECT foo FROM bar1 UNION SELECT foo FROM bar2"]))
(testing "union complex values"
(is (= (format {:union [{:select [:foo] :from [:bar1]}
{:select [:foo] :from [:bar2]}]
:with [[[:bar {:columns [:spam :eggs]}]
{:values [[1 2] [3 4] [5 6]]}]]})
["WITH bar (spam, eggs) AS (VALUES (?, ?), (?, ?), (?, ?)) SELECT foo FROM bar1 UNION SELECT foo FROM bar2"
1 2 3 4 5 6]))))
(deftest union-all-test (deftest union-all-test
(is (= (format {:union-all [{:select [:foo] :from [:bar1]} (is (= (format {:union-all [{:select [:foo] :from [:bar1]}
@ -168,7 +180,7 @@
(deftest compare-expressions-test (deftest compare-expressions-test
(testing "Sequences should be fns when in value/comparison spots" (testing "Sequences should be fns when in value/comparison spots"
(is (= ["SELECT foo FROM bar WHERE (col1 mod ?) = (col2 + ?)" 4 4] (is (= ["SELECT foo FROM bar WHERE (col1 MOD ?) = (col2 + ?)" 4 4]
(format {:select [:foo] (format {:select [:foo]
:from [:bar] :from [:bar]
:where [:= [:mod :col1 4] [:+ :col2 4]]})))) :where [:= [:mod :col1 4] [:+ :col2 4]]}))))
@ -177,11 +189,11 @@
(let [sub {:select [:%sum.amount] (let [sub {:select [:%sum.amount]
:from [:bar] :from [:bar]
:where [:in :id ["id-1" "id-2"]]}] :where [:in :id ["id-1" "id-2"]]}]
(is (= ["SELECT total FROM foo WHERE (SELECT sum(amount) FROM bar WHERE (id in (?, ?))) = total" "id-1" "id-2"] (is (= ["SELECT total FROM foo WHERE (SELECT sum(amount) FROM bar WHERE id IN (?, ?)) = total" "id-1" "id-2"]
(format {:select [:total] (format {:select [:total]
:from [:foo] :from [:foo]
:where [:= sub :total]}))) :where [:= sub :total]})))
(is (= ["WITH t AS (SELECT sum(amount) FROM bar WHERE (id in (?, ?))) SELECT total FROM foo WHERE total = t" "id-1" "id-2"] (is (= ["WITH t AS (SELECT sum(amount) FROM bar WHERE id IN (?, ?)) SELECT total FROM foo WHERE total = t" "id-1" "id-2"]
(format {:with [[:t sub]] (format {:with [[:t sub]]
:select [:total] :select [:total]
:from [:foo] :from [:foo]
@ -204,7 +216,7 @@
(deftest parameterizer-none (deftest parameterizer-none
(testing "array parameter" (testing "array parameter"
(println 'sql-array :unimplemented) (is nil "sql-array unimplemented")
#_(is (= (format {:insert-into :foo #_(is (= (format {:insert-into :foo
:columns [:baz] :columns [:baz]
:values [[(sql/array [1 2 3 4])]]} :values [[(sql/array [1 2 3 4])]]}
@ -250,7 +262,7 @@
:from [[:bar :b]] :from [[:bar :b]]
:where [:= :b.id 1]} :c]] :where [:= :b.id 1]} :c]]
:where [:= :f.kind "drama"]} :where [:= :f.kind "drama"]}
(format))))) (format {:quoted true})))))
(deftest set-after-join (deftest set-after-join
(is (= (is (=
@ -282,7 +294,7 @@
(format {:dialect :mysql}))))) (format {:dialect :mysql})))))
(deftest inlined-values-are-stringified-correctly (deftest inlined-values-are-stringified-correctly
(println 'inline :unimplemented) (is nil "inline unimplemented")
#_(is (= ["SELECT foo, bar, NULL"] #_(is (= ["SELECT foo, bar, NULL"]
(format {:select [(honeysql.core/inline "foo") (format {:select [(honeysql.core/inline "foo")
(honeysql.core/inline :bar) (honeysql.core/inline :bar)