diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a1d2bf..c68f262 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changes * 2.3.next in progress + * Fix [#438](https://github.com/seancorfield/honeysql/issues/438) by + supporting options on `TRUNCATE`. * Address [#435](https://github.com/seancorfield/honeysql/issues/435) by showing `CREATE TEMP TABLE` etc. * Fix [#431](https://github.com/seancorfield/honeysql/issues/431). * Address [#430](https://github.com/seancorfield/honeysql/issues/430) by treating `:'` as introducing a name that should be treating literally and not formatted as a SQL entity (which respects quoting, dot-splitting, etc); this effectively expands the "escape hatch" introduced via [#352](https://github.com/seancorfield/honeysql/issues/352) in 2.2.868. _Note that the function context behavior formats as a SQL entity, rather than the usual SQL "keyword", whereas this new context is a literal transcription rather than as a SQL entity!_ diff --git a/doc/clause-reference.md b/doc/clause-reference.md index ef5959d..cc14855 100644 --- a/doc/clause-reference.md +++ b/doc/clause-reference.md @@ -321,7 +321,7 @@ order they would appear in a valid SQL statement). These provide CTE support for SQL Server. The argument to `:with` (or `:with-recursive`) is a sequences of pairs, each of -a result set name (or description) and either of; a basic SQL +a result set name (or description) and either of; a basic SQL statement, a string, a keyword or a symbol. The result set can either be a SQL entity (a simple name) or a pair of a SQL entity and a set of column names. @@ -336,7 +336,7 @@ user=> (sql/format '{with ((stuff {select (:*) from (foo)}), ``` When the expression is a basic SQL statement in any of the pairs, -the resulting syntax of the pair is `with ident AS expr` as shown above. +the resulting syntax of the pair is `with ident AS expr` as shown above. However, when the expression is a string, a keyword or a symbol, the resulting syntax of the pair is of the form `with expr AS ident` like this: @@ -348,7 +348,7 @@ user=> (sql/format '{with ((ts_upper_bound "2019-08-01 15:23:00")) ["WITH ? AS ts_upper_bound SELECT * FROM hits WHERE EventDate = ts_upper_bound" "2019-08-01 15:23:00"] ``` -The syntax only varies for each pair and so you can use both SQL statements +The syntax only varies for each pair and so you can use both SQL statements and keywords/strings/symbols in the same WITH clause like this: ```clojure @@ -590,11 +590,14 @@ user=> (sql/format {:delete [:order :item] ## truncate -`:truncate` accepts a simple SQL entity (table name): +`:truncate` accepts a simple SQL entity (table name) +or a table name followed by various options: ```clojure user=> (sql/format '{truncate transport}) ["TRUNCATE transport"] +user=> (sql/format '{truncate (transport restart identity)}) +["TRUNCATE transport RESTART IDENTITY"] ``` ## columns diff --git a/src/honey/sql.cljc b/src/honey/sql.cljc index 8680993..27f798d 100644 --- a/src/honey/sql.cljc +++ b/src/honey/sql.cljc @@ -894,14 +894,14 @@ :else (sql-kw opt)))) -(defn- destructure-create-item [table context] +(defn- destructure-ddl-item [table context] (let [params (if (sequential? table) table [table]) tab? #(or (ident? %) (string? %)) coll (take-while tab? params) - opts (drop-while tab? params) + opts (filter some? (drop-while tab? params)) ine (last coll) [prequel table ine] (if (= :if-not-exists (sym->kw ine)) @@ -910,11 +910,26 @@ (into [(str/join " " (map sql-kw prequel)) (format-entity table) (when ine (sql-kw ine))] - (format-ddl-options opts context)))) + (when opts + (format-ddl-options opts context))))) + +(defn- format-truncate [k xs] + (let [[table & options] (if (sequential? xs) xs [xs]) + [pre table ine options] (destructure-ddl-item [table options] "truncate")] + (when (seq pre) (throw (ex-info "TRUNCATE syntax error" {:unexpected pre}))) + (when (seq ine) (throw (ex-info "TRUNCATE syntax error" {:unexpected ine}))) + [(str/join " " (cond-> [(sql-kw k) table] + (seq options) + (conj options)))])) + +(comment + (destructure-ddl-item [:foo [:abc [:continue :wibble] :identity]] "test") + (destructure-ddl-item [:foo] "test") + (format-truncate :truncate [:foo])) (defn- format-create [q k item as] (let [[pre entity ine & more] - (destructure-create-item item (str (sql-kw q) " options"))] + (destructure-ddl-item item (str (sql-kw q) " options"))] [(str/join " " (remove nil? (-> [(sql-kw q) (when (and (= :create q) (seq pre)) pre) @@ -1098,7 +1113,7 @@ :update (check-where #'format-selector) :delete (check-where #'format-selects) :delete-from (check-where #'format-selector) - :truncate #'format-selector + :truncate #'format-truncate :columns #'format-columns :set #'format-set-exprs :from #'format-selects diff --git a/test/honey/sql_test.cljc b/test/honey/sql_test.cljc index 6f53613..952f359 100644 --- a/test/honey/sql_test.cljc +++ b/test/honey/sql_test.cljc @@ -519,6 +519,9 @@ (deftest truncate-test (is (= ["TRUNCATE `foo`"] (-> {:truncate :foo} + (format {:dialect :mysql})))) + (is (= ["TRUNCATE `foo` CONTINUE IDENTITY"] + (-> {:truncate [:foo :continue :identity]} (format {:dialect :mysql}))))) (deftest inlined-values-are-stringified-correctly