-
Notifications
You must be signed in to change notification settings - Fork 0
/
cofx.cljc
148 lines (118 loc) · 4.17 KB
/
cofx.cljc
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
(ns a-frame.cofx
(:require
[promesa.core :as pr]
[promisespromises.error :as err]
[a-frame.schema :as schema]
[a-frame.registry :as registry]
[a-frame.cofx.data.tag-readers]
[a-frame.interceptor-chain :as interceptor-chain]
[a-frame.interceptor-chain.data :as data]
[a-frame.multimethods :as mm]
[taoensso.timbre :refer [info warn]]))
(defn reg-cofx
[id handler]
(registry/register-handler schema/a-frame-kind-cofx id handler))
(defn inject-cofx
"creates an InterceptorSpec data-structure for an event
interceptor chain"
([id]
{::interceptor-chain/key ::inject-cofx
::id id})
([id arg-spec]
{::interceptor-chain/key ::inject-cofx
::id id
::arg arg-spec}))
;; interceptor
(def inject-cofx-interceptor
"the interceptor functions to execute the interceptor
described by an InterceptorSpec produced by inject-cofx"
{::interceptor-chain/name ::inject-cofx
::interceptor-chain/enter
(fn inject-cofx-enter
[{app schema/a-frame-app-ctx
coeffects schema/a-frame-coeffects
:as context}
{id ::id
arg-spec ::arg
:as interceptor-spec}]
(let [handler (registry/get-handler schema/a-frame-kind-cofx id)
has-arg? (contains? interceptor-spec ::arg)
arg (when has-arg?
(data/resolve-data arg-spec context))]
(if (some? handler)
(pr/let [coeffects' (if has-arg?
(handler app coeffects arg)
(handler app coeffects))]
[(assoc context schema/a-frame-coeffects coeffects')
;; second value of response is a log value
(if has-arg? arg :_)])
(throw (err/ex-info
::no-cofx-handler
{::id id
::arg arg})))))})
(interceptor-chain/register-interceptor
::inject-cofx
inject-cofx-interceptor)
;; now the validated cofx gets the full interceptor-spec, so
;; it can add some data to the interceptor-spec for
;; path and validation
(defn inject-validated-cofx
"a cofx with a result with a defined schema to be
injected
- `id` : the cofx id
- `:schema` : the schema of the injected value
- `:arg-spec` : specification of the cofx handler arg
- `:path` : optional path in the coeffects to inject the value.
defaults to `id`"
([id schema]
(inject-validated-cofx id nil schema id))
([id arg-spec schema]
(inject-validated-cofx id arg-spec schema id))
([id arg-spec schema path]
(cond->
{::interceptor-chain/key ::inject-validated-cofx
::id id
::path path
::schema schema}
(some? arg-spec) (assoc ::arg arg-spec))))
(def inject-validated-cofx-interceptor
{::interceptor-chain/name ::inject-validated-cofx
::interceptor-chain/enter
(fn inject-validated-cofx-enter
[{app schema/a-frame-app-ctx
coeffects schema/a-frame-coeffects
:as context}
{id ::id
arg-spec ::arg
schema ::schema
path ::path
:as interceptor-spec}]
(let [handler (registry/get-handler schema/a-frame-kind-cofx id)
has-arg? (contains? interceptor-spec ::arg)
arg (when has-arg?
(data/resolve-data arg-spec context))
path (if (sequential? path) path [path])]
(if (some? handler)
(pr/let [coeffect (if has-arg?
(handler app coeffects arg)
(handler app coeffects))]
(when-not (mm/validate schema coeffect)
(throw (err/ex-info
::invalid-cofx
{::id id
::arg arg-spec
::path path
::schema schema
::coeffect coeffect})))
[(assoc-in context
(into [schema/a-frame-coeffects] path)
coeffect)
;; second value of response is a log value
(if has-arg? arg :_)])
(throw (err/ex-info
::no-cofx-handler
{::id id
::arg arg})))))})
(interceptor-chain/register-interceptor
::inject-validated-cofx
inject-validated-cofx-interceptor)