This repository has been archived by the owner on Apr 29, 2023. It is now read-only.
/
bounced_email.clj
165 lines (135 loc) · 5.78 KB
/
bounced_email.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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
(ns oc.lib.email.resources.bounced-email
(:require [taoensso.faraday :as far]
[schema.core :as schema]
[taoensso.timbre :as timbre]
[oc.lib.time :as oc-time]
[oc.lib.schema :as lib-schema]
[clojure.set :as clj-set]))
(defn table-name [db-opts]
(keyword (str (:table-prefix db-opts) "_bounced_email")))
(defn resource-type-gsi-name [db-opts]
(keyword (str (:table-prefix db-opts) "_resource_type")))
(def HardBounce :hard-bounce)
(def ResourceType (schema/enum HardBounce))
(def BouncedEmail {
:email lib-schema/NonBlankStr
:resource-type ResourceType
:created-at lib-schema/ISO8601
:updated-at lib-schema/ISO8601
:bounce-count schema/Int
})
(def BouncedEmail->bounced-email
{:resource_type :resource-type
:bounce_count :bounce-count
:created_at :created-at
:updated_at :updated-at})
(def bounced-email->BouncedEmail
{:resource-type :resource_type
:bounce-count :bounce_count
:created-at :created_at
:updated-at :updated_at})
(defn- ->dyn [clj-map]
(clj-set/rename-keys clj-map bounced-email->BouncedEmail))
(defn- ->clj [dyn-map]
(-> dyn-map
(clj-set/rename-keys BouncedEmail->bounced-email)
(update :resource-type keyword)))
(schema/defn ^:always-validate retrieve-email
:- (schema/maybe BouncedEmail)
[db-opts email :- lib-schema/NonBlankStr]
(let [key-idnx {:email email :resource-type HardBounce}
dyn-key-idnx (->dyn key-idnx)]
(timbre/tracef "Retrieve bounced-email %s with key %s" email dyn-key-idnx)
(when-let [email-record (far/get-item db-opts (table-name db-opts) dyn-key-idnx)]
(->clj email-record))))
(schema/defn ^:always-validate retrieve-hard-bounce
:- [BouncedEmail]
[db-opts]
(timbre/trace "Retrieve all bounced-email")
(map ->clj
(far/query db-opts (table-name db-opts) {:resource_type [:eq HardBounce]} {:index (resource-type-gsi-name db-opts)})))
(schema/defn ^:always-validate delete-hard-bounce!
[db-opts email :- lib-schema/NonBlankStr]
(let [key-idnx {:email email :resource-type HardBounce}
dyn-key-idnx (->dyn key-idnx)
existing-item (retrieve-email db-opts email)]
(timbre/tracef "Delete hard bounce for email %s with key %s" email dyn-key-idnx)
(timbre/tracef "Retrieved item: %s" existing-item)
(when existing-item
(far/delete-item db-opts (table-name db-opts) dyn-key-idnx))))
(schema/defn ^:always-validate store-hard-bounce!
[db-opts email :- lib-schema/NonBlankStr]
(timbre/tracef "Store hard bounce for email %s" email)
(if-let [prev-item (retrieve-email db-opts email)]
(let [updt-formulae "SET #ka = :va, #kb = :vb"
updt-attr-names {"#ka" (name :bounce_count)
"#kb" (name :updated_at)}
updt-attr-vals {":va" (-> prev-item :bounce-count inc)
":vb" (oc-time/current-timestamp)}
key-indx {:email email
:resource-type HardBounce}
dyn-key-indx (->dyn key-indx)]
(timbre/tracef "Email %s already present in db: %s" email prev-item)
(timbre/tracef "Updating record with index: %s, new bounce count: %d" dyn-key-indx (-> prev-item :bounce-count inc))
(far/update-item db-opts (table-name db-opts) dyn-key-indx
{:update-expr updt-formulae
:expr-attr-names updt-attr-names
:expr-attr-vals updt-attr-vals
:return :all-new}))
(let [ts (oc-time/current-timestamp)
new-item {:email email :resource-type HardBounce :bounce-count 1 :created-at ts :updated-at ts}
dyn-new-item (->dyn new-item)]
(timbre/tracef "Email %s not found in DB, creating a new record with 1 bounce" email)
(timbre/tracef "Will insert record: %s" dyn-new-item)
(far/put-item db-opts (table-name db-opts) dyn-new-item)))
true)
(comment
"Example data:
bounced_email:
[{:email iacopo@bounceme.com
:created_at 2021-08-24T03:38:12.321Z
:updated_at 2021-08-24T03:38:12.120Z
:resource-type hard-bounce
:bounce_count 1}
{:email iacopo@bounceme.com
:created_at 2021-08-22T03:38:02.231Z
:updated_at 2021-08-23T05:12:12.052Z
:resource-type hard-bounce
:bounce_count 3}]
"
(require '[oc.lib.email.resources.bounced-email :as bounced-email] :reload)
(far/list-tables db-opts)
(far/delete-table db-opts (bounced-email/table-name db-opts))
(aprint
(far/create-table db-opts
(bounced-email/table-name db-opts)
[:email :s]
{:range-keydef [:resource_type :s]
:billing-mode :pay-per-request
:block? true}))
(aprint
@(far/update-table db-opts
(bounced-email/table-name db-opts)
{:gsindexes {:operation :create
:name (bounced-email/resource-type-gsi-name db-opts)
:billing-mode :pay-per-request
:hash-keydef [:resource-type :s]
:range-keydef [:email :s]
:projection :keys-only}}))
;; Board followers
(far/delete-table db-opts (follow/board-unfollower-table-name db-opts))
(aprint
(far/create-table db-opts
(follow/board-unfollower-table-name db-opts)
[:unfollow_board_uuid :s]
{:range-keydef [:org_slug :s]
:billing-mode :pay-per-request
:block? true}))
(aprint (far/describe-table db-opts (follow/table-name db-opts)))
(follow/store! db-opts "1111-1111-1111" "aaaa-aaaa-aaaa" ["3333-3333-3333"] ["2222-2222-2222"])
(follow/follow! db-opts "1111-1111-1111" "aaaa-aaaa-aaaa" "4444-4444-4444")
(follow/unfollow! db-opts "1111-1111-1111" "aaaa-aaaa-aaaa" "2222-2222-2222")
(follow/retrieve db-opts "1111-1111-1111" "aaaa-aaaa-aaaa")
(follow/retrieve-all db-opts "aaaa-aaaa-aaaa")
(follow/delete! db-opts "1111-1111-1111" "aaaa-aaaa-aaaa")
(follow/delete-by-org! db-opts "aaaa-aaaa-aaaa"))