Skip to content

Commit 775483c

Browse files
committed
migrate to tags; make schema type required
1 parent 0f08807 commit 775483c

File tree

9 files changed

+256
-103
lines changed

9 files changed

+256
-103
lines changed

.projectile

Whitespace-only changes.

README.md

+34-8
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,37 @@
11
# zen meta store & schema
22

3-
## store
3+
zen project consists of set of namespaces.
4+
5+
On file system namespaces can be organized
6+
the same way as java/clojure project.
7+
8+
Each namespace is valid edn file with data,
9+
describing your models.
10+
Namespace is a map with two special symbol keys - 'ns and 'import
11+
12+
* 'ns - defines name of namespace
13+
* 'imports - is a set of required namespaces to interpret this namespace (zen namespace is imported implicitly)
14+
15+
Inside namespace you can refer local symbols just by local
16+
name or symbols from extrnal namespace by ns-name/sym-name.
17+
18+
All other symbolic keys defines meta-resources.
19+
20+
Symbol may be tagged with keywords. Keywords used to
21+
organize and classify symbols.
422

5-
* namespace
6-
* resource
23+
* global keys
724

825
```
9-
{
10-
ns myapp.something ;; namespace
11-
import #{some.ns}
26+
{ns myapp.something ;; namespace
27+
import #{ some.lib }
1228
29+
:tags {}
30+
:desc {}
1331
;; resource
14-
symbol {
32+
web {
1533
;; name myapp.something/symbol
16-
tags #{:zen/schema ....} ;; keyword tags - zen types
34+
:zen/tags #{:some.lib/http-server }
1735
1836
;; resource data
1937
:key "value"
@@ -27,6 +45,14 @@
2745
```
2846

2947

48+
49+
You can load zen project into meta-storage.
50+
zen will validate all m
51+
52+
## store
53+
54+
55+
3056
## schema
3157

3258
Composable, open-world schema engine.

pkg/zen.edn

+59-36
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,99 @@
11
{ns zen
22

3-
regex {types schema
4-
tags #{:zen/primitive}
5-
:desc "regexp primitive type"
6-
:type map
7-
:keys {}}
3+
:zen/tag {:zen/tags #{:zen/tag}
4+
:zen/desc "register keyword as a tag"}
5+
6+
:zen/schema {:zen/tags #{:zen/tag}
7+
:zen/desc "label resource as zen/schema"
8+
:schema schema}
9+
10+
:zen/property {:zen/tags #{:zen/tag}
11+
:zen/desc "register tag as a property - i.e. global key with schema"}
12+
13+
desc {:zen/tags #{:zen/property :zen/schema}
14+
:type string}
15+
16+
name {:zen/tags #{:zen/property :zen/schema}
17+
:type symbol}
18+
19+
;; ctx {:zen/tags #{:zen/schema}
20+
;; :zen/desc "schema for meta-store context"
21+
;; :keys {:tags {:type map :value {:type map :confirms #{tag}}}
22+
;; :symbols {:type map}}}
23+
24+
tags {:zen/tags #{:zen/property :zen/schema}
25+
:type zen/set
26+
:every {:type keyword}}
27+
828

9-
string {types schema
10-
tags #{:zen/primitive}
11-
:desc "sring primitive type"
29+
string {:zen/tags #{:zen/primitive :zen/schema}
30+
:zen/desc "sring primitive type"
1231
:type map
1332
:keys {:minLength {:type integer
1433
:min 0
1534
:desc "inclusive minimal length of string"}
1635
:maxLength {:type integer :min 0}
1736
:regex {:type regex}}}
1837

19-
integer {types schema
20-
tags #{:zen/primitive}
21-
:desc "integer primitive type"
38+
regex {:zen/tags #{:zen/schema :zen/primitive}
39+
:zen/desc "regexp primitive type"
40+
:type map}
41+
42+
43+
integer {:zen/tags #{:zen/primitive :zen/schema}
44+
:zen/desc "integer primitive type"
2245
:type map
2346
:keys {:min {:type integer}
2447
:max {:type integer}}}
2548

26-
number {types schema
27-
tags #{:zen/primitive}
28-
:desc "number primitive type"
49+
number {:zen/tags #{:zen/primitive :zen/schema}
50+
:zen/desc "number primitive type"
2951
:type map
3052
:keys {:min {:type number}
3153
:max {:type number}}}
3254

33-
date {types schema
34-
tags #{:zen/primitive}
55+
date {:zen/tags #{:zen/primitive :zen/schema}
3556
:type map
3657
:keys {:in-past {:type boolean}
3758
:in-future {:type boolean}}}
3859

39-
datetime {types schema
40-
tags #{:zen/primitive}
60+
datetime {:zen/tags #{:zen/primitive :zen/schema}
4161
:type map
4262
:keys {:in-past {:type boolean}
4363
:in-future {:type boolean}}}
4464

45-
boolean {types schema
46-
tags #{:zen/primitive}
65+
boolean {:zen/tags #{:zen/primitive :zen/schema}
4766
:type map}
4867

49-
symbol {types schema :type map}
50-
51-
keyword {types schema :type map}
68+
symbol {:zen/tags #{:zen/primitive :zen/schema}
69+
:type map}
5270

53-
union-key {types schema :type map}
71+
keyword {:zen/tags #{:zen/primitive :zen/schema}
72+
:type map}
5473

74+
union-key {:zen/tags #{:zen/primitive :zen/schema}
75+
:type map}
5576

56-
coll {types schema
77+
coll {:zen/tags #{:zen/coll :zen/schema}
5778
:type map
58-
:keys {:every {:confirms #{schema}}
79+
:keys {:every {:type map :confirms #{schema}}
5980
:minItems {:type integer :min 0}
6081
:maxItems {:type integer :min 0}}}
6182

62-
set {types schema
83+
set {:zen/tags #{:zen/coll :zen/schema}
6384
:type map
6485
:confirms #{coll}}
6586

66-
vector {types schema
87+
vector {:zen/tags #{:zen/coll :zen/schema}
6788
:type map
6889
:confirms #{coll}}
6990

70-
map {types schema
91+
map {:zen/tags #{:zen/coll :zen/schema}
7192
:type map
72-
:keys {:values {:confirms #{schema}}}}
93+
:keys {:values {:type map :confirms #{schema}}}}
7394

74-
schema {types schema
75-
:desc "zen schema"
95+
schema {:zen/tags #{:zen/schema}
96+
:zen/desc "zen schema"
7697
:type map
7798
:schema-key {:key :type}
7899
:keys {:type {:type symbol}
@@ -90,15 +111,17 @@
90111
:require {:type set :every {:type keyword}}}
91112
:require [:type]}
92113

93-
resource {types schema
114+
resource {:zen/tags #{:zen/schema}
94115
:type map
95116
:keys {:id {:type string}
96117
:resourceType {:type string}}}
97118

98-
reference {types schema
119+
reference {:zen/tags #{:zen/schema}
99120
:type map
100121
:keys {:id {:type string}
101122
:resourceType {:type string}}}
102123

103-
op {types schema
104-
:desc "Operaration"}}
124+
125+
op {:zen/tags #{:zen/schema}
126+
:desc "Operaration"
127+
:type map}}

src/zen/core.clj

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
(read-ns ctx 'myapp)
1919
(read-ns ctx 'zen)
2020

21+
22+
23+
2124
(println
2225
(str/join "\n" (:errors @ctx)))
2326

src/zen/store.clj

+60-40
Original file line numberDiff line numberDiff line change
@@ -8,61 +8,81 @@
88

99
(defn update-types-recur [ctx tp-sym sym]
1010
(swap! ctx update-in [:tps tp-sym] (fn [x] (conj (or x #{}) sym)))
11-
(doseq [tp-sym' (get-in @ctx [:syms tp-sym :isa])]
11+
(doseq [tp-sym' (get-in @ctx [:symbols tp-sym :isa])]
1212
(update-types-recur ctx tp-sym' sym)))
1313

1414
(declare read-ns)
1515

1616
(defn pretty-path [pth]
1717
(->> pth
1818
(mapv (fn [x] (if (keyword? x) (subs (str x) 1) (str x))))
19-
(str/join "." )))
19+
(str/join "->" )))
2020

21-
(defn load-ns [ctx nmsps]
21+
(defn eval-resource [ctx ns-str ns-name nmsps k resource]
22+
(-> (clojure.walk/postwalk
23+
(fn [x]
24+
(if (symbol? x)
25+
(if (namespace x)
26+
(do (when-not (get-in @ctx [:symbols x])
27+
(swap! ctx update :errors conj (format "Could not resolve symbol '%s in %s/%s" x ns-name k)))
28+
x)
29+
(do (when-not (get nmsps x)
30+
(swap! ctx update :errors conj (format "Could not resolve local symbol '%s in %s/%s" x ns-name k)))
31+
(symbol ns-str (name x))))
32+
x))
33+
resource)
34+
(assoc ;;TODO :zen/ns ns-name
35+
:zen/name (symbol (name ns-name) (name k)))))
36+
37+
(defn load-tag [ctx nmsps k v]
38+
(let [ns-name (get nmsps 'ns)
39+
ns-str (name ns-name)
40+
res (eval-resource ctx ns-str ns-name nmsps k v)]
41+
(swap! ctx (fn [ctx] (update-in ctx [:tags k] (fn [x] (when x (println "WARN: reload tag" (:zen/name res))) res))))))
42+
43+
44+
(defn load-symbol [ctx nmsps k v]
2245
(let [ns-name (get nmsps 'ns)
23-
ns-str (name ns-name)]
46+
ns-str (name ns-name)
47+
sym (symbol ns-str (name k))
48+
res (eval-resource ctx ns-str ns-name nmsps k v)]
49+
(swap! ctx (fn [ctx] (update-in ctx [:symbols sym] (fn [x] (when x (println "WARN: reload" (:zen/name res))) res))))
50+
(doseq [tg (:zen/tags res)]
51+
(swap! ctx update-in [:tags-index tg] (fn [x] (conj (or x #{}) sym))))
52+
res))
53+
54+
(defn validate-resource [ctx res]
55+
(let [tags (get res :zen/tags)
56+
tags-reg (get @ctx :tags)
57+
schemas (->> tags
58+
(mapv (fn [tag] (get-in tags-reg [tag :schema])))
59+
(filter identity)
60+
(into #{}))]
61+
(when-not (empty? schemas)
62+
(println "validate with" schemas)
63+
(let [{errs :errors} (zen.validation/validate ctx schemas res)]
64+
(when-not (empty? errs)
65+
(doseq [err errs]
66+
(swap! ctx update :errors
67+
conj (format "Validation: %s '%s' in %s by %s"
68+
(get res :zen/name)
69+
(:message err)
70+
(pretty-path (:path err))
71+
(pretty-path (:schema err))))))))))
72+
73+
(defn load-ns [ctx nmsps]
74+
(let [ns-name (get nmsps 'ns)]
2475
(when-not (get-in ctx [:ns ns-name])
2576
(swap! ctx (fn [ctx] (assoc-in ctx [:ns ns-name] nmsps)))
2677
(doseq [imp (get nmsps 'import)]
2778
(read-ns ctx imp))
2879
(->>
2980
(dissoc nmsps ['ns 'import])
3081
(mapv (fn [[k v]]
31-
(when (and (symbol? k) (map? v))
32-
(let [sym (symbol ns-str (name k))
33-
res (-> (clojure.walk/postwalk
34-
(fn [x]
35-
(if (and (symbol? x) (not (contains? #{'types} x)))
36-
(if (namespace x)
37-
(do (when-not (get-in @ctx [:syms x])
38-
(swap! ctx update :errors conj (format "Could not resolve symbol '%s in %s/%s" x ns-name k)))
39-
x)
40-
(do (when-not (get nmsps x)
41-
(swap! ctx update :errors conj (format "Could not resolve local symbol '%s in %s/%s" x ns-name k)))
42-
(symbol ns-str (name x))))
43-
x))
44-
(dissoc v 'tags 'types))
45-
(assoc 'ns ns-name
46-
'name (symbol (name ns-name) (name k))
47-
'types (get 'types v)))]
48-
(swap! ctx (fn [ctx] (assoc-in ctx [:syms sym] res)))
49-
(when-let [tps (get v 'types)]
50-
(assert (or (set? tps) (symbol? tps)) (format "types should be a set of symbols or symbol in %s/%s" ns-name k))
51-
(doseq [tp-sym (if (symbol? tps) [tps] tps)]
52-
(update-types-recur ctx tp-sym sym)))
53-
res))))
54-
(mapv (fn [res]
55-
(when-let [tps (and res (get res 'types))]
56-
(let [tps (if (symbol? tps) #{tps} tps)]
57-
(let [{errs :errors} (zen.validation/validate ctx tps (dissoc res 'types 'ns 'name 'tags))]
58-
(when-not (empty? errs)
59-
(doseq [err errs]
60-
(swap! ctx update :errors
61-
conj (format "Validation: %s '%s' in %s by %s"
62-
(get res 'name)
63-
(:message err)
64-
(pretty-path (:path err))
65-
(pretty-path (:schema err)))))))))))))))
82+
(cond (keyword? k) (load-tag ctx nmsps k v)
83+
(and (symbol? k) (map? v)) (load-symbol ctx nmsps k v)
84+
:else nil)))
85+
(mapv (fn [res] (validate-resource ctx res)))))))
6686

6787
(defn read-ns [ctx nm]
6888
(let [pth (str (str/replace (str nm) #"\." "/") ".edn")]
@@ -72,7 +92,7 @@
7292
(swap! ctx update :errors conj (format "Could not load ns '%s" nm)))))
7393

7494
(defn get-symbol [ctx nm]
75-
(when-let [res (get-in @ctx [:syms nm])]
95+
(when-let [res (get-in @ctx [:symbols nm])]
7696
(assoc res 'name nm)))
7797

7898
(defn new-context [& [opts]]

0 commit comments

Comments
 (0)