-
Notifications
You must be signed in to change notification settings - Fork 7
/
parameters.clj
112 lines (99 loc) · 3.2 KB
/
parameters.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
(ns com.yetanalytics.datasim.input.parameters
"Simulation global parameters"
(:require [clojure.spec.alpha :as s]
[com.yetanalytics.datasim.protocols :as p]
[xapi-schema.spec :as xs]
[com.yetanalytics.pan.objects.profile :as prof]
[com.yetanalytics.pan.objects.pattern :as pat]
[java-time.api :as t]
[com.yetanalytics.datasim.util.errors :as errs])
(:import [java.time.zone ZoneRulesException]
[java.time Instant]
[java.util Random]))
;; all options are optional, but everything except `end` will get defaults
;; (optional) start of the simulation (inclusive), 8601 stamp
(s/def ::start
::xs/timestamp)
;; (optional) start of the returned statements (if after ::start).
;; This lets us page through sims to later times. Defaults to ::start
(s/def ::from
::xs/timestamp)
;; (optional) end of the simulation (exclusive), 8601 stamp
(s/def ::end
(s/nilable ::xs/timestamp))
;; (optional) timezone, defaults to UTC
(s/def ::timezone
(s/and string?
not-empty
(fn [s]
(try (t/zone-id s)
(catch clojure.lang.ExceptionInfo exi
(if (= (type (ex-cause exi))
ZoneRulesException)
false
(throw exi)))))))
;; Seed is required, but will be generated if not present
(s/def ::seed
int?)
;; Max number of statements returned
(s/def ::max
pos-int?)
;; Restrict Generation to these profile IDs
(s/def ::gen-profiles
(s/every ::prof/id))
;; Restrict Generation to these pattern IDs
(s/def ::gen-patterns
(s/every ::pat/id))
(s/def ::parameters
(s/and
(s/keys :req-un [::start
::timezone
::seed]
:opt-un [::end
::from
::max
::gen-profiles
::gen-patterns])
(fn [{:keys [start from end]}]
(when end
(assert (t/before? (t/instant start)
(t/instant end))
"Sim must start before it ends.")
(when from
(assert (t/before? (t/instant from)
(t/instant end))
"From must be before end.")))
(when from
(assert (or (= from start)
(t/before? (t/instant start)
(t/instant from)))
"Sim start must be before or equal to from."))
true)))
(defn add-defaults
"Generate defualts"
[{:keys [start from timezone seed] :as params}]
(merge
params
(let [s (or start (.toString (Instant/now)))]
{:start s
:from (or from s)
:timezone (or timezone "UTC")
:seed (or seed (.nextLong (Random.)))})))
(defrecord Parameters [start
end
timezone
seed]
p/FromInput
(validate [this]
(when-some [ed (s/explain-data ::parameters this)]
(errs/explain-to-map-coll ::parameters ed)))
p/JSONRepresentable
(read-key-fn [this k]
(keyword nil (name k)))
(read-body-fn [this json-result]
(map->Parameters
(add-defaults json-result)))
(write-key-fn [this k]
(name k))
(write-body-fn [this]
(into {} this)))