Fixes #298 by restoring multi-CTE capability
Reverts code changes that stripped the sequence support. Updates the docs to clarify how sequence support works.
This commit is contained in:
parent
e02b5b5c82
commit
0a83601c3c
4 changed files with 54 additions and 3 deletions
|
|
@ -12,7 +12,53 @@ Except as noted, these clauses apply to all the SQL
|
||||||
dialects that HoneySQL supports.
|
dialects that HoneySQL supports.
|
||||||
|
|
||||||
## nest
|
## nest
|
||||||
|
|
||||||
|
This is pseudo-syntax that lets you wrap a substatement
|
||||||
|
in an extra level of parentheses. It should rarely be
|
||||||
|
needed and it is mostly present to provide the same
|
||||||
|
functionality for clauses that `[:nest ..]` provides
|
||||||
|
for expressions.
|
||||||
|
|
||||||
## with, with-recursive
|
## with, with-recursive
|
||||||
|
|
||||||
|
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 a basic SQL statement.
|
||||||
|
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.
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
user=> (sql/format '{with ((stuff {select (:*) from (foo)}),
|
||||||
|
(nonsense {select (:*) from (bar)}))
|
||||||
|
select (foo.id,bar.name)
|
||||||
|
from (stuff, nonsense)
|
||||||
|
where (= status 0)})
|
||||||
|
["WITH stuff AS (SELECT * FROM foo), nonsense AS (SELECT * FROM bar) SELECT foo.id, bar.name FROM stuff, nonsense WHERE status = ?" 0]
|
||||||
|
```
|
||||||
|
|
||||||
|
You can specify a list of columns for the CTE like this:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
user=> (sql/format {:with [[[:stuff {:columns [:id :name]}]
|
||||||
|
{:select [:*] :from [:foo]}]]
|
||||||
|
:select [:id :name]
|
||||||
|
:from [:stuff]
|
||||||
|
:where [:= :status 0]})
|
||||||
|
["WITH stuff (id, name) AS (SELECT * FROM foo) SELECT id, name FROM stuff WHERE status = ?" 0]
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use a `VALUES` clause in the CTE:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
user=> (sql/format {:with [[[:stuff {:columns [:id :name]}]
|
||||||
|
{:values [[1 "Sean"] [2 "Jay"]]}]]
|
||||||
|
:select [:id :name]
|
||||||
|
:from [:stuff]})
|
||||||
|
["WITH stuff (id, name) AS (VALUES (?, ?), (?, ?)) SELECT id, name FROM stuff" 1 "Sean" 2 "Jay"]
|
||||||
|
```
|
||||||
|
|
||||||
|
`:with-recursive` follows the same rules as `:with` and produces `WITH RECURSIVE` instead of just `WITH`.
|
||||||
|
|
||||||
## intersect, union, union-all, except, except-all
|
## intersect, union, union-all, except, except-all
|
||||||
|
|
||||||
These all expect a sequence of SQL clauses, those clauses
|
These all expect a sequence of SQL clauses, those clauses
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ values identified in the SQL expressions:
|
||||||
;;=> ["SELECT * FROM table WHERE id = ?" 1]
|
;;=> ["SELECT * FROM table WHERE id = ?" 1]
|
||||||
```
|
```
|
||||||
|
|
||||||
Any values found in the data structure, that are not keywords
|
By default, any values found in the data structure, that are not keywords
|
||||||
or symbols, are treated as positional parameters and replaced
|
or symbols, are treated as positional parameters and replaced
|
||||||
by `?` in the SQL string and lifted out into the vector that
|
by `?` in the SQL string and lifted out into the vector that
|
||||||
is returned from `format`.
|
is returned from `format`.
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,8 @@
|
||||||
(assoc {} k data)))
|
(assoc {} k data)))
|
||||||
|
|
||||||
(defn nest [& args] (generic :nest args))
|
(defn nest [& args] (generic :nest args))
|
||||||
(defn with [& args] (generic-1 :with args))
|
(defn with [& args] (generic :with args))
|
||||||
(defn with-recursive [& args] (generic-1 :with-recursive args))
|
(defn with-recursive [& args] (generic :with-recursive args))
|
||||||
;; these five need to supply an empty hash map since they wrap
|
;; these five need to supply an empty hash map since they wrap
|
||||||
;; all of their arguments:
|
;; all of their arguments:
|
||||||
(defn intersect [& args] (generic :intersect (cons {} args)))
|
(defn intersect [& args] (generic :intersect (cons {} args)))
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,11 @@
|
||||||
(deftest test-cte
|
(deftest test-cte
|
||||||
(is (= (format {:with [[:query {:select [:foo] :from [:bar]}]]})
|
(is (= (format {:with [[:query {:select [:foo] :from [:bar]}]]})
|
||||||
["WITH query AS (SELECT foo FROM bar)"]))
|
["WITH query AS (SELECT foo FROM bar)"]))
|
||||||
|
(is (= (format {:with [[:query1 {:select [:foo] :from [:bar]}]
|
||||||
|
[:query2 {:select [:bar] :from [:quux]}]]
|
||||||
|
:select [:query1.id :query2.name]
|
||||||
|
:from [:query1 :query2]})
|
||||||
|
["WITH query1 AS (SELECT foo FROM bar), query2 AS (SELECT bar FROM quux) SELECT query1.id, query2.name FROM query1, query2"]))
|
||||||
(is (= (format {:with-recursive [[:query {:select [:foo] :from [:bar]}]]})
|
(is (= (format {:with-recursive [[:query {:select [:foo] :from [:bar]}]]})
|
||||||
["WITH RECURSIVE query AS (SELECT foo FROM bar)"]))
|
["WITH RECURSIVE query AS (SELECT foo FROM bar)"]))
|
||||||
(is (= (format {:with [[[:static {:columns [:a :b :c]}] {:values [[1 2 3] [4 5]]}]]})
|
(is (= (format {:with [[[:static {:columns [:a :b :c]}] {:values [[1 2 3] [4 5]]}]]})
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue