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}
|
||||
: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
|
||||
INNER JOIN draq ON f.b = draq.x
|
||||
LEFT JOIN clod AS c ON f.a = c.d
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@
|
|||
:create-table :with-columns :create-view :drop-table
|
||||
;; then SQL clauses in priority order:
|
||||
: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
|
||||
:join :left-join :right-join :inner-join :outer-join :full-join
|
||||
:cross-join
|
||||
|
|
@ -272,16 +273,35 @@
|
|||
(let [[sqls params] (format-expr-list xs {:drop-ns (= :columns k)})]
|
||||
(into [(str "(" (str/join ", " sqls) ")")] params)))
|
||||
|
||||
(defn- format-selects [k xs]
|
||||
(defn- format-selects-common [prefix as xs]
|
||||
(if (sequential? xs)
|
||||
(let [[sqls params]
|
||||
(reduce (fn [[sql params] [sql' & params']]
|
||||
[(conj sql sql') (if params' (into params params') params)])
|
||||
[[] []]
|
||||
(map #(format-selectable-dsl % {:as (#{:select :from :window} k)}) xs))]
|
||||
(into [(str (sql-kw k) " " (str/join ", " sqls))] params))
|
||||
(let [[sql & params] (format-selectable-dsl xs {:as (#{:select :from} k)})]
|
||||
(into [(str (sql-kw k) " " sql)] params))))
|
||||
(map #(format-selectable-dsl % {:as as}) xs))]
|
||||
(into [(str prefix " " (str/join ", " sqls))] params))
|
||||
(let [[sql & params] (format-selectable-dsl xs {:as as})]
|
||||
(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]
|
||||
(if (sequential? x)
|
||||
|
|
@ -457,16 +477,46 @@
|
|||
(into [(str (sql-kw k) " " (str/join ", " sqls))] params)))
|
||||
|
||||
(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) ")")]
|
||||
(map? 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]
|
||||
(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})]
|
||||
[(str (sql-kw k) " " e " = EXCLUDED." e)])
|
||||
(format-set-exprs k x)))
|
||||
[(str (sql-kw k) " " e " = EXCLUDED." e)])))
|
||||
|
||||
(defn- format-simple-clause [c]
|
||||
(binding [*inline* true]
|
||||
|
|
@ -561,6 +611,7 @@
|
|||
:except-all #'format-on-set-op
|
||||
:select #'format-selects
|
||||
:select-distinct #'format-selects
|
||||
:select-distinct-on #'format-selects-on
|
||||
:insert-into #'format-insert
|
||||
:update #'format-selector
|
||||
:delete #'format-selects
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@
|
|||
|
||||
(defn select [& args] (generic :select 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 update [& args] (generic :update args))
|
||||
(defn delete [& args] (generic-1 :delete args))
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@
|
|||
(testing "Various construction methods are consistent"
|
||||
(is (= m1 m2)))
|
||||
(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]
|
||||
(sql/format m1 {:params {:param1 "gabba" :param2 2}}))))
|
||||
#?(: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"
|
||||
0 "bort" "gabba" 1 2 2 3 1 2 3 10 20 0 50 10])))
|
||||
(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]
|
||||
(sql/format (assoc m1 :lock [:in-share-mode])
|
||||
{:params {:param1 "gabba" :param2 2}
|
||||
|
|
|
|||
Loading…
Reference in a new issue