-
Notifications
You must be signed in to change notification settings - Fork 0
/
malli.cljc
91 lines (81 loc) · 3.32 KB
/
malli.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
(ns secret.keeper.malli
"The simple wrapper for the malli library.
Easy markup your secrets in one place - directly in your model."
(:require
[malli.core :as m]
[malli.transform :as mt]
[secret.keeper :as keeper]))
(defn transformer
"Secret transformer.
- Encoder - encodes all secrets using the specified categories.
- Decoder - decodes all secrets.
Strategy:
1. Try to extract the category from the schema properties using the specified key.
Important: The local category has the highest priority.
2. Try to extract the category from the transformer secrets map by the schema type
3. Otherwise, if the schema has any entries, we take the specified categories
from the transformer secrets map by the entry key
Usage:
```
;; 1. Define your transformer
(def Transformer
(transformer
{:key :category ;; by default ::keeper/category
:secrets {:passport :confidential
:password :internal-only}}))
;; 2. Define your schema
(def User
[:map
[:firstname string?]
[:lastname string?]
[:email string?]
[:passport string?]
[:address [:map {:category :personal}
[:street string?]
[:zip int?]
[:city string?]
[:country [:enum \"Russia\" \"USA\"]]]]
[:credentials [:map
[:login string?]
[:password string?]]]])
;; 3. Mark all secrets using the specified categories
(m/encode User <your-data> Transformer)
;; 4. Decode all secrets
(m/decode User <your-data> Transformer)
```"
([]
(transformer nil))
([{:keys [key secrets]
:or {key ::keeper/category
secrets {}}}]
(let [global-keys (set (keys secrets))
get-category (fn [schema]
(or (some-> schema m/properties key)
(some->> schema m/type (get secrets))))
encoder (fn [schema _opts]
(if-some [category (get-category schema)]
(fn [x]
(keeper/make-secret x category))
(when (seq global-keys)
(when-some [entries (m/entries schema)]
(let [ks (reduce
(fn [acc [k & _]]
(if (contains? global-keys k)
(assoc acc k (get secrets k))
acc))
{} entries)]
(fn [x]
(if (map? x)
(reduce-kv
(fn [acc key category]
(update acc key #(keeper/make-secret % category)))
x ks)
x)))))))
decoder (fn [_schema _opts]
(fn [x]
(if (keeper/secret? x)
(keeper/data x)
x)))]
(mt/transformer
{:default-encoder {:compile encoder}
:default-decoder {:compile decoder}}))))