-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
update.clj
75 lines (65 loc) · 3.01 KB
/
update.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
(ns toucan2.update
"Implementation of [[update!]]."
(:require
[clojure.spec.alpha :as s]
[methodical.core :as m]
[toucan2.model :as model]
[toucan2.operation :as op]
[toucan2.query :as query]
[toucan2.util :as u]))
;;; this is basically the same as the args for `select` and `delete` but the difference is that it has an additional
;;; optional arg, `:pk`, as the second arg, and one additional optional arg, the `changes` map at the end
(s/def ::default-args
(s/cat
:modelable ::query/default-args.modelable
:pk (s/? (complement (some-fn keyword? map?)))
;; these are treated as CONDITIONS
:kv-args ::query/default-args.kv-args
;; by default, assuming this resolves to a map query, is treated as a map of conditions.
:queryable ::query/default-args.queryable
;; TODO -- we should introduce some sort of `do-with-update-changes` method so it's possible to use named update maps
;; here.
:changes map?))
(m/defmethod query/args-spec ::update
[_query-type]
::default-args)
(m/defmethod query/parse-args ::update
[query-type unparsed-args]
(let [parsed (next-method query-type unparsed-args)]
(cond-> parsed
(contains? parsed :pk) (-> (dissoc :pk)
(update :kv-args assoc :toucan/pk (:pk parsed))))))
(m/defmethod query/build [::update :default clojure.lang.IPersistentMap]
[query-type model {:keys [kv-args query changes], :as parsed-args}]
(when (empty? changes)
(throw (ex-info "Cannot build an update query with no changes."
{:query-type query-type, :model model, :parsed-args parsed-args})))
(let [parsed-args (assoc parsed-args
:kv-args (merge kv-args query)
:query {:update [(keyword (model/table-name model))]
:set changes})]
(next-method query-type model parsed-args)))
(m/defmethod op/reducible-update* [::update :default]
[query-type model {:keys [changes], :as parsed-args}]
(if (empty? changes)
(do
(u/println-debug "Query has no changes, skipping update")
nil)
(next-method query-type model parsed-args)))
(defn reducible-update
{:arglists '([modelable pk? conditions-map-or-query? & conditions-kv-args changes-map])}
[modelable & unparsed-args]
(op/reducible-update* ::update modelable unparsed-args))
(defn update!
{:arglists '([modelable pk? conditions-map-or-query? & conditions-kv-args changes-map])}
[& unparsed-args]
(op/returning-update-count! ::update unparsed-args))
(defn reducible-update-returning-pks
{:arglists '([modelable pk? conditions-map-or-query? & conditions-kv-args changes-map])}
[& unparsed-args]
(op/reducible-update-returning-pks ::update unparsed-args))
(defn update-returning-pks!
{:arglists '([modelable pk? conditions-map-or-query? & conditions-kv-args changes-map])}
[& unparsed-args]
(op/update-returning-pks! ::update unparsed-args))
;;; TODO -- add `update-returning-instances!`, similar to [[toucan2.update/insert-returning-instances!]]