Restore upsert helper for #293
This commit is contained in:
parent
267eef778a
commit
e585ded37e
5 changed files with 65 additions and 32 deletions
|
|
@ -645,14 +645,6 @@ You can also register SQL clauses, specifying the keyword, the formatting functi
|
|||
|
||||
If you find yourself registering an operator, a function (syntax), or a new clause, consider submitting a [pull request to HoneySQL](https://github.com/seancorfield/honeysql/pulls) so others can use it, too. If it is dialect-specific, let me know in the pull request.
|
||||
|
||||
## TODO
|
||||
|
||||
- [ ] Create table, etc.
|
||||
|
||||
## Extensions
|
||||
|
||||
* [For PostgreSQL-specific extensions falling outside of ANSI SQL](https://github.com/nilenso/honeysql-postgres) -- these will all be core in 2.0!
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) 2020-2021 Sean Corfield. HoneySQL 1.x was copyright (c) 2012-2020 Justin Kramer and Sean Corfield.
|
||||
|
|
|
|||
|
|
@ -646,6 +646,11 @@ reasonable choices.
|
|||
(a keyword or symbol), or hash map of columns and
|
||||
values, like `:set` (above), or a hash map of fields
|
||||
(a sequence of SQL entities) and a where clause.
|
||||
For convenience of building clauses with helpers,
|
||||
it also accepts a sequence of one or more column
|
||||
names followed by an optional hash map: this is treated
|
||||
as an alternative form of the hash map with fields
|
||||
and a where clause.
|
||||
The single SQL entity and the list of fields produce
|
||||
`SET` clauses using `EXCLUDED`:
|
||||
|
||||
|
|
|
|||
|
|
@ -495,22 +495,27 @@
|
|||
{:clause x}))))
|
||||
|
||||
(defn- format-do-update-set [k 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)])))
|
||||
(cond (map? x)
|
||||
(if (or (contains? x :fields) (contains? x 'fields))
|
||||
(let [sets (str/join ", "
|
||||
(map (fn [e]
|
||||
(let [e (format-entity e {:drop-ns true})]
|
||||
(str e " = EXCLUDED." e)))
|
||||
(or (:fields x)
|
||||
('fields x))))
|
||||
where (or (:where x) ('where x))
|
||||
[sql & params] (when where (format-dsl {:where where}))]
|
||||
(into [(str (sql-kw k) " " sets
|
||||
(when sql (str " " sql)))] params))
|
||||
(format-set-exprs k x))
|
||||
(sequential? x)
|
||||
(let [[cols clauses] (split-with (complement map?) x)]
|
||||
(if (seq cols)
|
||||
(recur k {:fields cols :where (:where (first clauses))})
|
||||
(recur k (first clauses))))
|
||||
:else
|
||||
(let [e (format-entity x {:drop-ns true})]
|
||||
[(str (sql-kw k) " " e " = EXCLUDED." e)])))
|
||||
|
||||
(defn- format-simple-clause [c]
|
||||
(binding [*inline* true]
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@
|
|||
(defn on-conflict [& args] (generic-1 :on-conflict args))
|
||||
(defn on-constraint [& args] (generic :on-constraint args))
|
||||
(defn do-nothing [& args] (generic :do-nothing args))
|
||||
(defn do-update-set [& args] (generic-1 :do-update-set args))
|
||||
(defn do-update-set [& args] (generic :do-update-set args))
|
||||
(defn returning [& args] (generic :returning args))
|
||||
|
||||
;; helpers that produce non-clause expressions -- must be listed below:
|
||||
|
|
@ -114,8 +114,21 @@
|
|||
;; to make this easy to use in a select, wrap it so it becomes a function:
|
||||
(defn over [& args] [(into [:over] args)])
|
||||
|
||||
;; helper to ease compatibility with former nilenso/honeysql-postgres code:
|
||||
(defn upsert [data & clauses] (default-merge data clauses))
|
||||
;; this helper is intended to ease the migration from nilenso:
|
||||
(defn upsert
|
||||
([clause] (upsert {} clause))
|
||||
([data clause]
|
||||
(let [{:keys [on-conflict do-nothing do-update-set where]} clause]
|
||||
(cond-> data
|
||||
on-conflict
|
||||
(assoc :on-conflict on-conflict)
|
||||
do-nothing
|
||||
(assoc :do-nothing do-nothing)
|
||||
do-update-set
|
||||
(assoc :do-update-set (if where
|
||||
{:fields do-update-set
|
||||
:where where}
|
||||
do-update-set))))))
|
||||
|
||||
#?(:clj
|
||||
(assert (= (clojure.core/set (conj @@#'h/base-clause-order
|
||||
|
|
|
|||
|
|
@ -14,9 +14,7 @@
|
|||
;; pull in all the PostgreSQL helpers that the nilenso
|
||||
;; library provided (as well as the regular HoneySQL ones):
|
||||
[honey.sql.helpers :as sqlh :refer
|
||||
[;; not needed because on-conflict accepts clauses
|
||||
#_upsert
|
||||
on-conflict do-nothing on-constraint
|
||||
[upsert on-conflict do-nothing on-constraint
|
||||
returning do-update-set
|
||||
;; not needed because do-update-set can do this directly
|
||||
#_do-update-set!
|
||||
|
|
@ -44,18 +42,38 @@
|
|||
(do-update-set :dname)
|
||||
(returning :*)
|
||||
sql/format)))
|
||||
(is (= ["INSERT INTO distributors (did, dname) VALUES (?, ?), (?, ?) ON CONFLICT (did) DO UPDATE SET dname = EXCLUDED.dname RETURNING *" 5 "Gizmo Transglobal" 6 "Associated Computing, Inc"]
|
||||
(-> (insert-into :distributors)
|
||||
(values [{:did 5 :dname "Gizmo Transglobal"}
|
||||
{:did 6 :dname "Associated Computing, Inc"}])
|
||||
(upsert (-> (on-conflict :did)
|
||||
(do-update-set :dname)))
|
||||
(returning :*)
|
||||
sql/format)))
|
||||
(is (= ["INSERT INTO distributors (did, dname) VALUES (?, ?) ON CONFLICT (did) DO NOTHING" 7 "Redline GmbH"]
|
||||
(-> (insert-into :distributors)
|
||||
(values [{:did 7 :dname "Redline GmbH"}])
|
||||
(on-conflict :did)
|
||||
do-nothing
|
||||
sql/format)))
|
||||
(is (= ["INSERT INTO distributors (did, dname) VALUES (?, ?) ON CONFLICT (did) DO NOTHING" 7 "Redline GmbH"]
|
||||
(-> (insert-into :distributors)
|
||||
(values [{:did 7 :dname "Redline GmbH"}])
|
||||
(upsert (-> (on-conflict :did)
|
||||
do-nothing))
|
||||
sql/format)))
|
||||
(is (= ["INSERT INTO distributors (did, dname) VALUES (?, ?) ON CONFLICT ON CONSTRAINT distributors_pkey DO NOTHING" 9 "Antwerp Design"]
|
||||
(-> (insert-into :distributors)
|
||||
(values [{:did 9 :dname "Antwerp Design"}])
|
||||
(on-conflict (on-constraint :distributors_pkey))
|
||||
do-nothing
|
||||
sql/format)))
|
||||
(is (= ["INSERT INTO distributors (did, dname) VALUES (?, ?) ON CONFLICT ON CONSTRAINT distributors_pkey DO NOTHING" 9 "Antwerp Design"]
|
||||
(-> (insert-into :distributors)
|
||||
(values [{:did 9 :dname "Antwerp Design"}])
|
||||
(upsert (-> (on-conflict (on-constraint :distributors_pkey))
|
||||
do-nothing))
|
||||
sql/format)))
|
||||
(is (= ["INSERT INTO distributors (did, dname) VALUES (?, ?), (?, ?) ON CONFLICT (did) DO UPDATE SET dname = EXCLUDED.dname" 10 "Pinp Design" 11 "Foo Bar Works"]
|
||||
(sql/format {:insert-into :distributors
|
||||
:values [{:did 10 :dname "Pinp Design"}
|
||||
|
|
@ -73,8 +91,8 @@
|
|||
(-> (insert-into [:distributors [:did :dname]]
|
||||
(select 1 "whatever"))
|
||||
#_(query-values (select 1 "whatever"))
|
||||
(on-conflict (on-constraint :distributors_pkey))
|
||||
do-nothing
|
||||
(upsert (-> (on-conflict (on-constraint :distributors_pkey))
|
||||
do-nothing))
|
||||
sql/format)))))
|
||||
|
||||
(deftest upsert-where-test
|
||||
|
|
|
|||
Loading…
Reference in a new issue