From fd84864279e9d2c3eb040ffd8893d106d28b3ffd Mon Sep 17 00:00:00 2001 From: Sean Corfield Date: Mon, 15 Mar 2021 14:48:28 -0700 Subject: [PATCH] Fixes #161 by adding :raw clause support --- CHANGELOG.md | 3 +++ doc/clause-reference.md | 9 +++++++++ doc/special-syntax.md | 4 +++- src/honey/sql.cljc | 31 +++++++++++++++++-------------- src/honey/sql/helpers.cljc | 14 ++------------ 5 files changed, 34 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7f572f..bf3d474 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changes +* 2.0.next in progress + * Fix #161 by adding `:raw` as a clause. There is no helper function equivalent (because it would be ambiguous whether you meant a function form -- `[:raw ..]` -- or a clause form -- `{:raw ..}`; and for the same reason, there is no `nest` helper function since that also works as a clause and as a function/special syntax). + * 2.0.0-alpha3 (for early testing; 2021-03-13) * Change coordinates to `com.github.seancorfield/honeysql` (although new versions will continue to be deployed to `seancorfield/honeysql` for a while -- see the [Clojars Verified Group Names policy](https://github.com/clojars/clojars-web/wiki/Verified-Group-Names)). * Support much richer range of syntax on `CREATE`/`DROP` statements in general, including columns, `TABLESPACE`, `CASCADE`, `WITH [NO] DATA`, etc. diff --git a/doc/clause-reference.md b/doc/clause-reference.md index 21a6047..e4312d4 100644 --- a/doc/clause-reference.md +++ b/doc/clause-reference.md @@ -154,6 +154,15 @@ needed and it is mostly present to provide the same functionality for clauses that `[:nest ..]` provides for expressions. +## raw + +This is pseudo-syntax that lets you insert a complete +SQL clause as a string, if HoneySQL doesn't support +some exotic SQL construct. It should rarely be +needed and it is mostly present to provide the same +functionality for clauses that `[:raw ..]` provides +for expressions (which usage is likely to be more common). + ## with, with-recursive These provide CTE support for SQL Server. The argument to diff --git a/doc/special-syntax.md b/doc/special-syntax.md index 98f8c2e..46d4e07 100644 --- a/doc/special-syntax.md +++ b/doc/special-syntax.md @@ -129,7 +129,7 @@ level of parentheses around it: ;;=> ["WHERE (x = ?)" 42] ``` -`nest` is also supported as a SQL clause for the same reason. +`:nest` is also supported as a SQL clause for the same reason. ## not @@ -202,6 +202,8 @@ parameters from them: ;;=> ["SELECT a, @var := ?" "foo"] ``` +`:raw` is also supported as a SQL clause for the same reason. + ## Column Descriptors There are three types of descriptors that vary diff --git a/src/honey/sql.cljc b/src/honey/sql.cljc index a6cadb4..57d5fbe 100644 --- a/src/honey/sql.cljc +++ b/src/honey/sql.cljc @@ -44,7 +44,7 @@ :drop-table :drop-view :drop-materialized-view :drop-extension :refresh-materialized-view ;; then SQL clauses in priority order: - :nest :with :with-recursive :intersect :union :union-all :except :except-all + :raw :nest :with :with-recursive :intersect :union :union-all :except :except-all :select :select-distinct :select-distinct-on :select-top :select-distinct-top :into :bulk-collect-into :insert-into :update :delete :delete-from :truncate @@ -716,6 +716,20 @@ (defn- format-rename-item [k [x y]] [(str (sql-kw k) " " (format-entity x) " TO " (format-entity y))]) +(defn- raw-render [_ [s]] + (if (sequential? s) + (let [[sqls params] + (reduce (fn [[sqls params] s] + (if (sequential? s) + (let [[sql & params'] (format-expr s)] + [(conj sqls sql) + (into params params')]) + [(conj sqls s) params])) + [[] []] + s)] + (into [(str/join sqls)] params)) + [s])) + (def ^:private base-clause-order "The (base) order for known clauses. Can have items added and removed. @@ -751,6 +765,7 @@ :drop-view #'format-drop-items :drop-materialized-view #'format-drop-items :refresh-materialized-view (fn [_ x] (format-create :refresh :materialized-view x nil)) + :raw #'raw-render :nest (fn [_ x] (format-expr x)) :with #'format-with :with-recursive #'format-with @@ -1049,19 +1064,7 @@ [(sqlize-value (param-value k))] ["?" (->param k)])) :raw - (fn [_ [s]] - (if (sequential? s) - (let [[sqls params] - (reduce (fn [[sqls params] s] - (if (sequential? s) - (let [[sql & params'] (format-expr s)] - [(conj sqls sql) - (into params params')]) - [(conj sqls s) params])) - [[] []] - s)] - (into [(str/join sqls)] params)) - [s]))})) + #'raw-render})) (defn format-expr "Given a data structure that represents a SQL expression and a hash diff --git a/src/honey/sql/helpers.cljc b/src/honey/sql/helpers.cljc index dc7d265..8f9b4d4 100644 --- a/src/honey/sql/helpers.cljc +++ b/src/honey/sql/helpers.cljc @@ -263,17 +263,6 @@ [& views] (generic :refresh-materialized-view views)) -(defn nest - "A pseudo clause that exists purely to cause nesting - in parentheses. Should only be needed very rarely in - cases where HoneySQL doesn't do the right thing for - your specific database dialect. - - Wraps a single clause." - {:arglists '([clause])} - [& args] - (generic :nest args)) - (defn with "Accepts one or more CTE definitions. @@ -887,4 +876,5 @@ ;; ensure all public functions match clauses: (assert (= (clojure.core/set (conj @@#'honey.sql/base-clause-order :composite :lateral :over :upsert)) - (clojure.core/set (map keyword (keys (ns-publics *ns*)))))))) + (clojure.core/set (conj (map keyword (keys (ns-publics *ns*))) + :nest :raw))))))