Fixes #308 by adding support for clauses
This also corrects the docstring for the join-by helper.
This commit is contained in:
parent
d734767877
commit
e6a5bdb001
5 changed files with 48 additions and 9 deletions
|
|
@ -4,6 +4,7 @@
|
|||
* The documentation continues to be expanded and clarified in response to feedback!
|
||||
* Tentative fix for #315 by expanding `:in` handling to deal with `nil` values.
|
||||
* Fix #310 by adding support for `FILTER`, `WITHIN GROUP`, and `ORDER BY` (as an expression), from [nilenso/honeysql-postgres](https://github.com/nilenso/honeysql-postgres) 0.4.112. These are [Special Syntax](doc/special-syntax.md) and there are also helpers for `filter` and `within-group` -- so **be careful about referring in all of `honey.sql.helpers`** since it will now shadow `clojure.core/filter` (it already shadows `for`, `group-by`, `into`, `partition-by`, `set`, and `update`).
|
||||
* Fix #308 by supporting join clauses in `join-by`.
|
||||
|
||||
* 2.0.0-beta1 (for testing; 2021-04-09)
|
||||
* Since Alpha 3, more documentation has been written and existing documentation clarified (addressing #300, #309, #313, #314).
|
||||
|
|
|
|||
|
|
@ -528,9 +528,9 @@ for more detail).
|
|||
## join-by
|
||||
|
||||
This is a convenience that allows for an arbitrary sequence of `JOIN`
|
||||
operations to be performed in a specific order. It accepts a sequence
|
||||
of join operation name (keyword or symbol) and the clause that join
|
||||
would take:
|
||||
operations to be performed in a specific order. It accepts either a sequence
|
||||
of alternating join operation name (keyword or symbol) and the clause that join
|
||||
would take, or a sequence of `JOIN` clauses as hash maps:
|
||||
|
||||
```clojure
|
||||
user=> (sql/format {:select [:t.ref :pp.code]
|
||||
|
|
@ -540,7 +540,24 @@ user=> (sql/format {:select [:t.ref :pp.code]
|
|||
:join [[:logtransaction :log]
|
||||
[:= :t.id :log.id]]]
|
||||
:where [:= "settled" :pp.status]})
|
||||
["SELECT t.ref, pp.code FROM transaction AS t LEFT JOIN paypal_tx AS pp USING (id) INNER JOIN logtransaction AS log ON t.id = log.id WHERE ? = pp.status" "settled"]
|
||||
;; newlines inserted for readability:
|
||||
["SELECT t.ref, pp.code FROM transaction AS t
|
||||
LEFT JOIN paypal_tx AS pp USING (id)
|
||||
INNER JOIN logtransaction AS log ON t.id = log.id
|
||||
WHERE ? = pp.status" "settled"]
|
||||
;; or using helpers:
|
||||
user=> (sql/format (-> (select :t.ref :pp.code)
|
||||
(from [:transaction :t])
|
||||
(join-by (left-join [:paypal-tx :pp]
|
||||
[:using :id])
|
||||
(join [:logtransaction :log]
|
||||
[:= :t.id :log.id]))
|
||||
(where := "settled" :pp.status)))
|
||||
;; newlines inserted for readability:
|
||||
["SELECT t.ref, pp.code FROM transaction AS t
|
||||
LEFT JOIN paypal_tx AS pp USING (id)
|
||||
INNER JOIN logtransaction AS log ON t.id = log.id
|
||||
WHERE ? = pp.status" "settled"]
|
||||
```
|
||||
|
||||
Without `:join-by`, a `:join` would normally be generated before a `:left-join`.
|
||||
|
|
|
|||
|
|
@ -464,10 +464,16 @@
|
|||
|
||||
(defn- format-join-by
|
||||
"Clauses should be a sequence of join types followed
|
||||
by their table and condition, so that you can construct
|
||||
a series of joins in a specific order."
|
||||
by their table and condition, or a sequence of join
|
||||
clauses, so that you can construct a series of joins
|
||||
in a specific order."
|
||||
[_ clauses]
|
||||
(let [joins (partition-by ident? clauses)]
|
||||
(let [joins (if (every? map? clauses)
|
||||
(into []
|
||||
(comp (mapcat #(mapcat (juxt key val) %))
|
||||
(map vector))
|
||||
clauses)
|
||||
(partition-by ident? clauses))]
|
||||
(when-not (even? (count joins))
|
||||
(throw (ex-info ":join-by expects a sequence of join clauses"
|
||||
{:clauses clauses})))
|
||||
|
|
|
|||
|
|
@ -470,8 +470,8 @@
|
|||
|
||||
(-> (select :*)
|
||||
(from :foo)
|
||||
(join-by :left :bar [:= :foo.id :bar.id]
|
||||
:join :quux [:= :bar.qid = :quux.id])
|
||||
(join-by :left [:bar [:= :foo.id :bar.id]]
|
||||
:join [:quux [:= :bar.qid :quux.id]]))
|
||||
|
||||
This produces a LEFT JOIN followed by an INNER JOIN
|
||||
even though the 'natural' order for `left-join` and
|
||||
|
|
|
|||
|
|
@ -232,6 +232,21 @@
|
|||
:right-join [:bock [:= :bock.z :c.e]]
|
||||
:left-join [[:clod :c] [:= :f.a :c.d]]
|
||||
:inner-join [:draq [:= :f.b :draq.x]])
|
||||
(sql/format)))))
|
||||
(testing "Specific JOIN orders with join clauses"
|
||||
(is (= ["SELECT * FROM foo FULL JOIN beck ON beck.x = c.y RIGHT JOIN bock ON bock.z = c.e LEFT JOIN clod AS c ON f.a = c.d INNER JOIN draq ON f.b = draq.x"]
|
||||
(sql/format {:select [:*] :from [:foo]
|
||||
:join-by [{:full-join [:beck [:= :beck.x :c.y]]}
|
||||
{:right-join [:bock [:= :bock.z :c.e]]}
|
||||
{:left-join [[:clod :c] [:= :f.a :c.d]]}
|
||||
{:join [:draq [:= :f.b :draq.x]]}]})))
|
||||
(is (= ["SELECT * FROM foo FULL JOIN beck ON beck.x = c.y RIGHT JOIN bock ON bock.z = c.e LEFT JOIN clod AS c ON f.a = c.d INNER JOIN draq ON f.b = draq.x"]
|
||||
(-> (select :*)
|
||||
(from :foo)
|
||||
(join-by (full-join :beck [:= :beck.x :c.y])
|
||||
(right-join :bock [:= :bock.z :c.e])
|
||||
(left-join [:clod :c] [:= :f.a :c.d])
|
||||
(join :draq [:= :f.b :draq.x]))
|
||||
(sql/format))))))
|
||||
|
||||
(deftest test-cast
|
||||
|
|
|
|||
Loading…
Reference in a new issue