diff --git a/doc/clause-reference.md b/doc/clause-reference.md index da65500..70f917e 100644 --- a/doc/clause-reference.md +++ b/doc/clause-reference.md @@ -815,6 +815,17 @@ user=> (sql/format {:select [:u.username :s.name] ["SELECT u.username, s.name FROM user AS u, status AS s WHERE (u.statusid = s.id) AND (u.id = ?)" 9] ``` +`:from` can also accept a `:values` clause: + +```clojure +user=> (sql/format {:update :table :set {:a :v.a} + :from [[{:values [[1 2 3] + [4 5 6]]} + [:v [:composite :a :b :c]]]] + :where [:and [:= :x :v.b] [:> :y :v.c]]}) +["UPDATE table SET a = v.a FROM (VALUES (?, ?, ?), (?, ?, ?)) AS v (a, b, c) WHERE (x = v.b) AND (y > v.c)" 1 2 3 4 5 6] +``` + As of 2.4.1066, HoneySQL supports a temporal clause that starts with `:for`, followed by the time reference (e.g., `:system-time` or `:business-time`), followed by a temporal qualifier, diff --git a/doc/special-syntax.md b/doc/special-syntax.md index 7208373..c910e52 100644 --- a/doc/special-syntax.md +++ b/doc/special-syntax.md @@ -174,6 +174,23 @@ expression (comma-separated, wrapped in parentheses): ;;=> ["(a, b, ?, x + ?)" "red" 1] ``` +This can be useful in a number of situations where you want a composite +value, as above, or a composite based on or declaring columns names: + +```clojure +(sql/format {:select [[[:composite :a :b] :c]] :from :table}) +;;=> ["SELECT (a, b) AS c FROM table"] +``` + +```clojure +(sql/format {:update :table :set {:a :v.a} + :from [[{:values [[1 2 3] + [4 5 6]]} + [:v [:composite :a :b :c]]]] + :where [:and [:= :x :v.b] [:> :y :v.c]]}) +;;=> ["UPDATE table FROM (VALUES (?, ?, ?), (?, ?, ?)) AS v (a, b, c) SET a = v.a WHERE (x = v.b) AND (y > v.c)" 1 2 3 4 5 6] +``` + ## distinct Accepts a single expression and prefixes it with `DISTINCT `: diff --git a/src/honey/sql.cljc b/src/honey/sql.cljc index fb964d2..1d09d33 100644 --- a/src/honey/sql.cljc +++ b/src/honey/sql.cljc @@ -341,7 +341,7 @@ (when k (let [n (str/replace (name k) "?" "??")] (if (= \' (first n)) - (let [ident (subs n 1 (count n)) + (let [ident (subs n 1) ident-l (str/lower-case ident)] (binding [*quoted* (when-not (contains? #{"array"} ident-l) *quoted*)] (format-entity (keyword ident)))) diff --git a/test/honey/sql_test.cljc b/test/honey/sql_test.cljc index 7d58241..18a3d58 100644 --- a/test/honey/sql_test.cljc +++ b/test/honey/sql_test.cljc @@ -1341,10 +1341,26 @@ ORDER BY id = ? DESC (= ["SELECT * FROM table WITH (DEF, ABC)"] (sut/format {:select [:*] :from [^{:abc true :def true} [:table]]})))))) +(deftest issue-527-composite + (is (= ["SELECT (a, b) AS c FROM table"] + (sut/format {:select [[[:composite :a :b] :c]] :from [:table]}))) + (is (= ["SELECT a FROM table WHERE (b, c) = (?, ?)" 1 2] + (sut/format {:select :a :from :table :where [:= [:composite :b :c] [:composite 1 2]]}))) + (is (= ["SELECT a, b, c FROM (VALUES (?, ?, ?), (?, ?, ?)) AS t (a, b, c)" 1 2 3 4 5 6] + (sut/format {:select [:a :b :c] + :from [[{:values [[1 2 3] [4 5 6]]} + [:t [:composite :a :b :c]]]]})))) + (comment ;; partial (incorrect!) workaround for #407: (sut/format {:select :f.* :from [[:foo [:f :for :system-time]]] :where [:= :f.id 1]}) ;; correct version: (sut/format {:select :f.* :from [[:foo :f :for :system-time]] :where [:= :f.id 1]}) (sut/format {:where [:= :x [:inline :DATE "2019-01-01"]]}) + ;; https://github.com/seancorfield/honeysql/issues/526 + (-> + {:create-table-as [:a-b.b-c.c-d] + :select [:*] + :from [:a-b.b-c.c-d]} + (sut/format {:dialect :nrql})) )