diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c3ebf1..9e8fe27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changes +* 2.7.next in progress + * Fix [#571](https://github.com/seancorfield/honeysql/issues/571) by allowing `:order-by` to take an empty sequence of columns (and be omitted). + * 2.7.1295 -- 2025-03-12 * Address #570 by adding `:.:.` as special syntax for Snowflake's JSON path syntax, and `:at` as special syntax for general `[`..`]` path syntax. * Drop support for Clojure 1.9 [#561](https://github.com/seancorfield/honeysql/issues/561). diff --git a/doc/clause-reference.md b/doc/clause-reference.md index 4010a69..92562fb 100644 --- a/doc/clause-reference.md +++ b/doc/clause-reference.md @@ -1070,6 +1070,9 @@ The `:where` clause can have a single SQL expression, or a sequence of SQL expressions prefixed by either `:and` or `:or`. See examples of `:where` in various clauses above. +If `:where` is given an empty sequence, the `WHERE` clause will +be omitted from the generated SQL. + Sometimes it is convenient to construct a `WHERE` clause that tests several columns for equality, and you might have a Clojure hash map containing those values. `honey.sql/map=` exists to @@ -1210,12 +1213,15 @@ user=> (sql/format {:select [[[:over ## order-by -`:order-by` accepts a sequence of one or more ordering +`:order-by` accepts a sequence of zero or more ordering expressions. Each ordering expression is either a simple SQL entity or a pair of a SQL expression and a direction (which can be `:asc`, `:desc`, `:nulls-first`, `:desc-null-last`, etc -- or the symbol equivalent). +If `:order-by` is given an empty sequence, the `ORDER BY` clause will +be omitted from the generated SQL. + If you want to order by an expression, you should wrap it as a pair with a direction: diff --git a/src/honey/sql.cljc b/src/honey/sql.cljc index b035ea1..6ed773d 100644 --- a/src/honey/sql.cljc +++ b/src/honey/sql.cljc @@ -1119,11 +1119,13 @@ dirs (map #(when (sequential? %) (second %)) xs) [sqls params] (format-expr-list (map #(if (sequential? %) (first %) %) xs))] - (into [(str (sql-kw k) " " - (join ", " (map (fn [sql dir] - (str sql " " (sql-kw (or dir :asc)))) - sqls - dirs)))] params))) + (if (seq sqls) + (into [(str (sql-kw k) " " + (join ", " (map (fn [sql dir] + (str sql " " (sql-kw (or dir :asc)))) + sqls + dirs)))] params) + []))) (defn- format-lock-strength [k xs] (let [[strength tables nowait] (ensure-sequential xs)] @@ -1771,7 +1773,7 @@ (if (seq leftover) (throw (ex-info (str "These SQL clauses are unknown or have nil values: " (join ", " (keys leftover)) - "(perhaps you need [:lift {" + " (perhaps you need [:lift {" (first (keys leftover)) " ...}] here?)") leftover)) diff --git a/test/honey/sql_test.cljc b/test/honey/sql_test.cljc index 3bd63bc..bb44f22 100644 --- a/test/honey/sql_test.cljc +++ b/test/honey/sql_test.cljc @@ -1486,6 +1486,24 @@ ORDER BY id = ? DESC (h/select :*) (h/from :table))))))) +(deftest issue-571 + (testing "an empty where clause is omitted" + (is (= ["SELECT * FROM foo"] + (sut/format {:select :* :from :foo :where []}))) + #?(:clj + (is (thrown? clojure.lang.ExceptionInfo + (sut/format {:select :* :from :foo :where nil})))) + (is (= ["SELECT * FROM foo WHERE 1 = 1"] + (sut/format {:select :* :from :foo :where [:= 1 1]} {:inline true})))) + (testing "an empty order by clause is omitted" + (is (= ["SELECT * FROM foo"] + (sut/format {:select :* :from :foo :order-by []}))) + #?(:clj + (is (thrown? clojure.lang.ExceptionInfo + (sut/format {:select :* :from :foo :order-by nil})))) + (is (= ["SELECT * FROM foo ORDER BY bar ASC"] + (sut/format {:select :* :from :foo :order-by [:bar]}))))) + (comment ;; partial (incorrect!) workaround for #407: (sut/format {:select :f.* :from [[:foo [:f :for :system-time]]] :where [:= :f.id 1]})