add distinct/expr clauses
This commit is contained in:
parent
75830df509
commit
ac09fc1abd
5 changed files with 42 additions and 11 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
* 2.4.next in progress
|
* 2.4.next in progress
|
||||||
* Address [#504](https://github.com/seancorfield/honeysql/issues/504) by adding special syntax for ignore/respect nulls. More work will be needed to support distinct/order by/limit in BigQuery array aggregation.
|
* Address [#504](https://github.com/seancorfield/honeysql/issues/504) for BigQuery support, by adding special syntax for ignore/respect nulls, as well as new `:distinct` and `:expr` clauses to allow expressions to be qualified with SQL clauses. The latter will probably be useful for other dialects too.
|
||||||
|
|
||||||
* 2.4.1066 -- 2023-08-27
|
* 2.4.1066 -- 2023-08-27
|
||||||
* Add `:select` with function call and alias example to README (PR [#502](https://github.com/seancorfield/honeysql/pull/502) [@markbastian](https://github.com/markbastian)).
|
* Add `:select` with function call and alias example to README (PR [#502](https://github.com/seancorfield/honeysql/pull/502) [@markbastian](https://github.com/markbastian)).
|
||||||
|
|
|
||||||
|
|
@ -52,11 +52,11 @@ section of the documentation before trying to use HoneySQL to build your own que
|
||||||
From Clojure:
|
From Clojure:
|
||||||
<!-- {:test-doc-blocks/reader-cond :clj} -->
|
<!-- {:test-doc-blocks/reader-cond :clj} -->
|
||||||
```clojure
|
```clojure
|
||||||
(refer-clojure :exclude '[filter for group-by into partition-by set update])
|
(refer-clojure :exclude '[distinct filter for group-by into partition-by set update])
|
||||||
(require '[honey.sql :as sql]
|
(require '[honey.sql :as sql]
|
||||||
;; CAUTION: this overwrites several clojure.core fns:
|
;; CAUTION: this overwrites several clojure.core fns:
|
||||||
;;
|
;;
|
||||||
;; filter, for, group-by, into, partition-by, set, and update
|
;; distinct, filter, for, group-by, into, partition-by, set, and update
|
||||||
;;
|
;;
|
||||||
;; you should generally only refer in the specific
|
;; you should generally only refer in the specific
|
||||||
;; helpers that you want to use!
|
;; helpers that you want to use!
|
||||||
|
|
|
||||||
|
|
@ -1002,6 +1002,19 @@ user=> (sql/format (-> (select :id
|
||||||
["SELECT id, AVG(salary) OVER () AS Average, MAX(salary) OVER () AS MaxSalary FROM employee"]
|
["SELECT id, AVG(salary) OVER () AS Average, MAX(salary) OVER () AS MaxSalary FROM employee"]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## distinct, expr
|
||||||
|
|
||||||
|
Related to the windowing clauses above, `:distinct` and `:expr` are
|
||||||
|
intended to let you mix clauses with expressions, such as in BigQuery's
|
||||||
|
`ARRAY_AGG` function:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
user=> (sql/format {:select [[[:over
|
||||||
|
[[:array_agg {:distinct [:ignore-nulls :col] :order-by :x}]
|
||||||
|
{:partition-by :y}]]]]})
|
||||||
|
["SELECT ARRAY_AGG (DISTINCT col IGNORE NULLS ORDER BY x ASC) OVER (PARTITION BY y)"]
|
||||||
|
```
|
||||||
|
|
||||||
## order-by
|
## order-by
|
||||||
|
|
||||||
`:order-by` accepts a sequence of one or more ordering
|
`:order-by` accepts a sequence of one or more ordering
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@
|
||||||
:raw :nest :with :with-recursive :intersect :union :union-all :except :except-all
|
:raw :nest :with :with-recursive :intersect :union :union-all :except :except-all
|
||||||
:table
|
:table
|
||||||
:select :select-distinct :select-distinct-on :select-top :select-distinct-top
|
:select :select-distinct :select-distinct-on :select-top :select-distinct-top
|
||||||
|
:distinct :expr
|
||||||
:into :bulk-collect-into
|
:into :bulk-collect-into
|
||||||
:insert-into :replace-into :update :delete :delete-from :truncate
|
:insert-into :replace-into :update :delete :delete-from :truncate
|
||||||
:columns :set :from :using
|
:columns :set :from :using
|
||||||
|
|
@ -288,13 +289,14 @@
|
||||||
|
|
||||||
Any ? is escaped to ??."
|
Any ? is escaped to ??."
|
||||||
[k]
|
[k]
|
||||||
(let [n (str/replace (name k) "?" "??")]
|
(when k
|
||||||
(if (= \' (first n))
|
(let [n (str/replace (name k) "?" "??")]
|
||||||
(let [ident (subs n 1 (count n))
|
(if (= \' (first n))
|
||||||
ident-l (str/lower-case ident)]
|
(let [ident (subs n 1 (count n))
|
||||||
(binding [*quoted* (when-not (contains? #{"array"} ident-l) *quoted*)]
|
ident-l (str/lower-case ident)]
|
||||||
(format-entity (keyword ident))))
|
(binding [*quoted* (when-not (contains? #{"array"} ident-l) *quoted*)]
|
||||||
(-> n (dehyphen) (upper-case)))))
|
(format-entity (keyword ident))))
|
||||||
|
(-> n (dehyphen) (upper-case))))))
|
||||||
|
|
||||||
(defn- sym->kw
|
(defn- sym->kw
|
||||||
"Given a symbol, produce a keyword, retaining the namespace
|
"Given a symbol, produce a keyword, retaining the namespace
|
||||||
|
|
@ -1361,6 +1363,8 @@
|
||||||
:select-distinct-on #'format-selects-on
|
:select-distinct-on #'format-selects-on
|
||||||
:select-top #'format-select-top
|
:select-top #'format-select-top
|
||||||
:select-distinct-top #'format-select-top
|
:select-distinct-top #'format-select-top
|
||||||
|
:distinct (fn [k xs] (format-selects k [[xs]]))
|
||||||
|
:expr (fn [_ xs] (format-selects nil [[xs]]))
|
||||||
:into #'format-select-into
|
:into #'format-select-into
|
||||||
:bulk-collect-into #'format-select-into
|
:bulk-collect-into #'format-select-into
|
||||||
:insert-into #'format-insert
|
:insert-into #'format-insert
|
||||||
|
|
@ -2269,4 +2273,8 @@
|
||||||
[:transport :t] [:id :name]]
|
[:transport :t] [:id :name]]
|
||||||
:values [[1 "Car"] [2 "Boat"] [3 "Bike"]]}
|
:values [[1 "Car"] [2 "Boat"] [3 "Bike"]]}
|
||||||
{:pretty true})
|
{:pretty true})
|
||||||
|
(sql/format-expr [:array_agg {:distinct [:ignore-nulls :a] :order-by :a}])
|
||||||
|
(sql/format-expr [:over [[:array_agg {:expr [:respect-nulls :a] :order-by :a
|
||||||
|
:limit 10}]
|
||||||
|
{:partition-by :something}]])
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@
|
||||||
bulk-collect-info [& args]
|
bulk-collect-info [& args]
|
||||||
|
|
||||||
(as they are for all helper functions)."
|
(as they are for all helper functions)."
|
||||||
(:refer-clojure :exclude [filter for group-by into partition-by set update])
|
(:refer-clojure :exclude [distinct filter for group-by into partition-by set update])
|
||||||
(:require [clojure.core :as c]
|
(:require [clojure.core :as c]
|
||||||
[honey.sql]))
|
[honey.sql]))
|
||||||
|
|
||||||
|
|
@ -468,6 +468,16 @@
|
||||||
[& args]
|
[& args]
|
||||||
(generic :select-distinct-top args))
|
(generic :select-distinct-top args))
|
||||||
|
|
||||||
|
(defn distinct
|
||||||
|
"Like `select-distinct` but produces DISTINCT..."
|
||||||
|
[& args]
|
||||||
|
(generic-1 :distinct args))
|
||||||
|
|
||||||
|
(defn expr
|
||||||
|
"Like `distinct` but produces ... (i.e., just the expression that follows)."
|
||||||
|
[& args]
|
||||||
|
(generic-1 :expr args))
|
||||||
|
|
||||||
(defn into
|
(defn into
|
||||||
"Accepts table name, optionally followed a database name."
|
"Accepts table name, optionally followed a database name."
|
||||||
{:arglists '([table] [table dbname])}
|
{:arglists '([table] [table dbname])}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue