Fix select as, select distinct on
This commit is contained in:
parent
4ce56997c9
commit
f6975ef6bd
4 changed files with 68 additions and 16 deletions
|
|
@ -559,7 +559,7 @@ big-complicated-map
|
||||||
{:params {:param1 "gabba" :param2 2}
|
{:params {:param1 "gabba" :param2 2}
|
||||||
:pretty true})
|
:pretty true})
|
||||||
=> ["
|
=> ["
|
||||||
SELECT DISTINCT f.*, b.baz, c.quux, b.bla \"bla-bla\", NOW(), @x := 10
|
SELECT DISTINCT f.*, b.baz, c.quux, b.bla AS \"bla-bla\", NOW(), @x := 10
|
||||||
FROM foo AS f, baz AS b
|
FROM foo AS f, baz AS b
|
||||||
INNER JOIN draq ON f.b = draq.x
|
INNER JOIN draq ON f.b = draq.x
|
||||||
LEFT JOIN clod AS c ON f.a = c.d
|
LEFT JOIN clod AS c ON f.a = c.d
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,8 @@
|
||||||
:create-table :with-columns :create-view :drop-table
|
:create-table :with-columns :create-view :drop-table
|
||||||
;; then SQL clauses in priority order:
|
;; then SQL clauses in priority order:
|
||||||
:nest :with :with-recursive :intersect :union :union-all :except :except-all
|
:nest :with :with-recursive :intersect :union :union-all :except :except-all
|
||||||
:select :select-distinct :insert-into :update :delete :delete-from :truncate
|
:select :select-distinct :select-distinct-on
|
||||||
|
:insert-into :update :delete :delete-from :truncate
|
||||||
:columns :set :from :using
|
:columns :set :from :using
|
||||||
:join :left-join :right-join :inner-join :outer-join :full-join
|
:join :left-join :right-join :inner-join :outer-join :full-join
|
||||||
:cross-join
|
:cross-join
|
||||||
|
|
@ -272,16 +273,35 @@
|
||||||
(let [[sqls params] (format-expr-list xs {:drop-ns (= :columns k)})]
|
(let [[sqls params] (format-expr-list xs {:drop-ns (= :columns k)})]
|
||||||
(into [(str "(" (str/join ", " sqls) ")")] params)))
|
(into [(str "(" (str/join ", " sqls) ")")] params)))
|
||||||
|
|
||||||
(defn- format-selects [k xs]
|
(defn- format-selects-common [prefix as xs]
|
||||||
(if (sequential? xs)
|
(if (sequential? xs)
|
||||||
(let [[sqls params]
|
(let [[sqls params]
|
||||||
(reduce (fn [[sql params] [sql' & params']]
|
(reduce (fn [[sql params] [sql' & params']]
|
||||||
[(conj sql sql') (if params' (into params params') params)])
|
[(conj sql sql') (if params' (into params params') params)])
|
||||||
[[] []]
|
[[] []]
|
||||||
(map #(format-selectable-dsl % {:as (#{:select :from :window} k)}) xs))]
|
(map #(format-selectable-dsl % {:as as}) xs))]
|
||||||
(into [(str (sql-kw k) " " (str/join ", " sqls))] params))
|
(into [(str prefix " " (str/join ", " sqls))] params))
|
||||||
(let [[sql & params] (format-selectable-dsl xs {:as (#{:select :from} k)})]
|
(let [[sql & params] (format-selectable-dsl xs {:as as})]
|
||||||
(into [(str (sql-kw k) " " sql)] params))))
|
(into [(str prefix " " sql)] params))))
|
||||||
|
|
||||||
|
(defn- format-selects [k xs]
|
||||||
|
(format-selects-common
|
||||||
|
(sql-kw k)
|
||||||
|
(#{:select :select-distinct :from :window
|
||||||
|
'select 'select-distinct 'from 'window}
|
||||||
|
k)
|
||||||
|
xs))
|
||||||
|
|
||||||
|
(defn- format-selects-on [k xs]
|
||||||
|
(let [[on & cols] xs
|
||||||
|
[sql & params]
|
||||||
|
(format-expr (into [:distinct-on] on))
|
||||||
|
[sql' & params']
|
||||||
|
(format-selects-common
|
||||||
|
(str (sql-kw :select) " " sql)
|
||||||
|
true
|
||||||
|
cols)]
|
||||||
|
(-> [sql'] (into params) (into params'))))
|
||||||
|
|
||||||
(defn- format-with-part [x]
|
(defn- format-with-part [x]
|
||||||
(if (sequential? x)
|
(if (sequential? x)
|
||||||
|
|
@ -457,16 +477,46 @@
|
||||||
(into [(str (sql-kw k) " " (str/join ", " sqls))] params)))
|
(into [(str (sql-kw k) " " (str/join ", " sqls))] params)))
|
||||||
|
|
||||||
(defn- format-on-conflict [k x]
|
(defn- format-on-conflict [k x]
|
||||||
(if (or (keyword? x) (symbol? x))
|
(cond (or (keyword? x) (symbol? x))
|
||||||
[(str (sql-kw k) " (" (format-entity x) ")")]
|
[(str (sql-kw k) " (" (format-entity x) ")")]
|
||||||
|
(map? x)
|
||||||
(let [[sql & params] (format-dsl x)]
|
(let [[sql & params] (format-dsl x)]
|
||||||
(into [(str (sql-kw k) " " sql)] params))))
|
(into [(str (sql-kw k) " " sql)] params))
|
||||||
|
(and (sequential? x)
|
||||||
|
(or (keyword? (first x)) (symbol? (first x)))
|
||||||
|
(map? (second x)))
|
||||||
|
(let [[sql & params] (format-dsl (second x))]
|
||||||
|
(into [(str (sql-kw k)
|
||||||
|
" (" (format-entity (first x)) ") "
|
||||||
|
sql)]
|
||||||
|
params))
|
||||||
|
:else
|
||||||
|
(throw (ex-info "unsupported :on-conflict format"
|
||||||
|
{:clause x}))))
|
||||||
|
(comment
|
||||||
|
keyword/symbol -> e = excluded.e
|
||||||
|
[k/s] -> join , e = excluded.e
|
||||||
|
{e v} -> join , e = v
|
||||||
|
{:fields f :where w} -> join , e = excluded.e (from f) where w
|
||||||
|
|
||||||
|
,)
|
||||||
(defn- format-do-update-set [k x]
|
(defn- format-do-update-set [k x]
|
||||||
(if (or (keyword? x) (symbol? x))
|
(if (map? x)
|
||||||
|
(if (and (or (contains? x :fields) (contains? x 'fields))
|
||||||
|
(or (contains? x :where) (contains? x 'where)))
|
||||||
|
(let [sets (str/join ", "
|
||||||
|
(map (fn [e]
|
||||||
|
(let [e (format-entity e {:drop-ns true})]
|
||||||
|
(str e " = EXCLUDED." e)))
|
||||||
|
(or (:fields x)
|
||||||
|
('fields x))))
|
||||||
|
[sql & params] (format-dsl {:where
|
||||||
|
(or (:where x)
|
||||||
|
('where x))})]
|
||||||
|
(into [(str (sql-kw k) " " sets " " sql)] params))
|
||||||
|
(format-set-exprs k x))
|
||||||
(let [e (format-entity x {:drop-ns true})]
|
(let [e (format-entity x {:drop-ns true})]
|
||||||
[(str (sql-kw k) " " e " = EXCLUDED." e)])
|
[(str (sql-kw k) " " e " = EXCLUDED." e)])))
|
||||||
(format-set-exprs k x)))
|
|
||||||
|
|
||||||
(defn- format-simple-clause [c]
|
(defn- format-simple-clause [c]
|
||||||
(binding [*inline* true]
|
(binding [*inline* true]
|
||||||
|
|
@ -561,6 +611,7 @@
|
||||||
:except-all #'format-on-set-op
|
:except-all #'format-on-set-op
|
||||||
:select #'format-selects
|
:select #'format-selects
|
||||||
:select-distinct #'format-selects
|
:select-distinct #'format-selects
|
||||||
|
:select-distinct-on #'format-selects-on
|
||||||
:insert-into #'format-insert
|
:insert-into #'format-insert
|
||||||
:update #'format-selector
|
:update #'format-selector
|
||||||
:delete #'format-selects
|
:delete #'format-selects
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@
|
||||||
|
|
||||||
(defn select [& args] (generic :select args))
|
(defn select [& args] (generic :select args))
|
||||||
(defn select-distinct [& args] (generic :select-distinct args))
|
(defn select-distinct [& args] (generic :select-distinct args))
|
||||||
|
(defn select-distinct-on [& args] (generic :select-distinct-on args))
|
||||||
(defn insert-into [& args] (generic :insert-into args))
|
(defn insert-into [& args] (generic :insert-into args))
|
||||||
(defn update [& args] (generic :update args))
|
(defn update [& args] (generic :update args))
|
||||||
(defn delete [& args] (generic-1 :delete args))
|
(defn delete [& args] (generic-1 :delete args))
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@
|
||||||
(testing "Various construction methods are consistent"
|
(testing "Various construction methods are consistent"
|
||||||
(is (= m1 m2)))
|
(is (= m1 m2)))
|
||||||
(testing "SQL data formats correctly"
|
(testing "SQL data formats correctly"
|
||||||
(is (= ["WITH cte AS (SELECT * FROM example WHERE example_column = ?) SELECT DISTINCT f.*, b.baz, c.quux, b.bla \"bla-bla\", NOW(), @x := 10 FROM foo AS f, baz AS b INNER JOIN draq ON f.b = draq.x LEFT JOIN clod AS c ON f.a = c.d RIGHT JOIN bock ON bock.z = c.e FULL JOIN beck ON beck.x = c.y WHERE ((f.a = ?) AND (b.baz <> ?)) OR ((? < ?) AND (? < ?)) OR (f.e IN (?, ?, ?)) OR f.e BETWEEN ? AND ? GROUP BY f.a HAVING ? < f.e ORDER BY b.baz DESC, c.quux ASC, f.a NULLS FIRST LIMIT ? OFFSET ?"
|
(is (= ["WITH cte AS (SELECT * FROM example WHERE example_column = ?) SELECT DISTINCT f.*, b.baz, c.quux, b.bla AS \"bla-bla\", NOW(), @x := 10 FROM foo AS f, baz AS b INNER JOIN draq ON f.b = draq.x LEFT JOIN clod AS c ON f.a = c.d RIGHT JOIN bock ON bock.z = c.e FULL JOIN beck ON beck.x = c.y WHERE ((f.a = ?) AND (b.baz <> ?)) OR ((? < ?) AND (? < ?)) OR (f.e IN (?, ?, ?)) OR f.e BETWEEN ? AND ? GROUP BY f.a HAVING ? < f.e ORDER BY b.baz DESC, c.quux ASC, f.a NULLS FIRST LIMIT ? OFFSET ?"
|
||||||
0 "bort" "gabba" 1 2 2 3 1 2 3 10 20 0 50 10]
|
0 "bort" "gabba" 1 2 2 3 1 2 3 10 20 0 50 10]
|
||||||
(sql/format m1 {:params {:param1 "gabba" :param2 2}}))))
|
(sql/format m1 {:params {:param1 "gabba" :param2 2}}))))
|
||||||
#?(:clj (testing "SQL data prints and reads correctly"
|
#?(:clj (testing "SQL data prints and reads correctly"
|
||||||
|
|
@ -68,7 +68,7 @@
|
||||||
["WITH cte AS (SELECT * FROM example WHERE example_column = $1) SELECT DISTINCT f.*, b.baz, c.quux, b.bla \"bla-bla\", NOW(), @x := 10 FROM foo AS f, baz AS b INNER JOIN draq ON f.b = draq.x LEFT JOIN clod AS c ON f.a = c.d RIGHT JOIN bock ON bock.z = c.e FULL JOIN beck ON beck.x = c.y WHERE ((f.a = $2) AND (b.baz <> $3)) OR (($4 < $5) AND ($6 < $7)) OR (f.e IN ($8, $9, $10)) OR f.e BETWEEN $11 AND $12 GROUP BY f.a HAVING $13 < f.e ORDER BY b.baz DESC, c.quux ASC, f.a NULLS FIRST LIMIT $14 OFFSET $15"
|
["WITH cte AS (SELECT * FROM example WHERE example_column = $1) SELECT DISTINCT f.*, b.baz, c.quux, b.bla \"bla-bla\", NOW(), @x := 10 FROM foo AS f, baz AS b INNER JOIN draq ON f.b = draq.x LEFT JOIN clod AS c ON f.a = c.d RIGHT JOIN bock ON bock.z = c.e FULL JOIN beck ON beck.x = c.y WHERE ((f.a = $2) AND (b.baz <> $3)) OR (($4 < $5) AND ($6 < $7)) OR (f.e IN ($8, $9, $10)) OR f.e BETWEEN $11 AND $12 GROUP BY f.a HAVING $13 < f.e ORDER BY b.baz DESC, c.quux ASC, f.a NULLS FIRST LIMIT $14 OFFSET $15"
|
||||||
0 "bort" "gabba" 1 2 2 3 1 2 3 10 20 0 50 10])))
|
0 "bort" "gabba" 1 2 2 3 1 2 3 10 20 0 50 10])))
|
||||||
(testing "Locking"
|
(testing "Locking"
|
||||||
(is (= ["WITH cte AS (SELECT * FROM example WHERE example_column = ?) SELECT DISTINCT f.*, b.baz, c.quux, b.bla `bla-bla`, NOW(), @x := 10 FROM foo AS f, baz AS b INNER JOIN draq ON f.b = draq.x LEFT JOIN clod AS c ON f.a = c.d RIGHT JOIN bock ON bock.z = c.e FULL JOIN beck ON beck.x = c.y WHERE ((f.a = ?) AND (b.baz <> ?)) OR ((? < ?) AND (? < ?)) OR (f.e IN (?, ?, ?)) OR f.e BETWEEN ? AND ? GROUP BY f.a HAVING ? < f.e ORDER BY b.baz DESC, c.quux ASC, f.a NULLS FIRST LIMIT ? OFFSET ? LOCK IN SHARE MODE"
|
(is (= ["WITH cte AS (SELECT * FROM example WHERE example_column = ?) SELECT DISTINCT f.*, b.baz, c.quux, b.bla AS `bla-bla`, NOW(), @x := 10 FROM foo AS f, baz AS b INNER JOIN draq ON f.b = draq.x LEFT JOIN clod AS c ON f.a = c.d RIGHT JOIN bock ON bock.z = c.e FULL JOIN beck ON beck.x = c.y WHERE ((f.a = ?) AND (b.baz <> ?)) OR ((? < ?) AND (? < ?)) OR (f.e IN (?, ?, ?)) OR f.e BETWEEN ? AND ? GROUP BY f.a HAVING ? < f.e ORDER BY b.baz DESC, c.quux ASC, f.a NULLS FIRST LIMIT ? OFFSET ? LOCK IN SHARE MODE"
|
||||||
0 "bort" "gabba" 1 2 2 3 1 2 3 10 20 0 50 10]
|
0 "bort" "gabba" 1 2 2 3 1 2 3 10 20 0 50 10]
|
||||||
(sql/format (assoc m1 :lock [:in-share-mode])
|
(sql/format (assoc m1 :lock [:in-share-mode])
|
||||||
{:params {:param1 "gabba" :param2 2}
|
{:params {:param1 "gabba" :param2 2}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue